.classpath
| 1
modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
| 4
modules/core/plugin-container/src/test/java/org/rhq/test/pc/PluginContainerTest.java
| 37
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/AvailabilityOverUnderGraphType.java
| 9
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/StackedBarMetricGraphImpl.java
| 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/D3GroupGraphListView.java
| 1
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java
| 3
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupTableView.java
| 408
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupView.java
| 193
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupViewDataSource.java
| 314
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricAvailabilityView.java
| 223
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsGridFieldName.java
| 63
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
| 3
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java
| 30
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsViewDataSource.java
| 56
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/ResourceMetricAvailabilityView.java
| 224
modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/util/rpc/TrackingRequestCallback.java
| 6
modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/CoreGUI.gwt.xml
| 2
modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_de.properties
| 601
modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_ja.properties
| 210
modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.3.13.js
| 9293 ++++++++++
modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.3.13.min.js
| 5
modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.js
| 8768 ---------
modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.min.js
| 5
modules/enterprise/remoting/cli/pom.xml
| 19
modules/enterprise/remoting/cli/src/etc/Remoting_Setup.txt
| 43
modules/enterprise/remoting/cli/src/etc/build.xml
| 80
modules/enterprise/remoting/cli/src/etc/generate-jaxb-client-types.bat
| 16
modules/enterprise/remoting/cli/src/etc/generate-jaxb-client-types.sh
| 18
modules/enterprise/remoting/cli/src/etc/rhq-cli-env.bat
| 32
modules/enterprise/remoting/cli/src/etc/rhq-cli-env.sh
| 40
modules/enterprise/remoting/cli/src/etc/rhq-cli.bat
| 51
modules/enterprise/remoting/cli/src/etc/rhq-cli.sh
| 104
modules/enterprise/remoting/cli/src/etc/toRun.txt
| 3
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProvider.java
| 33
modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
| 375
modules/enterprise/remoting/cli/src/main/samples/modules/util.js
| 30
modules/enterprise/remoting/cli/src/main/scripts/rhq-client.build.xml
| 2
modules/enterprise/remoting/cli/src/test/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProviderTest.java
| 67
modules/enterprise/server/appserver/src/main/bin-resources/bin/internal/rhq-server.sh
| 5
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
| 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
| 12
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/ControlCommand.java
| 39
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
| 36
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/AbstractInstall.java
| 112
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Console.java
| 33
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Install.java
| 27
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Remove.java
| 55
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Restart.java
| 6
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Start.java
| 55
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Status.java
| 35
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Stop.java
| 55
modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
| 67
modules/enterprise/server/server-metrics/pom.xml
| 4
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/AbortedException.java
| 23
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
| 37
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsServer.java
| 92
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/SignalingCountDownLatch.java
| 34
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregate1HourData.java
| 127
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregate6HourData.java
| 84
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregateIndexEntriesHandler.java
| 73
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregateRawData.java
| 133
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregationState.java
| 257
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregator.java
| 378
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute1HourData.java
| 113
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute24HourData.java
| 99
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute6HourData.java
| 106
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregationTests.java
| 498
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/CassandraIntegrationTest.java
| 41
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsDAOTest.java
| 26
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsPerfTests.java
| 191
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsServerTest.java
| 38
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsTest.java
| 138
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/WaitForRawInserts.java
| 51
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/WaitForWrite.java
| 48
modules/enterprise/server/server-metrics/src/test/resources/log4j.xml
| 2
modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/MeasurementAggregator.java
| 7
modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/Simulator.java
| 41
modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlan.java
| 40
modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlanner.java
| 3
modules/plugins/database/pom.xml
| 64
modules/plugins/database/src/main/java/org/rhq/plugins/database/AbstractDatabaseComponent.java
| 36
modules/plugins/database/src/main/java/org/rhq/plugins/database/BasePooledConnectionProvider.java
| 226
modules/plugins/database/src/main/java/org/rhq/plugins/database/ConnectionPoolingSupport.java
| 52
modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java
| 65
modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableDiscoveryComponent.java
| 84
modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java
| 84
modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseComponent.java
| 14
modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabasePluginLifecycleListener.java
| 7
modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabasePluginUtil.java
| 379
modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseQueryUtility.java
| 16
modules/plugins/database/src/main/java/org/rhq/plugins/database/DriverDataSource.java
| 103
modules/plugins/database/src/main/java/org/rhq/plugins/database/PooledConnectionProvider.java
| 39
modules/plugins/database/src/test/java/org/rhq/plugins/database/ComponentTest.java
| 19
modules/plugins/database/src/test/java/org/rhq/plugins/database/H2Database.java
| 82
modules/plugins/database/src/test/java/org/rhq/plugins/database/H2DatabaseDiscovery.java
| 20
modules/plugins/database/src/test/java/org/rhq/plugins/database/H2PooledConnectionProvider.java
| 59
modules/plugins/database/src/test/java/org/rhq/plugins/database/NonPoolingCustomTableComponent.java
| 17
modules/plugins/database/src/test/java/org/rhq/plugins/database/PluginTest.java
| 88
modules/plugins/database/src/test/resources/META-INF/rhq-plugin.xml
| 94
modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerPluginConfigurationProperties.java
| 2
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
| 49
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
| 46
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DomainDeploymentComponent.java
| 21
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Ejb3BeanRuntimeComponent.java
| 17
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java
| 19
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/MemoryPoolComponent.java
| 88
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterConfigurationDiscovery.java
| 11
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterContextComponent.java
| 21
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/SubsystemDiscovery.java
| 4
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/VHostComponent.java
| 8
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/WebRuntimeComponent.java
| 29
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/helper/ServerPluginConfiguration.java
| 11
modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml
| 6
modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java
| 2
modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheDiscoveryComponent.java
| 10
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java
| 131
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionInfo.java
| 92
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java
| 124
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseComponent.java
| 182
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java
| 79
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java
| 117
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java
| 36
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPooledConnectionProvider.java
| 61
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableComponent.java
| 126
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableDiscoveryComponent.java
| 72
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserComponent.java
| 103
modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserDiscoveryComponent.java
| 62
modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/ComponentTest.java
| 6
modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/PluginTest.java
| 9
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupComponent.java
| 147
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupDiscoveryComponent.java
| 65
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleDiscoveryComponent.java
| 35
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleFlashRecoveryAreaComponent.java
| 40
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OraclePluginLifecycleListener.java
| 19
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OraclePooledConnectionProvider.java
| 71
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java
| 96
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleTablespaceComponent.java
| 40
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java
| 40
modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml
| 8
modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/ComponentTest.java
| 19
modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
| 28
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseComponent.java
| 312
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseDiscoveryComponent.java
| 18
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDiscoveryComponent.java
| 95
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresPluginLifecycleListener.java
| 7
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresPooledConnectionProvider.java
| 62
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresServerComponent.java
| 258
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableComponent.java
| 98
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableDiscoveryComponent.java
| 61
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserComponent.java
| 100
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserDiscoveryComponent.java
| 28
modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/util/PostgresqlConfFile.java
| 15
modules/plugins/postgres/src/test/java/org/rhq/plugins/postgres/test/PostgresPluginTest.java
| 10
modules/plugins/virt/src/main/java/org/rhq/plugins/virt/VirtualizationHostDiscoveryComponent.java
| 9
pom.xml
| 4
156 files changed, 18144 insertions(+), 11230 deletions(-)
New commits:
commit 3498c4eb990be7416a2fa79942ade306773e63bb
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Fri Jan 3 16:05:16 2014 -0500
Some tweaks to test code
diff --git
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
index 2bcb7aa..2cca059 100644
---
a/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
+++
b/modules/core/plugin-container/src/test/java/org/rhq/core/pc/upgrade/FakeServerInventory.java
@@ -421,10 +421,6 @@ public class FakeServerInventory {
return platform == null ? null :
PlatformSyncInfo.buildPlatformSyncInfo(platform);
}
- private Collection<ResourceSyncInfo> getResourceSyncInfo(Resource resource) {
- return resource == null ? null : convert(resource);
- }
-
private static Collection<ResourceSyncInfo> convert(Resource root) {
Set<ResourceSyncInfo> result = new HashSet<ResourceSyncInfo>();
convertInternal(root, result);
diff --git
a/modules/core/plugin-container/src/test/java/org/rhq/test/pc/PluginContainerTest.java
b/modules/core/plugin-container/src/test/java/org/rhq/test/pc/PluginContainerTest.java
index c9528a0..5beb7a5 100644
---
a/modules/core/plugin-container/src/test/java/org/rhq/test/pc/PluginContainerTest.java
+++
b/modules/core/plugin-container/src/test/java/org/rhq/test/pc/PluginContainerTest.java
@@ -60,7 +60,7 @@ import org.rhq.test.JMockTest;
* <p>
* This class is used to declaratively setup a plugin container a test wants
* to use using the {@link PluginContainerSetup} annotation on a test method or class.
- *
+ *
* @author Lukas Krejci
*/
public class PluginContainerTest extends JMockTest {
@@ -96,9 +96,9 @@ public class PluginContainerTest extends JMockTest {
* provided by JMock.
* <p>
* This method together with {@link #setServerSideFake(String, Object)} provides a
generic
- * "storage" for tests to share these objects and is only provided as a
convenience to
+ * "storage" for tests to share these objects and is only provided as a
convenience to
* the test writers. There's nothing that would manadate using it.
- *
+ *
* @param name
* @return
*/
@@ -114,7 +114,7 @@ public class PluginContainerTest extends JMockTest {
}
/**
- * Returns the {@link PluginContainerConfiguration} as configured using
+ * Returns the {@link PluginContainerConfiguration} as configured using
* the {@link PluginContainerSetup} annotation on the current test (or null
* if no such thing is configured).
* @return
@@ -202,7 +202,7 @@ public class PluginContainerTest extends JMockTest {
* <p>
* This is not done automatically to support sharing the plugin container among
* multiple tests to simulate upgrades, etc.
- *
+ *
* @throws IOException
*/
public static void clearStorageOfCurrentPluginContainer() throws IOException {
@@ -219,9 +219,9 @@ public class PluginContainerTest extends JMockTest {
/**
* This method clears the storage of all tests made. This is useful in {@link
AfterSuite}
- * method to clean up after all the tests (annotated with {@link
PluginContainerSetup})
+ * method to clean up after all the tests (annotated with {@link
PluginContainerSetup})
* that have been run.
- *
+ *
* @throws IOException
*/
public synchronized static void clearStorage() throws IOException {
@@ -238,9 +238,9 @@ public class PluginContainerTest extends JMockTest {
* this method is provided to automatically clean up after all the plugin container
tests that ran
* in the test suite.
* <p>
- * If you use PluginContainerTest as a listener, you have to call {@link
#clearStorage()} method
+ * If you use PluginContainerTest as a listener, you have to call {@link
#clearStorage()} method
* on your own.
- *
+ *
* @throws IOException
*/
@AfterSuite
@@ -249,12 +249,12 @@ public class PluginContainerTest extends JMockTest {
}
/**
- * This method returns the {@link PluginContainerConfiguration} that will be used in
- * the current test as was configured by the PluginContainerSetup annotation.
+ * This method returns the {@link PluginContainerConfiguration} that will be used in
+ * the current test as was configured by the PluginContainerSetup annotation.
* <p>
- * If your test class inherits from PluginContainerTest, you can override this method
+ * If your test class inherits from PluginContainerTest, you can override this
method
* to provide custom configuration.
- *
+ *
* @param testObject the object of the current test
* @param testMethod the test method currently being executed on the test object
* @return
@@ -293,7 +293,7 @@ public class PluginContainerTest extends JMockTest {
}
/**
- * This method is called after the test to tear down resources associated with the
+ * This method is called after the test to tear down resources associated with the
* current plugin container configuration.
*/
protected void tearDownPluginContainerConfiguration() {
@@ -371,9 +371,16 @@ public class PluginContainerTest extends JMockTest {
}
}
+ // Note that on WINDOWS this does not always/usually work and therefore test
failures
+ // tend to happen. For unknown reasons windows/jvm keeps a lock on the plugin jar
and it
+ // fails to delete, thus allowing for multiple versions of the plugin in the same
path. I've
+ // added a system out to make it more clear in the log. There was no obvious
workaround.
private void deletePlugins(File deployDirectory) throws IOException {
if (deployDirectory.exists()) {
- FileUtil.purge(deployDirectory, false);
+ FileUtil.purge(deployDirectory, true);
+ }
+ if (deployDirectory.exists()) {
+ throw new IllegalStateException("Failed to clean up plugins in [" +
deployDirectory.getPath() + "]");
}
}
commit cfc253df7a2a3853adebde405d15dce8246d71d2
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Thu Jan 2 11:12:18 2014 -0500
i'll assume this was a mistake to import a JUnit annotation, and it should have
been testng
diff --git
a/modules/enterprise/remoting/cli/src/test/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProviderTest.java
b/modules/enterprise/remoting/cli/src/test/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProviderTest.java
index 4060d07..8227e38 100644
---
a/modules/enterprise/remoting/cli/src/test/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProviderTest.java
+++
b/modules/enterprise/remoting/cli/src/test/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProviderTest.java
@@ -28,8 +28,8 @@ import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
-import org.junit.BeforeClass;
import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
commit fe8df7628c6ec39ed99be17b6c951a1b64e11299
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Thu Jan 2 10:50:02 2014 -0500
BZ 994250 - finish the merging/peer review for patches submitted so that rhqctl
returns proper exit codes. Note that this completes the merge of the two submitted patches
- see prior two commits to this one. This third commit fixes some problems with the
original patches: 1. Some scripts/files are not found in bin/internal of the distro, but
rather are in bin/ - so we need to avoid using getBinDir() in those cases 2. Fix the code
to conform to code conventions - DEATH TO TABS! 3. Remove a constant that got resurrected
(ControlCommand.RHQ_STORAGE_BASEDIR_PROP is no longer needed) 4. A couple other minor
things
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/ControlCommand.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/ControlCommand.java
index 27f8e8f..a13a598 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/ControlCommand.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/ControlCommand.java
@@ -60,7 +60,6 @@ public abstract class ControlCommand {
public static final String SERVER_OPTION = "server";
public static final String STORAGE_OPTION = "storage";
public static final String AGENT_OPTION = "agent";
- public static final String RHQ_STORAGE_BASEDIR_PROP =
"rhq.storage.basedir";
public static final String RHQ_AGENT_BASEDIR_PROP = "rhq.agent.basedir";
protected static final String STORAGE_BASEDIR_NAME = "rhq-storage";
@@ -300,7 +299,7 @@ public abstract class ControlCommand {
}
protected String getStoragePid() throws IOException {
- File pidFile = getStoragePidFile();
+ File pidFile = getStoragePidFile();
if (pidFile.exists()) {
return StreamUtil.slurp(new FileReader(pidFile));
@@ -494,18 +493,18 @@ public abstract class ControlCommand {
protected boolean isStorageRunning() throws IOException {
String pid = getStoragePid();
- if(pid == null) {
- return false;
- } else if(pid != null && !isUnixPidRunning(pid)) {
- // There is a phantom pidfile
- File pidFile = getStoragePidFile();
- if(!pidFile.delete()) {
- throw new RHQControlException("Could not delete storage pidfile " +
pidFile.getAbsolutePath());
- }
- return false;
- } else {
- return true;
- }
+ if (pid == null) {
+ return false;
+ } else if (pid != null && !isUnixPidRunning(pid)) {
+ // There is a phantom pidfile
+ File pidFile = getStoragePidFile();
+ if (!pidFile.delete()) {
+ throw new RHQControlException("Could not delete storage pidfile
" + pidFile.getAbsolutePath());
+ }
+ return false;
+ } else {
+ return true;
+ }
}
private class NullOutputStream extends OutputStream {
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
index 28a37de..88b085f 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
@@ -135,7 +135,7 @@ public class RHQControl {
} catch (Throwable t) {
log.warn("Failed to clean up after the failed installation attempt.
"
+ "You may have to clean up some things before attempting to
install again", t);
- rValue = EXIT_CODE_OPERATION_FAILED;
+ rValue = EXIT_CODE_OPERATION_FAILED;
}
}
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/AbstractInstall.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/AbstractInstall.java
index 1b3d47b..ed2b2f8 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/AbstractInstall.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/AbstractInstall.java
@@ -88,14 +88,14 @@ public abstract class AbstractInstall extends ControlCommand {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine;
- int rValue = RHQControl.EXIT_CODE_OK;
+ int rValue = RHQControl.EXIT_CODE_OK;
if (replaceExistingService) {
- commandLine = getCommandLine(batFile, "stop");
- rValue = Math.max(rValue, executor.execute(commandLine));
+ commandLine = getCommandLine(batFile, "stop");
+ rValue = Math.max(rValue, executor.execute(commandLine));
- commandLine = getCommandLine(batFile, "remove");
- rValue = Math.max(rValue, executor.execute(commandLine));
+ commandLine = getCommandLine(batFile, "remove");
+ rValue = Math.max(rValue, executor.execute(commandLine));
}
commandLine = getCommandLine(batFile, "install");
@@ -277,7 +277,7 @@ public abstract class AbstractInstall extends ControlCommand {
return RHQControl.EXIT_CODE_OK;
}
- int rValue = 0;
+ int rValue = 0;
try {
File agentBinDir = new File(agentBasedir, "bin");
@@ -317,7 +317,7 @@ public abstract class AbstractInstall extends ControlCommand {
throw e;
}
- return rValue;
+ return rValue;
}
protected int startAgent(final File agentBasedir) throws Exception {
@@ -366,7 +366,7 @@ public abstract class AbstractInstall extends ControlCommand {
Executor executor = new DefaultExecutor();
executor.setWorkingDirectory(agentBinDir);
executor.setStreamHandler(new PumpStreamHandler());
- org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-agent-wrapper", "stop");
+ org.apache.commons.exec.CommandLine commandLine;
int rValue = 0;
@@ -635,7 +635,7 @@ public abstract class AbstractInstall extends ControlCommand {
clearAgentPreferences();
int rValue = installAgent(agentBasedir);
configureAgent(agentBasedir, commandLine);
- return rValue;
+ return rValue;
}
private int installAgent(final File agentBasedir) throws IOException {
@@ -667,7 +667,7 @@ public abstract class AbstractInstall extends ControlCommand {
int exitValue = executor.execute(commandLine);
log.info("The agent installer finished running with exit value " +
exitValue);
- return exitValue;
+ return exitValue;
} catch (IOException e) {
log.error("An error occurred while running the agent installer: " +
e.getMessage());
throw e;
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Start.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Start.java
index 5d540a1..e2ef3a8 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Start.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Start.java
@@ -138,7 +138,7 @@ public class Start extends ControlCommand {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine;
- int rValue;
+ int rValue;
// Cassandra looks for JAVA_HOME or then defaults to PATH. We want it to use the
Java
// defined for RHQ, so make sure JAVA_HOME is set, and set to the RHQ Java for
the executor
@@ -167,7 +167,7 @@ public class Start extends ControlCommand {
// For now we are duplicating logic in the status command. This code will be
// replaced when we implement a rhq-storage.sh script.
if (isStorageRunning()) {
- String pid = getStoragePid();
+ String pid = getStoragePid();
System.out.println("RHQ storage node (pid " + pid + ") is
running");
rValue = RHQControl.EXIT_CODE_OK;
} else {
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Stop.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Stop.java
index a3920e0..7ef66b4 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Stop.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Stop.java
@@ -144,7 +144,7 @@ public class Stop extends AbstractInstall {
rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
- if(isStorageRunning()) {
+ if (isStorageRunning()) {
String pid = getStoragePid();
System.out.println("Stopping RHQ storage node...");
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
index cc3d8c2..e80edd9 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
@@ -186,7 +186,7 @@ public class Upgrade extends AbstractInstall {
return exitValue;
}
- // If any failures occur during upgrade, we know we need to reset
rhq-server.properties.
+ // If any failures occur during upgrade, we know we need to reset
rhq-server.properties.
final FileReverter serverPropFileReverter = new
FileReverter(getServerPropertiesFile());
addUndoTask(new ControlCommand.UndoTask("Reverting server properties
file") {
public void performUndoWork() throws Exception {
@@ -229,7 +229,7 @@ public class Upgrade extends AbstractInstall {
}
} catch (Throwable t) {
log.warn("Unable to stop services: " + t.getMessage());
- rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
}
@@ -262,7 +262,7 @@ public class Upgrade extends AbstractInstall {
}
Executor executor = new DefaultExecutor();
- executor.setWorkingDirectory(getBinDir());
+ executor.setWorkingDirectory(new File(getBaseDir(), "bin")); //
data migrator script is not in bin/internal
executor.setStreamHandler(new PumpStreamHandler());
int exitValue = executor.execute(commandLine);
@@ -546,7 +546,7 @@ public class Upgrade extends AbstractInstall {
}
// now merge the old settings in with the default properties from the new server
install
- String newServerPropsFilePath = new File(getBinDir(),
"rhq-server.properties").getAbsolutePath();
+ String newServerPropsFilePath = new File(getBaseDir(),
"bin/rhq-server.properties").getAbsolutePath();
PropertiesFileUpdate newServerPropsFile = new
PropertiesFileUpdate(newServerPropsFilePath);
newServerPropsFile.update(oldServerProps);
commit c34ceb3b055bbd0ec67ef71bb7c14212fffae76e
Author: burmanm <yak(a)iki.fi>
Date: Sat Dec 28 23:56:16 2013 +0200
Fix the return codes for rhq-server.sh status and clean commands.
diff --git
a/modules/enterprise/server/appserver/src/main/bin-resources/bin/internal/rhq-server.sh
b/modules/enterprise/server/appserver/src/main/bin-resources/bin/internal/rhq-server.sh
index 9856190..1b974ae 100755
---
a/modules/enterprise/server/appserver/src/main/bin-resources/bin/internal/rhq-server.sh
+++
b/modules/enterprise/server/appserver/src/main/bin-resources/bin/internal/rhq-server.sh
@@ -610,7 +610,7 @@ case "$1" in
if [ "$_SERVER_RUNNING" = "1" ]; then
echo "$_SERVER_STATUS"
echo "Please shutdown the server before cleaning."
- exit 0
+ exit 1
fi
echo "Cleaning data, tmp and log directories..."
@@ -622,6 +622,9 @@ case "$1" in
'status')
echo "$_SERVER_STATUS"
echo "$_JVM_STATUS"
+ if [ "$_SERVER_RUNNING" = "0" ] || [ "$_JVM_RUNNING" = 0
]; then
+ exit 3
+ fi
exit 0
;;
commit 59ff38658a1fc8a54b7e6a2b937ee0fa645666fe
Author: burmanm <yak(a)iki.fi>
Date: Tue Aug 6 17:52:38 2013 +0200
Fix return codes of the rhqctl command, rebased to the 4.10 master.
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/ControlCommand.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/ControlCommand.java
index db6a0ca..27f8e8f 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/ControlCommand.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/ControlCommand.java
@@ -60,6 +60,7 @@ public abstract class ControlCommand {
public static final String SERVER_OPTION = "server";
public static final String STORAGE_OPTION = "storage";
public static final String AGENT_OPTION = "agent";
+ public static final String RHQ_STORAGE_BASEDIR_PROP =
"rhq.storage.basedir";
public static final String RHQ_AGENT_BASEDIR_PROP = "rhq.agent.basedir";
protected static final String STORAGE_BASEDIR_NAME = "rhq-storage";
@@ -133,6 +134,7 @@ public abstract class ControlCommand {
throw new RHQControlException("Failed to load configuration",
e);
}
}
+
defaultStorageBasedir = new File(getBaseDir(), STORAGE_BASEDIR_NAME);
defaultAgentBasedir = new File(getBaseDir().getParent(), AGENT_BASEDIR_NAME);
}
@@ -143,22 +145,26 @@ public abstract class ControlCommand {
public abstract Options getOptions();
- protected abstract void exec(CommandLine commandLine);
+ protected abstract int exec(CommandLine commandLine);
- public void exec(String[] args) {
+ public int exec(String[] args) {
Options options = getOptions();
+ int rValue = RHQControl.EXIT_CODE_OK;
try {
CommandLineParser parser = new PosixParser();
CommandLine cmdLine = parser.parse(options, args);
- exec(cmdLine);
+ rValue = exec(cmdLine);
if (rhqctlConfig != null) {
rhqctlConfig.save();
}
} catch (ParseException e) {
printUsage();
+ rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
} catch (ConfigurationException e) {
throw new RHQControlException("Failed to update " +
getRhqCtlProperties(), e);
+ } finally {
+ return rValue;
}
}
@@ -386,7 +392,6 @@ public abstract class ControlCommand {
result = new org.apache.commons.exec.CommandLine("cmd.exe");
result.addArgument("/C");
result.addArgument(scriptName.replace('/', '\\') +
".bat");
-
} else {
result = new org.apache.commons.exec.CommandLine("./" + (addShExt ?
scriptName + ".sh" : scriptName));
}
@@ -456,6 +461,7 @@ public abstract class ControlCommand {
PumpStreamHandler streamHandler = new PumpStreamHandler(new NullOutputStream(),
new NullOutputStream());
executor.setStreamHandler(streamHandler);
org.apache.commons.exec.CommandLine commandLine;
+
commandLine = new
org.apache.commons.exec.CommandLine("kill").addArgument(pid);
executor.execute(commandLine);
}
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
index 24e4995..28a37de 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
@@ -22,6 +22,7 @@
* * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
+
package org.rhq.server.control;
import java.io.Console;
@@ -50,6 +51,19 @@ public class RHQControl {
private final Log log = LogFactory.getLog(RHQControl.class);
+ public static final int EXIT_CODE_OK = 0;
+
+ // These try to follow the LSB specification - status command
+ public static final int EXIT_CODE_STATUS_NOT_RUNNING = 3;
+ public static final int EXIT_CODE_STATUS_UNKNOWN = 4;
+
+ // These try to follow the LSB specification - other commands
+ public static final int EXIT_CODE_OPERATION_FAILED = 1;
+ public static final int EXIT_CODE_INVALID_ARGUMENT = 2;
+ public static final int EXIT_CODE_NOT_INSTALLED = 5;
+// public static final int EXIT_CODE_OPERATION_NOT_RUNNING = 7;
+
+
private Commands commands = new Commands();
public void printUsage() {
@@ -63,7 +77,8 @@ public class RHQControl {
helpFormatter.printHelp(syntax, header, commands.getOptions(), footer);
}
- public void exec(String[] args) {
+ public int exec(String[] args) {
+ int rValue = EXIT_CODE_OK;
ControlCommand command = null;
boolean undo = false;
AbortHook abortHook = new AbortHook();
@@ -71,6 +86,7 @@ public class RHQControl {
try {
if (args.length == 0) {
printUsage();
+ rValue = EXIT_CODE_INVALID_ARGUMENT;
} else {
String commandName = findCommand(commands, args);
command = commands.get(commandName);
@@ -84,10 +100,11 @@ public class RHQControl {
Runtime.getRuntime().addShutdownHook(abortHook);
// run the command
- command.exec(getCommandLine(commandName, args));
+ rValue = command.exec(getCommandLine(commandName, args));
}
} catch (UsageException e) {
printUsage();
+ rValue = EXIT_CODE_INVALID_ARGUMENT;
} catch (RHQControlException e) {
undo = true;
@@ -98,9 +115,11 @@ public class RHQControl {
} else {
log.error(rootCause.getMessage());
}
+ rValue = EXIT_CODE_OPERATION_FAILED;
} catch (Throwable t) {
undo = true;
log.error(t);
+ rValue = EXIT_CODE_OPERATION_FAILED;
} finally {
abortHook.setCommand(null);
Runtime.getRuntime().removeShutdownHook(abortHook);
@@ -116,10 +135,11 @@ public class RHQControl {
} catch (Throwable t) {
log.warn("Failed to clean up after the failed installation attempt.
"
+ "You may have to clean up some things before attempting to
install again", t);
+ rValue = EXIT_CODE_OPERATION_FAILED;
}
}
- return;
+ return rValue;
}
private void logWarningIfAgentRPMIsInstalled(ControlCommand command) {
@@ -303,9 +323,9 @@ public class RHQControl {
public static void main(String[] args) throws Exception {
RHQControl control = new RHQControl();
+ int rValue;
try {
- control.exec(args);
- System.exit(0);
+ rValue = control.exec(args);
} catch (RHQControlException e) {
Throwable rootCause = ThrowableUtil.getRootCause(e);
// Only show the messy stack trace if we're in debug mode. Otherwise keep
it cleaner for the user...
@@ -314,8 +334,9 @@ public class RHQControl {
} else {
control.log.error("There was an unexpected error: " +
rootCause.getMessage());
}
- System.exit(1);
+ rValue = EXIT_CODE_OPERATION_FAILED;
}
+ System.exit(rValue);
}
private class AbortHook extends Thread {
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/AbstractInstall.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/AbstractInstall.java
index eb6cd15..1b3d47b 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/AbstractInstall.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/AbstractInstall.java
@@ -43,6 +43,7 @@ import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.exec.DefaultExecuteResultHandler;
import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;
@@ -55,6 +56,7 @@ import org.rhq.core.util.file.FileReverter;
import org.rhq.core.util.file.FileUtil;
import org.rhq.core.util.stream.StreamUtil;
import org.rhq.server.control.ControlCommand;
+import org.rhq.server.control.RHQControl;
import org.rhq.server.control.RHQControlException;
/**
@@ -79,28 +81,31 @@ public abstract class AbstractInstall extends ControlCommand {
private static final String PREF_RHQ_AGENT_SERVER_BINDPORT =
"rhq.agent.server.bind-port";
private static final String PREF_RHQ_AGENT_SERVER_TRANSPORTPARAMS =
"rhq.agent.server.transport-params";
- protected void installWindowsService(File workingDir, String batFile, boolean
replaceExistingService, boolean start)
+ protected int installWindowsService(File workingDir, String batFile, boolean
replaceExistingService, boolean start)
throws Exception {
Executor executor = new DefaultExecutor();
executor.setWorkingDirectory(workingDir);
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine;
+ int rValue = RHQControl.EXIT_CODE_OK;
+
if (replaceExistingService) {
- commandLine = getCommandLine(batFile, "stop");
- executor.execute(commandLine);
+ commandLine = getCommandLine(batFile, "stop");
+ rValue = Math.max(rValue, executor.execute(commandLine));
- commandLine = getCommandLine(batFile, "remove");
- executor.execute(commandLine);
+ commandLine = getCommandLine(batFile, "remove");
+ rValue = Math.max(rValue, executor.execute(commandLine));
}
commandLine = getCommandLine(batFile, "install");
- executor.execute(commandLine);
+ rValue = Math.max(rValue, executor.execute(commandLine));
if (start) {
commandLine = getCommandLine(batFile, "start");
- executor.execute(commandLine);
+ rValue = Math.max(rValue, executor.execute(commandLine));
}
+ return rValue;
}
protected void validateCustomStorageDataDirectories(CommandLine commandLine,
List<String> errors) {
@@ -155,6 +160,31 @@ public abstract class AbstractInstall extends ControlCommand {
}
+ protected boolean isUnixPidRunning(String pid) {
+
+ Executor executor = new DefaultExecutor();
+ executor.setWorkingDirectory(getBinDir());
+ executor.setStreamHandler(new PumpStreamHandler());
+ org.apache.commons.exec.CommandLine commandLine;
+
+ commandLine = new
org.apache.commons.exec.CommandLine("/bin/kill").addArgument("-0").addArgument(pid);
+
+ try {
+ int code = executor.execute(commandLine);
+ if (code != 0) {
+ return false;
+ }
+ } catch (ExecuteException ee) {
+ if (ee.getExitValue() == 1) {
+ // return code 1 means process does not exist
+ return false;
+ }
+ } catch (IOException e) {
+ log.error("Checking for running process failed: " +
e.getMessage());
+ }
+ return true;
+ }
+
protected void waitForRHQServerToInitialize() throws Exception {
try {
final long messageInterval = 30000L;
@@ -169,13 +199,13 @@ public abstract class AbstractInstall extends ControlCommand {
long totalWait = (now - timerStart);
if (totalWait < problemMessageInterval) {
- log.info("Still waiting for server to initialize...");
+ log.info("Still waiting for server to start...");
} else {
long minutes = totalWait / 60000;
log.info("It has been over ["
+ minutes
- + "] minutes - you may want to ensure your server
initialization is proceeding as expected. You can check the log at ["
+ + "] minutes - you may want to ensure your server
startup is proceeding as expected. You can check the log at ["
+ new File(getBaseDir(),
"logs/server.log").getPath() + "].");
timerStart = now;
@@ -196,6 +226,7 @@ public abstract class AbstractInstall extends ControlCommand {
}
}
+ @SuppressWarnings("resource")
protected boolean isRHQServerInitialized() throws IOException {
BufferedReader reader = null;
@@ -241,11 +272,13 @@ public abstract class AbstractInstall extends ControlCommand {
}
}
- protected void updateWindowsAgentService(final File agentBasedir) throws Exception {
+ protected int updateWindowsAgentService(final File agentBasedir) throws Exception {
if (!isWindows()) {
- return;
+ return RHQControl.EXIT_CODE_OK;
}
+ int rValue = 0;
+
try {
File agentBinDir = new File(agentBasedir, "bin");
if (!agentBinDir.exists()) {
@@ -262,7 +295,7 @@ public abstract class AbstractInstall extends ControlCommand {
commandLine = getCommandLine("rhq-agent-wrapper",
"stop");
try {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
// Ignore, service may not exist or be running, , script returns 1
log.debug("Failed to stop agent service", e);
@@ -270,22 +303,26 @@ public abstract class AbstractInstall extends ControlCommand {
commandLine = getCommandLine("rhq-agent-wrapper",
"remove");
try {
- executor.execute(commandLine);
+ rValue = Math.max(rValue, executor.execute(commandLine));
} catch (Exception e) {
// Ignore, service may not exist, script returns 1
log.debug("Failed to uninstall agent service", e);
}
commandLine = getCommandLine("rhq-agent-wrapper",
"install");
- executor.execute(commandLine);
+ rValue = Math.max(rValue, executor.execute(commandLine));
} catch (IOException e) {
log.error("An error occurred while updating the agent service: " +
e.getMessage());
throw e;
}
+
+ return rValue;
}
- protected void startAgent(final File agentBasedir) throws Exception {
+ protected int startAgent(final File agentBasedir) throws Exception {
+ int rValue;
+
try {
File agentBinDir = new File(agentBasedir, "bin");
if (!agentBinDir.exists()) {
@@ -300,7 +337,7 @@ public abstract class AbstractInstall extends ControlCommand {
// For *nix, just start the server in the background, for Win, now that the
service is installed, start it
commandLine = getCommandLine("rhq-agent-wrapper",
"start");
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
// if any errors occur after now, we need to stop the agent
addUndoTask(new ControlCommand.UndoTask("Stopping agent") {
@@ -314,9 +351,10 @@ public abstract class AbstractInstall extends ControlCommand {
log.error("An error occurred while starting the agent: " +
e.getMessage());
throw e;
}
+ return rValue;
}
- protected void killAgent(File agentBasedir) throws Exception {
+ protected int killAgent(File agentBasedir) throws Exception {
File agentBinDir = new File(agentBasedir, "bin");
if (!agentBinDir.exists()) {
@@ -328,25 +366,32 @@ public abstract class AbstractInstall extends ControlCommand {
Executor executor = new DefaultExecutor();
executor.setWorkingDirectory(agentBinDir);
executor.setStreamHandler(new PumpStreamHandler());
+ org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-agent-wrapper", "stop");
+
+ int rValue = 0;
if (isWindows()) {
try {
- org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-agent-wrapper", "stop");
- executor.execute(commandLine);
+ commandLine = getCommandLine("rhq-agent-wrapper",
"stop");
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
// Ignore, service may not exist or be running, , script returns 1
log.debug("Failed to stop agent service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
String pid = getAgentPid();
if (pid != null) {
- org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-agent-wrapper", "kill");
- executor.execute(commandLine);
+ commandLine = getCommandLine("rhq-agent-wrapper",
"kill");
+ rValue = executor.execute(commandLine);
+ } else {
+ rValue = RHQControl.EXIT_CODE_OK;
}
}
+ return rValue;
}
- protected void stopServer() throws Exception {
+ protected int stopServer() throws Exception {
File serverBinDir = getBinDir();
if (!serverBinDir.exists()) {
@@ -360,16 +405,20 @@ public abstract class AbstractInstall extends ControlCommand {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-server", "stop");
+ int rValue;
+
if (isWindows()) {
try {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
// Ignore, service may not exist or be running, , script returns 1
log.debug("Failed to stop server service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
}
+ return rValue;
}
protected void startRHQServerForInstallation() throws IOException {
@@ -446,7 +495,7 @@ public abstract class AbstractInstall extends ControlCommand {
}
}
- protected void runRHQServerInstaller() throws IOException {
+ protected int runRHQServerInstaller() throws IOException {
try {
log.info("Installing RHQ server");
@@ -467,10 +516,14 @@ public abstract class AbstractInstall extends ControlCommand {
executor.setWorkingDirectory(getBinDir());
executor.setStreamHandler(new PumpStreamHandler());
- executor.execute(commandLine, new DefaultExecuteResultHandler());
+ DefaultExecuteResultHandler executeHandler = new
DefaultExecuteResultHandler();
+
+ executor.execute(commandLine, executeHandler);
log.info("The server installer is running");
- } catch (Exception e) {
+ return executeHandler.getExitValue();
+ } catch (IOException e) {
log.error("An error occurred while starting the server installer: "
+ e.getMessage());
+ return RHQControl.EXIT_CODE_NOT_INSTALLED;
}
}
@@ -560,6 +613,7 @@ public abstract class AbstractInstall extends ControlCommand {
Executor executor = new DefaultExecutor();
executor.setWorkingDirectory(getBinDir());
executor.setStreamHandler(new PumpStreamHandler());
+
int exitCode = executor.execute(commandLine);
log.info("The storage node installer has finished with an exit value of
" + exitCode);
@@ -577,13 +631,14 @@ public abstract class AbstractInstall extends ControlCommand {
}
}
- protected void installAgent(final File agentBasedir, final CommandLine commandLine)
throws Exception {
+ protected int installAgent(final File agentBasedir, final CommandLine commandLine)
throws Exception {
clearAgentPreferences();
- installAgent(agentBasedir);
+ int rValue = installAgent(agentBasedir);
configureAgent(agentBasedir, commandLine);
+ return rValue;
}
- private void installAgent(final File agentBasedir) throws IOException {
+ private int installAgent(final File agentBasedir) throws IOException {
try {
log.info("Installing RHQ agent");
@@ -612,6 +667,7 @@ public abstract class AbstractInstall extends ControlCommand {
int exitValue = executor.execute(commandLine);
log.info("The agent installer finished running with exit value " +
exitValue);
+ return exitValue;
} catch (IOException e) {
log.error("An error occurred while running the agent installer: " +
e.getMessage());
throw e;
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Console.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Console.java
index 4139969..6039e9d 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Console.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Console.java
@@ -32,6 +32,7 @@ import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;
import org.rhq.server.control.ControlCommand;
+import org.rhq.server.control.RHQControl;
import org.rhq.server.control.RHQControlException;
/**
@@ -70,32 +71,38 @@ public class Console extends ControlCommand {
}
@Override
- protected void exec(CommandLine commandLine) {
+ protected int exec(CommandLine commandLine) {
+ int rValue = RHQControl.EXIT_CODE_OK;
+
if (commandLine.getOptions().length != 1) {
printUsage();
+ rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
} else {
String option = commandLine.getOptions()[0].getLongOpt();
try {
if (option.equals(STORAGE_OPTION)) {
if (isStorageInstalled()) {
- startStorageInForeground();
+ rValue = Math.max(rValue, startStorageInForeground());
} else {
log.warn("It appears that the storage node is not installed.
The --" + STORAGE_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
} else if (option.equals(SERVER_OPTION)) {
if (isServerInstalled()) {
- startServerInForeground();
+ rValue = Math.max(rValue, startServerInForeground());
} else {
log.warn("It appears that the server is not installed. The
--" + SERVER_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
} else if (option.equals(AGENT_OPTION)) {
if (isAgentInstalled()) {
- startAgentInForeground();
+ rValue = Math.max(rValue, startAgentInForeground());
} else {
log.warn("It appears that the agent is not installed. The
--" + AGENT_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
} else {
throw new IllegalArgumentException(option + " is not a supported
option");
@@ -104,32 +111,33 @@ public class Console extends ControlCommand {
throw new RHQControlException("Failed to execute console
command", e);
}
}
+ return rValue;
}
- private void startStorageInForeground() throws Exception {
+ private int startStorageInForeground() throws Exception {
log.debug("Starting RHQ storage node in foreground");
File storageBinDir = new File(getStorageBasedir(), "bin");
org.apache.commons.exec.CommandLine commandLine = new
org.apache.commons.exec.CommandLine(getCommandLine(false,
"cassandra", "-f"));
- Executor exeuctor = new DefaultExecutor();
- exeuctor.setWorkingDirectory(storageBinDir);
- exeuctor.setStreamHandler(new PumpStreamHandler());
- exeuctor.execute(commandLine);
+ Executor executor = new DefaultExecutor();
+ executor.setWorkingDirectory(storageBinDir);
+ executor.setStreamHandler(new PumpStreamHandler());
+ return executor.execute(commandLine);
}
- private void startServerInForeground() throws Exception {
+ private int startServerInForeground() throws Exception {
log.debug("Starting RHQ server in foreground");
org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-server", "console");
Executor executor = new DefaultExecutor();
executor.setWorkingDirectory(getBinDir());
executor.setStreamHandler(new PumpStreamHandler());
- executor.execute(commandLine);
+ return executor.execute(commandLine);
}
- private void startAgentInForeground() throws Exception {
+ private int startAgentInForeground() throws Exception {
log.info("Starting RHQ agent in foreground");
File agentHomeDir = getAgentBasedir();
@@ -165,6 +173,7 @@ public class Console extends ControlCommand {
// agentThread.start();
// doneSignal.await();
// agentThread.join();
+ return RHQControl.EXIT_CODE_OK;
}
private class AgentInputStreamPipe extends Thread {
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Install.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Install.java
index be76e59..3ab3f00 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Install.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Install.java
@@ -33,6 +33,7 @@ import org.apache.commons.cli.Options;
import org.rhq.core.util.file.FileReverter;
import org.rhq.server.control.ControlCommand;
+import org.rhq.server.control.RHQControl;
import org.rhq.server.control.RHQControlException;
/**
@@ -95,10 +96,11 @@ public class Install extends AbstractInstall {
}
@Override
- protected void exec(CommandLine commandLine) {
+ protected int exec(CommandLine commandLine) {
boolean start = commandLine.hasOption(START_OPTION);
boolean startedStorage = false;
boolean startedServer = false;
+ int rValue = RHQControl.EXIT_CODE_OK;
try {
List<String> errors = validateOptions(commandLine);
@@ -107,7 +109,7 @@ public class Install extends AbstractInstall {
log.error(error);
}
log.error("Exiting due to the previous errors");
- return;
+ return RHQControl.EXIT_CODE_NOT_INSTALLED;
}
// If any failures occur, we know we need to reset rhq-server.properties.
@@ -137,10 +139,10 @@ public class Install extends AbstractInstall {
if (isWindows()) {
log.info("Ensuring the RHQ Storage Windows service exists.
Ignore any CreateService failure.");
- installWindowsService(getBinDir(), "rhq-storage",
false, false);
+ rValue = Math.max(rValue, installWindowsService(getBinDir(),
"rhq-storage", false, false));
}
} else {
- installStorageNode(getStorageBasedir(), commandLine, false);
+ rValue = Math.max(rValue, installStorageNode(getStorageBasedir(),
commandLine, false));
startStorage = start;
}
}
@@ -148,7 +150,7 @@ public class Install extends AbstractInstall {
if (startStorage || installServer) {
startedStorage = true;
Start startCommand = new Start();
- startCommand.exec(new String[] { "start", "--storage"
});
+ rValue = Math.max(rValue, startCommand.exec(new String[] {
"start", "--storage" }));
}
if (installServer) {
@@ -157,12 +159,12 @@ public class Install extends AbstractInstall {
if (isWindows()) {
log.info("Ensuring the RHQ Server Windows service exists.
Ignore any CreateService failure.");
- installWindowsService(getBinDir(), "rhq-server", false,
false);
+ rValue = Math.max(rValue, installWindowsService(getBinDir(),
"rhq-server", false, false));
}
} else {
startedServer = true;
startRHQServerForInstallation();
- runRHQServerInstaller();
+ rValue = Math.max(rValue, runRHQServerInstaller());
waitForRHQServerToInitialize();
}
}
@@ -175,7 +177,7 @@ public class Install extends AbstractInstall {
if (isWindows()) {
try {
log.info("Ensuring the RHQ Agent Windows service exists.
Ignore any CreateService failure.");
- installWindowsService(new File(getAgentBasedir(),
"bin"), "rhq-agent-wrapper", false, false);
+ rValue = Math.max(rValue, installWindowsService(new
File(getAgentBasedir(), "bin"), "rhq-agent-wrapper", false, false));
} catch (Exception e) {
// Ignore, service may already exist or be running, wrapper
script returns 1
log.debug("Failed to stop agent service", e);
@@ -185,10 +187,10 @@ public class Install extends AbstractInstall {
File agentBasedir = getAgentBasedir();
installAgent(agentBasedir, commandLine);
- updateWindowsAgentService(agentBasedir);
+ rValue = Math.max(rValue, updateWindowsAgentService(agentBasedir));
if (start) {
- startAgent(agentBasedir);
+ rValue = Math.max(rValue, startAgent(agentBasedir));
}
}
}
@@ -200,13 +202,14 @@ public class Install extends AbstractInstall {
if (!start && (startedStorage || startedServer)) {
Stop stopCommand = new Stop();
if (startedServer) {
- stopCommand.exec(new String[] { "stop",
"--server" });
+ rValue = Math.max(rValue, stopCommand.exec(new String[] {
"stop", "--server" }));
}
if (startedStorage) {
- stopCommand.exec(new String[] { "stop",
"--storage" });
+ rValue = Math.max(rValue, stopCommand.exec(new String[] {
"stop", "--storage" }));
}
}
}
+ return rValue;
}
private List<String> validateOptions(CommandLine commandLine) {
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Remove.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Remove.java
index cb8f43b..1de4250 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Remove.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Remove.java
@@ -34,6 +34,7 @@ import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;
import org.rhq.server.control.ControlCommand;
+import org.rhq.server.control.RHQControl;
import org.rhq.server.control.RHQControlException;
/**
@@ -74,52 +75,56 @@ public class Remove extends ControlCommand {
}
@Override
- protected void exec(CommandLine commandLine) {
+ protected int exec(CommandLine commandLine) {
+ int rValue = RHQControl.EXIT_CODE_OK;
try {
// if no options specified, then stop whatever is installed
if (commandLine.getOptions().length == 0) {
if (isAgentInstalled()) {
- removeAgentService();
+ rValue = Math.max(rValue, removeAgentService());
}
// the server service may be installed even if the full server install
fails. The files to execute
// the remove are there after the initial unzip, so just go ahead and try
to remove the service. This
// may help clean up a failed install.
- removeServerService();
+ rValue = Math.max(rValue, removeServerService());
if (isStorageInstalled()) {
- removeStorageService();
+ rValue = Math.max(rValue, removeStorageService());
}
} else {
if (commandLine.hasOption(AGENT_OPTION)) {
if (isAgentInstalled()) {
- removeAgentService();
+ rValue = Math.max(rValue, removeAgentService());
} else {
log.warn("It appears that the agent is not installed. The
--" + AGENT_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
}
if (commandLine.hasOption(SERVER_OPTION)) {
// the server service may be installed even if the full server
install fails. The files to execute
// the remove are there after the initial unzip, so just go ahead and
try to remove the service. This
// may help clean up a failed install.
- removeServerService();
+ rValue = Math.max(rValue, removeServerService());
}
if (commandLine.hasOption(STORAGE_OPTION)) {
if (isStorageInstalled()) {
- removeStorageService();
+ rValue = Math.max(rValue, removeStorageService());
} else {
log.warn("It appears that the storage node is not installed.
The --" + STORAGE_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
}
}
} catch (Exception e) {
throw new RHQControlException("Failed to stop services", e);
}
+ return rValue;
}
- private void removeStorageService() throws Exception {
+ private int removeStorageService() throws Exception {
log.debug("Stopping RHQ storage node");
Executor executor = new DefaultExecutor();
@@ -127,12 +132,15 @@ public class Remove extends ControlCommand {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine;
+ int rValue;
+
if (isWindows()) {
commandLine = getCommandLine("rhq-storage", "remove");
try {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
log.debug("Failed to remove storage service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
String pid = getStoragePid();
@@ -141,15 +149,18 @@ public class Remove extends ControlCommand {
System.out.println("RHQ storage node (pid=" + pid + ") is
stopping...");
commandLine = new
org.apache.commons.exec.CommandLine("kill").addArgument(pid);
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
System.out.println("RHQ storage node has stopped");
+ } else {
+ rValue = RHQControl.EXIT_CODE_OK;
}
}
+ return rValue;
}
- private void removeServerService() throws Exception {
+ private int removeServerService() throws Exception {
log.debug("Stopping RHQ server");
Executor executor = new DefaultExecutor();
@@ -157,25 +168,31 @@ public class Remove extends ControlCommand {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine;
+ int rValue;
+
if (isWindows()) {
try {
commandLine = getCommandLine("rhq-server",
"remove");
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
// Ignore, service may not exist or be running, , script returns 1
log.debug("Failed to remove server service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
String pid = getServerPid();
if (pid != null) {
commandLine = getCommandLine("rhq-server", "stop");
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
+ } else {
+ rValue = RHQControl.EXIT_CODE_OK;
}
}
+ return rValue;
}
- private void removeAgentService() throws Exception {
+ private int removeAgentService() throws Exception {
log.debug("Stopping RHQ agent");
File agentBinDir = new File(getAgentBasedir(), "bin");
@@ -184,21 +201,27 @@ public class Remove extends ControlCommand {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine;
+ int rValue;
+
if (isWindows()) {
try {
commandLine = getCommandLine("rhq-agent-wrapper",
"remove");
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
// Ignore, service may not exist, script returns 1
log.debug("Failed to remove agent service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
String pid = getAgentPid();
if (pid != null) {
commandLine = getCommandLine("rhq-agent-wrapper",
"stop");
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
+ } else {
+ rValue = RHQControl.EXIT_CODE_OK;
}
}
+ return rValue;
}
}
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Restart.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Restart.java
index fffb769..40d61c6 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Restart.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Restart.java
@@ -64,11 +64,13 @@ public class Restart extends ControlCommand {
}
@Override
- protected void exec(CommandLine commandLine) {
+ protected int exec(CommandLine commandLine) {
Stop stop = new Stop();
stop.exec(commandLine);
+ // If the server isn't stopped.. restart had some LSB rules.. check 'em.
+
Start start = new Start();
- start.exec(commandLine);
+ return start.exec(commandLine);
}
}
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Start.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Start.java
index 7d621cb..5d540a1 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Start.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Start.java
@@ -36,6 +36,7 @@ import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;
import org.rhq.server.control.ControlCommand;
+import org.rhq.server.control.RHQControl;
import org.rhq.server.control.RHQControlException;
/**
@@ -72,7 +73,8 @@ public class Start extends ControlCommand {
}
@Override
- protected void exec(CommandLine commandLine) {
+ protected int exec(CommandLine commandLine) {
+ int rValue = RHQControl.EXIT_CODE_OK;
try {
// if no options specified, then start whatever is installed
if (commandLine.getOptions().length == 0) {
@@ -82,55 +84,62 @@ public class Start extends ControlCommand {
if (!(storageInstalled || serverInstalled || agentInstalled)) {
log.warn("Nothing to start. No RHQ services are
installed.");
+ rValue = RHQControl.EXIT_CODE_NOT_INSTALLED;
} else {
if (storageInstalled) {
- startStorage();
+ rValue = Math.max(rValue, startStorage());
}
if (serverInstalled) {
- startRHQServer();
+ rValue = Math.max(rValue, startRHQServer());
}
if (agentInstalled) {
- startAgent();
+ rValue = Math.max(rValue, startAgent());
}
}
} else {
if (commandLine.hasOption(STORAGE_OPTION)) {
if (isStorageInstalled()) {
- startStorage();
+ rValue = Math.max(rValue, startStorage());
} else {
log.warn("It appears that the storage node is not installed.
The --" + STORAGE_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_NOT_INSTALLED;
}
}
if (commandLine.hasOption(SERVER_OPTION)) {
if (isServerInstalled()) {
- startRHQServer();
+ rValue = Math.max(rValue, startRHQServer());
} else {
log.warn("It appears that the server is not installed. The
--" + SERVER_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_NOT_INSTALLED;
}
}
if (commandLine.hasOption(AGENT_OPTION)) {
if (isAgentInstalled()) {
- startAgent();
+ rValue = Math.max(rValue, startAgent());
} else {
log.warn("It appears that the agent is not installed. The
--" + AGENT_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_NOT_INSTALLED;
}
}
}
} catch (Exception e) {
throw new RHQControlException("Failed to start services", e);
}
+ return rValue;
}
- private void startStorage() throws Exception {
+ private int startStorage() throws Exception {
log.debug("Starting RHQ storage node");
Executor executor = new DefaultExecutor();
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine;
+ int rValue;
+
// Cassandra looks for JAVA_HOME or then defaults to PATH. We want it to use the
Java
// defined for RHQ, so make sure JAVA_HOME is set, and set to the RHQ Java for
the executor
// environment.
@@ -144,11 +153,12 @@ public class Start extends ControlCommand {
executor.setWorkingDirectory(getBinDir());
commandLine = getCommandLine("rhq-storage", "start");
try {
- executor.execute(commandLine, env);
+ rValue = executor.execute(commandLine, env);
} catch (Exception e) {
// Ignore, service may not exist or may already be running, script
returns 1
log.debug("Failed to start storage service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
File storageBinDir = new File(getStorageBasedir(), "bin");
@@ -159,16 +169,18 @@ public class Start extends ControlCommand {
if (isStorageRunning()) {
String pid = getStoragePid();
System.out.println("RHQ storage node (pid " + pid + ") is
running");
+ rValue = RHQControl.EXIT_CODE_OK;
} else {
commandLine = getCommandLine(false, "cassandra",
"-p", pidFile.getAbsolutePath());
executor.setWorkingDirectory(storageBinDir);
- executor.execute(commandLine, env);
+ rValue = executor.execute(commandLine, env);
}
}
+ return rValue;
}
- private void startRHQServer() throws Exception {
+ private int startRHQServer() throws Exception {
log.debug("Starting RHQ server");
Executor executor = new DefaultExecutor();
@@ -176,19 +188,23 @@ public class Start extends ControlCommand {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-server", "start");
+ int rValue;
+
if (isWindows()) {
try {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
// Ignore, service may not exist or be running, , script returns 1
log.debug("Failed to start server service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
}
+ return rValue;
}
- private void startAgent() throws Exception {
+ private int startAgent() throws Exception {
log.debug("Starting RHQ agent");
File agentBinDir = new File(getAgentBasedir(), "bin");
@@ -197,16 +213,21 @@ public class Start extends ControlCommand {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-agent-wrapper", "start");
+ int rValue;
+
if (isWindows()) {
try {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
// Ignore, service may not exist or be running, , script returns 1
log.debug("Failed to start agent service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
}
+
+ return rValue;
}
}
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Status.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Status.java
index 9ba9f60..e52f0a8 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Status.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Status.java
@@ -35,6 +35,7 @@ import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;
import org.rhq.server.control.ControlCommand;
+import org.rhq.server.control.RHQControl;
import org.rhq.server.control.RHQControlException;
/**
@@ -71,23 +72,24 @@ public class Status extends ControlCommand {
}
@Override
- protected void exec(CommandLine commandLine) {
+ protected int exec(CommandLine commandLine) {
+ int rValue = RHQControl.EXIT_CODE_OK;
try {
// if no options specified, then check the status of whatever is installed
if (commandLine.getOptions().length == 0) {
if (isStorageInstalled()) {
- checkStorageStatus();
+ rValue = Math.max(rValue, checkStorageStatus());
}
if (isServerInstalled()) {
- checkServerStatus();
+ rValue = Math.max(rValue, checkServerStatus());
}
if (isAgentInstalled()) {
- checkAgentStatus();
+ rValue = Math.max(rValue, checkAgentStatus());
}
} else {
if (commandLine.hasOption(STORAGE_OPTION)) {
if (isStorageInstalled()) {
- checkStorageStatus();
+ rValue = Math.max(rValue, checkStorageStatus());
} else {
log.warn("It appears that the storage node is not installed.
The --" + STORAGE_OPTION
+ " option will be ignored.");
@@ -95,7 +97,7 @@ public class Status extends ControlCommand {
}
if (commandLine.hasOption(SERVER_OPTION)) {
if (isServerInstalled()) {
- checkServerStatus();
+ rValue = Math.max(rValue, checkServerStatus());
} else {
log.warn("It appears that the server is not installed. The
--" + SERVER_OPTION
+ " option will be ignored.");
@@ -103,7 +105,7 @@ public class Status extends ControlCommand {
}
if (commandLine.hasOption(AGENT_OPTION)) {
if (isAgentInstalled()) {
- checkAgentStatus();
+ rValue = Math.max(rValue, checkAgentStatus());
} else {
log.warn("It appears that the agent is not installed. The
--" + AGENT_OPTION
+ " option will be ignored.");
@@ -113,11 +115,14 @@ public class Status extends ControlCommand {
} catch (Exception e) {
throw new RHQControlException("Failed to check statuses", e);
}
+ return rValue;
}
- private void checkStorageStatus() throws Exception {
+ private int checkStorageStatus() throws Exception {
log.debug("Checking RHQ storage node status");
+ int rValue = RHQControl.EXIT_CODE_OK;
+
if (isWindows()) {
Executor executor = new DefaultExecutor();
executor.setStreamHandler(new PumpStreamHandler());
@@ -125,31 +130,34 @@ public class Status extends ControlCommand {
executor.setWorkingDirectory(getBinDir());
commandLine = getCommandLine("rhq-storage", "status");
try {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
log.debug("Failed to check storage service status", e);
+ rValue = RHQControl.EXIT_CODE_STATUS_UNKNOWN;
}
} else {
if(isStorageRunning()) {
System.out.println(String.format("%-30s", "RHQ Storage
Node") + " (pid " + String.format("%-7s", getStoragePid()) +
") IS running");
} else {
System.out.println(String.format("%-30s", "RHQ Storage
Node") + " (no pid file) IS NOT running");
+ rValue = RHQControl.EXIT_CODE_STATUS_NOT_RUNNING;
}
}
+ return rValue;
}
- private void checkServerStatus() throws Exception {
+ private int checkServerStatus() throws Exception {
log.debug("Checking RHQ server status");
org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-server", "status");
Executor executor = new DefaultExecutor();
executor.setWorkingDirectory(getBinDir());
executor.setStreamHandler(new PumpStreamHandler());
- executor.execute(commandLine);
+ return executor.execute(commandLine);
}
- private void checkAgentStatus() throws Exception {
+ private int checkAgentStatus() throws Exception {
log.debug("Checking RHQ agent status");
File agentBinDir = new File(getAgentBasedir(), "bin");
@@ -159,7 +167,7 @@ public class Status extends ControlCommand {
executor.setWorkingDirectory(agentBinDir);
executor.setStreamHandler(new PumpStreamHandler());
try {
- executor.execute(commandLine);
+ return executor.execute(commandLine);
} catch (ExecuteException e) {
// For windows the JSW exit code for a status check is expected to be a mask
value and the agent wrapper
// .bat will return it explicitly. We can ignore it and assume that the
logged output is sufficient.
@@ -167,6 +175,7 @@ public class Status extends ControlCommand {
if (!isWindows()) {
throw e;
}
+ return RHQControl.EXIT_CODE_STATUS_UNKNOWN;
}
}
}
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Stop.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Stop.java
index 9b51e28..a3920e0 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Stop.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Stop.java
@@ -33,6 +33,7 @@ import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.PumpStreamHandler;
+import org.rhq.server.control.RHQControl;
import org.rhq.server.control.RHQControlException;
/**
@@ -68,29 +69,33 @@ public class Stop extends AbstractInstall {
}
@Override
- protected void exec(CommandLine commandLine) {
+ protected int exec(CommandLine commandLine) {
+
+ int rValue = RHQControl.EXIT_CODE_OK;
+
try {
// if no options specified, then stop whatever is installed
if (commandLine.getOptions().length == 0) {
if (isAgentInstalled()) {
- stopAgent();
+ rValue = Math.max(rValue, stopAgent());
}
// the server service may be installed even if the full server install
fails. The files to execute
// the remove are there after the initial unzip, so just go ahead and try
to stop the service. This
// may help clean up a failed install.
- stopRHQServer();
+ rValue = Math.max(rValue, stopRHQServer());
if (isStorageInstalled()) {
- stopStorage();
+ rValue = Math.max(rValue, stopStorage());
}
} else {
if (commandLine.hasOption(AGENT_OPTION)) {
if (isAgentInstalled()) {
- stopAgent();
+ rValue = Math.max(rValue, stopAgent());
} else {
log.warn("It appears that the agent is not installed. The
--" + AGENT_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
}
@@ -98,24 +103,26 @@ public class Stop extends AbstractInstall {
// the server service may be installed even if the full server
install fails. The files to execute
// the remove are there after the initial unzip, so just go ahead and
try to stop the service. This
// may help clean up a failed install.
- stopRHQServer();
+ rValue = Math.max(rValue, stopRHQServer());
}
if (commandLine.hasOption(STORAGE_OPTION)) {
if (isStorageInstalled()) {
- stopStorage();
+ rValue = Math.max(rValue, stopStorage());
} else {
log.warn("It appears that the storage node is not installed.
The --" + STORAGE_OPTION
+ " option will be ignored.");
+ rValue = RHQControl.EXIT_CODE_INVALID_ARGUMENT;
}
}
}
} catch (Exception e) {
throw new RHQControlException("Failed to stop services", e);
}
+ return rValue;
}
- private void stopStorage() throws Exception {
+ private int stopStorage() throws Exception {
log.debug("Stopping RHQ storage node");
Executor executor = new DefaultExecutor();
@@ -123,17 +130,21 @@ public class Stop extends AbstractInstall {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine;
+ int rValue;
+
if (isWindows()) {
commandLine = getCommandLine("rhq-storage", "stop");
try {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
+ System.out.println("RHQ storage node has stopped");
} catch (Exception e) {
// Ignore, service may not exist or be running, script returns 1
log.debug("Failed to stop storage service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
- if (isStorageRunning()) {
+ if(isStorageRunning()) {
String pid = getStoragePid();
System.out.println("Stopping RHQ storage node...");
@@ -145,11 +156,13 @@ public class Stop extends AbstractInstall {
System.out.println("RHQ storage node has stopped");
}
+ rValue = RHQControl.EXIT_CODE_OK; // If process isn't running, stopping
it is considered OK.
}
+ return rValue;
}
- private void stopRHQServer() throws Exception {
+ private int stopRHQServer() throws Exception {
log.debug("Stopping RHQ server");
Executor executor = new DefaultExecutor();
@@ -157,23 +170,29 @@ public class Stop extends AbstractInstall {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-server", "stop");
+ int rValue;
+
if (isWindows()) {
try {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
// Ignore, service may not exist or be running, , script returns 1
log.debug("Failed to stop server service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
String pid = getServerPid();
if (pid != null) {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
+ } else {
+ rValue = RHQControl.EXIT_CODE_OK;
}
}
+ return rValue;
}
- private void stopAgent() throws Exception {
+ private int stopAgent() throws Exception {
log.debug("Stopping RHQ agent");
File agentBinDir = new File(getAgentBasedir(), "bin");
@@ -182,19 +201,25 @@ public class Stop extends AbstractInstall {
executor.setStreamHandler(new PumpStreamHandler());
org.apache.commons.exec.CommandLine commandLine =
getCommandLine("rhq-agent-wrapper", "stop");
+ int rValue;
+
if (isWindows()) {
try {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
} catch (Exception e) {
// Ignore, service may not exist or be running, , script returns 1
log.debug("Failed to stop agent service", e);
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
} else {
String pid = getAgentPid();
if (pid != null) {
- executor.execute(commandLine);
+ rValue = executor.execute(commandLine);
+ } else {
+ rValue = RHQControl.EXIT_CODE_OK;
}
}
+ return rValue;
}
}
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
index 5a762cd..cc3d8c2 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/command/Upgrade.java
@@ -48,6 +48,7 @@ import org.rhq.core.util.file.FileUtil;
import org.rhq.core.util.file.FileVisitor;
import org.rhq.core.util.stream.StreamUtil;
import org.rhq.server.control.ControlCommand;
+import org.rhq.server.control.RHQControl;
import org.rhq.server.control.RHQControlException;
/**
@@ -125,7 +126,8 @@ public class Upgrade extends AbstractInstall {
}
@Override
- protected void exec(CommandLine commandLine) {
+ protected int exec(CommandLine commandLine) {
+ int rValue = RHQControl.EXIT_CODE_OK;
boolean start = commandLine.hasOption(START_OPTION);
try {
@@ -135,9 +137,13 @@ public class Upgrade extends AbstractInstall {
log.error(error);
}
log.error("Exiting due to the previous errors");
- return;
+ return RHQControl.EXIT_CODE_OPERATION_FAILED;
}
+ // Attempt to shutdown any running components. A failure to shutdown a
component is not a failure as it
+ // really shouldn't be running anyway. This is just an attempt to avoid
upgrade problems.
+ log.info("Stopping any running RHQ components...");
+
// If using non-default agent location then save it so it will be applied to
all subsequent rhqctl commands.
boolean hasFromAgentOption = commandLine.hasOption(FROM_AGENT_DIR_OPTION);
if (hasFromAgentOption) {
@@ -149,7 +155,7 @@ public class Upgrade extends AbstractInstall {
// if the agent already exists in the default location, it may be there from
a prior install.
if (isStorageInstalled() || isServerInstalled()) {
log.warn("RHQ is already installed so upgrade can not be
performed.");
- return;
+ return RHQControl.EXIT_CODE_OPERATION_FAILED;
}
// Attempt to shutdown any running components. A failure to shutdown a
component is not a failure as it
@@ -158,7 +164,7 @@ public class Upgrade extends AbstractInstall {
// Stop the agent, if running.
if (hasFromAgentOption) {
- killAgent(getFromAgentDir(commandLine)); // this validates the path as
well
+ rValue = Math.max(rValue, killAgent(getFromAgentDir(commandLine))); //
this validates the path as well
}
// If rhqctl exists in the old version, use it to stop old components,
otherwise, just try and stop the
@@ -177,10 +183,10 @@ public class Upgrade extends AbstractInstall {
} else {
log.error("The old installation components failed to be stopped.
Please stop them manually before continuing. exit code="
+ exitValue);
- return;
+ return exitValue;
}
- // If any failures occur during upgrade, we know we need to reset
rhq-server.properties.
+ // If any failures occur during upgrade, we know we need to reset
rhq-server.properties.
final FileReverter serverPropFileReverter = new
FileReverter(getServerPropertiesFile());
addUndoTask(new ControlCommand.UndoTask("Reverting server properties
file") {
public void performUndoWork() throws Exception {
@@ -193,9 +199,9 @@ public class Upgrade extends AbstractInstall {
});
// now upgrade everything
- upgradeStorage(commandLine);
- upgradeServer(commandLine);
- upgradeAgent(commandLine);
+ rValue = Math.max(rValue, upgradeStorage(commandLine));
+ rValue = Math.max(rValue, upgradeServer(commandLine));
+ rValue = Math.max(rValue, upgradeAgent(commandLine));
File agentDir;
@@ -208,7 +214,7 @@ public class Upgrade extends AbstractInstall {
updateWindowsAgentService(agentDir);
if (start) {
- startAgent(agentDir);
+ rValue = Math.max(rValue, startAgent(agentDir));
}
} catch (Exception e) {
throw new RHQControlException("An error occurred while executing the
upgrade command", e);
@@ -218,30 +224,33 @@ public class Upgrade extends AbstractInstall {
Stop stopCommand = new Stop();
stopCommand.exec(new String[] { "stop",
"--server" });
if (!commandLine.hasOption(RUN_DATA_MIGRATION)) {
- stopCommand.exec(new String[] { "stop",
"--storage" });
+ rValue = Math.max(rValue, stopCommand.exec(new String[] {
"stop", "--storage" }));
}
}
} catch (Throwable t) {
log.warn("Unable to stop services: " + t.getMessage());
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
}
if (!isRhq48OrLater(commandLine) &&
commandLine.hasOption(RUN_DATA_MIGRATION)) {
- runDataMigration(commandLine);
+ rValue = Math.max(rValue, runDataMigration(commandLine));
}
-
+ return rValue;
}
- private void runDataMigration(CommandLine rhqctlCommandLine) {
+ private int runDataMigration(CommandLine rhqctlCommandLine) {
String migrationOption = rhqctlCommandLine.getOptionValue(RUN_DATA_MIGRATION);
+ int rValue;
+
if (migrationOption.equals("none")) {
log.info("No data migration will run");
if (!isRhq48OrLater(rhqctlCommandLine)) {
printDataMigrationNotice();
}
- return;
+ return RHQControl.EXIT_CODE_OK;
}
// We deduct the database parameters from the server properties
@@ -253,23 +262,28 @@ public class Upgrade extends AbstractInstall {
}
Executor executor = new DefaultExecutor();
- executor.setWorkingDirectory(new File(getBaseDir(), "bin")); //
data migrator script is not in bin/internal
+ executor.setWorkingDirectory(getBinDir());
executor.setStreamHandler(new PumpStreamHandler());
int exitValue = executor.execute(commandLine);
log.info("The data migrator finished with exit value " +
exitValue);
+ rValue = exitValue;
} catch (Exception e) {
log.error("Running the data migrator failed - please try to run it from
the command line: "
+ e.getMessage());
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
+ return rValue;
}
- private void upgradeStorage(CommandLine rhqctlCommandLine) throws Exception {
+ private int upgradeStorage(CommandLine rhqctlCommandLine) throws Exception {
if (rhqctlCommandLine.hasOption(USE_REMOTE_STORAGE_NODE)) {
log.info("Ignoring storage node upgrade, a remote storage node is
configured.");
- return;
+ return RHQControl.EXIT_CODE_OK;
}
+ int rValue;
+
// If upgrading from a pre-cassandra then just install an initial storage node.
Otherwise, upgrade
if (isRhq48OrLater(rhqctlCommandLine)) {
try {
@@ -293,28 +307,30 @@ public class Upgrade extends AbstractInstall {
int exitCode = executor.execute(commandLine);
log.info("The storage node upgrade has finished with an exit value
of " + exitCode);
-
+ rValue = exitCode;
} catch (IOException e) {
log.error("An error occurred while running the storage node upgrade:
" + e.getMessage());
throw e;
}
} else {
- installStorageNode(getStorageBasedir(), rhqctlCommandLine, true);
+ rValue = installStorageNode(getStorageBasedir(), rhqctlCommandLine, true);
}
+ return rValue;
}
- private void upgradeServer(CommandLine commandLine) throws Exception {
+ private int upgradeServer(CommandLine commandLine) throws Exception {
// don't upgrade the server if this is a storage node only install
File oldServerDir = getFromServerDir(commandLine);
if (!(!isRhq48OrLater(commandLine) || isServerInstalled(oldServerDir))) {
log.info("Ignoring server upgrade, this is a storage node only
installation.");
- return;
+ return RHQControl.EXIT_CODE_OK;
}
// copy all the old settings into the new rhq-server.properties file
upgradeServerPropertiesFile(commandLine);
+ int rValue = RHQControl.EXIT_CODE_OK;
// make sure we retain the oracle driver if one exists
try {
copyOracleDriver(oldServerDir);
@@ -323,6 +339,7 @@ public class Upgrade extends AbstractInstall {
+ "The upgrade will continue but your server may not work if
connecting to an Oracle database, "
+ "in which case you will need to manually install an Oracle driver
to your server. " + "Cause: "
+ ThrowableUtil.getAllMessages(e));
+ rValue = RHQControl.EXIT_CODE_OPERATION_FAILED;
}
// copy over any wrapper.inc that may have been added
@@ -334,10 +351,10 @@ public class Upgrade extends AbstractInstall {
// start the server, the invoke the installer and wait for the server to be
completely installed
startRHQServerForInstallation();
- runRHQServerInstaller();
+ rValue = Math.max(rValue, runRHQServerInstaller());
waitForRHQServerToInitialize();
- return;
+ return rValue;
}
public void copyOracleDriver(File oldServerDir) throws IOException {
@@ -529,7 +546,7 @@ public class Upgrade extends AbstractInstall {
}
// now merge the old settings in with the default properties from the new server
install
- String newServerPropsFilePath = new File(getBaseDir(),
"bin/rhq-server.properties").getAbsolutePath();
+ String newServerPropsFilePath = new File(getBinDir(),
"rhq-server.properties").getAbsolutePath();
PropertiesFileUpdate newServerPropsFile = new
PropertiesFileUpdate(newServerPropsFilePath);
newServerPropsFile.update(oldServerProps);
@@ -606,7 +623,7 @@ public class Upgrade extends AbstractInstall {
return (null != path) ? path.replace('\\', '/') : null;
}
- private void upgradeAgent(CommandLine rhqctlCommandLine) throws Exception {
+ private int upgradeAgent(CommandLine rhqctlCommandLine) throws Exception {
try {
File oldAgentDir;
if (rhqctlCommandLine.hasOption(FROM_AGENT_DIR_OPTION)) {
@@ -628,8 +645,7 @@ public class Upgrade extends AbstractInstall {
+ " option specified and no agent found in the default
location ["
+ oldAgentDir.getAbsolutePath()
+ "]. Installing agent in the default location as part of
the upgrade.");
- installAgent(getAgentBasedir(), rhqctlCommandLine);
- return;
+ return installAgent(getAgentBasedir(), rhqctlCommandLine);
}
}
@@ -687,6 +703,7 @@ public class Upgrade extends AbstractInstall {
});
log.info("The agent has been upgraded and placed in: " +
agentBasedir);
+ return exitValue;
} catch (IOException e) {
log.error("An error occurred while upgrading the agent: " +
e.getMessage());
commit a90246c660b740055b9671b83a55681fcfb9a9bb
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Thu Jan 2 16:59:20 2014 +0100
Add BoneCP to Eclipse classpath file
diff --git a/.classpath b/.classpath
index f8048fc..f371634 100644
--- a/.classpath
+++ b/.classpath
@@ -399,5 +399,6 @@
<classpathentry kind="var"
path="M2_REPO/com/fasterxml/jackson/core/jackson-core/2.1.1/jackson-core-2.1.1.jar"/>
<classpathentry kind="var"
path="M2_REPO/com/codahale/metrics/metrics-core/3.0.1/metrics-core-3.0.1.jar"/>
<classpathentry kind="var"
path="M2_REPO/com/datastax/cassandra/cassandra-driver-core/1.0.2/cassandra-driver-core-1.0.2.jar"/>
+ <classpathentry kind="var"
path="M2_REPO/com/jolbox/bonecp/0.8.0.RELEASE/bonecp-0.8.0.RELEASE.jar"/>
<classpathentry kind="output" path="eclipse-classes"/>
</classpath>
commit 4bd71559e3c124828f66725fb002ca6a2c1b0b9a
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Tue Dec 17 21:35:47 2013 +0100
Bug 968361 - Improve database plugin design to support connection pooling
This changeset introduces a new API for database plugins and deprecates the previous
one. Compatibility with the previous API will be maintained until next major version of
RHQ.
The 'rhq-database-plugin' was based on
org.rhq.plugins.database.DatabaseComponent interface which encouraged plugin authors to
share a single JDBC connection across database components. This was wrong for various
reasons (connection leaks, concurrent JDBC calls... etc).
The new API introduces three important classes:
* org.rhq.plugins.database.PooledConnectionProvider
* org.rhq.plugins.database.BasePooledConnectionProvider
* org.rhq.plugins.database.ConnectionPoolingSupport
BasePooledConnectionProvider is a base implementation of a PooledConnectionProvider.
Plugin authors should create a concrete implementation of BasePooledConnectionProvider
which overrides the #getDriverClass() method. This is important if a database plugin
embeds a JDBC driver: the database-specific driver class must be loaded by the child
plugin classloader.
ConnectionPoolingSupport helps to manage the compatibility with the old API. It's
a contract that all new database resource components should obey to. It declares the
following methods:
* #supportsConnectionPooling()
* #getPooledConnectionProvider()
Results of calls to #supportsConnectionPooling() #getPooledConnectionProvider() must
be consistent. In practice, a top level server database component should be able to create
a PooledConnectionProvider instance, and child servers and services should indicate they
support connection pooling only if their parent component does.
The 'rhq-database-plugin' embeds the BoneCP library (JDBC connection pooling)
and its dependencies (Google's Guava). Child plugins will have all the classes
accessible as soon as they have this node in their plugin descriptor:
===
<depends plugin="Database" useClasses="true"/>
===
This changeset includes the necessary changes to support connection pooling in the
Oracle, Postgres and MySQL plugins.
Thanks to Elias Ross for contributing the original patch from which this changeset is
derived.
diff --git a/modules/plugins/database/pom.xml b/modules/plugins/database/pom.xml
index 7ede2af..952e919 100644
--- a/modules/plugins/database/pom.xml
+++ b/modules/plugins/database/pom.xml
@@ -17,9 +17,33 @@
<properties>
<rhq.internal>false</rhq.internal>
+ <slf4j.version>1.7.2</slf4j.version>
</properties>
<dependencies>
+
+ <!-- Bone CP and its dependencies -->
+ <dependency>
+ <groupId>com.jolbox</groupId>
+ <artifactId>bonecp</artifactId>
+ <version>0.8.0.RELEASE</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>15.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>${slf4j.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>${slf4j.version}</version>
+ </dependency>
+ <!-- Test dependencies -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
@@ -28,7 +52,45 @@
</dependency>
</dependencies>
- <profiles>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-dependency-jars</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>com.jolbox</groupId>
+ <artifactId>bonecp</artifactId>
+ </artifactItem>
+ <artifactItem>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </artifactItem>
+ <artifactItem>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </artifactItem>
+ </artifactItems>
+
<outputDirectory>${project.build.outputDirectory}/lib</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
<profile>
<id>dev</id>
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/AbstractDatabaseComponent.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/AbstractDatabaseComponent.java
index 5976695..a0fdf07 100644
---
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/AbstractDatabaseComponent.java
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/AbstractDatabaseComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,31 +13,49 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.database;
+import static org.rhq.plugins.database.DatabasePluginUtil.hasConnectionPoolingSupport;
+
import java.sql.Connection;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
/**
- * Base class for database components.
+ * Base class for nested database components.
* @author Greg Hinkle
*/
-public abstract class AbstractDatabaseComponent<T extends
DatabaseComponent<?>> implements DatabaseComponent {
+public abstract class AbstractDatabaseComponent<T extends
DatabaseComponent<?>> implements DatabaseComponent,
+ ConnectionPoolingSupport {
+
+ private PooledConnectionProvider pooledConnectionProvider;
protected ResourceContext<T> resourceContext;
public void start(ResourceContext resourceContext) throws
InvalidPluginConfigurationException, Exception {
this.resourceContext = resourceContext;
+ if (hasConnectionPoolingSupport(resourceContext.getParentResourceComponent())) {
+ pooledConnectionProvider = ((ConnectionPoolingSupport)
resourceContext.getParentResourceComponent())
+ .getPooledConnectionProvider();
+ }
}
- /*public void start(ResourceContext<T> resourceContext) throws
InvalidPluginConfigurationException, Exception
- * { this.resourceContext = resourceContext;}*/
-
public void stop() {
+ pooledConnectionProvider = null;
+ }
+
+ @Override
+ public boolean supportsConnectionPooling() {
+ return pooledConnectionProvider != null;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return pooledConnectionProvider;
}
public Connection getConnection() {
@@ -52,4 +70,4 @@ public abstract class AbstractDatabaseComponent<T extends
DatabaseComponent<?>>
public String toString() {
return getClass().getName() + " key=" +
resourceContext.getResourceKey();
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/BasePooledConnectionProvider.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/BasePooledConnectionProvider.java
new file mode 100644
index 0000000..c9b3a59
--- /dev/null
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/BasePooledConnectionProvider.java
@@ -0,0 +1,226 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.plugins.database;
+
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.SQLException;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import javax.sql.DataSource;
+
+import com.jolbox.bonecp.BoneCP;
+import com.jolbox.bonecp.BoneCPConfig;
+import com.jolbox.bonecp.hooks.AbstractConnectionHook;
+import com.jolbox.bonecp.hooks.AcquireFailConfig;
+import com.jolbox.bonecp.hooks.ConnectionHook;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.core.domain.configuration.Configuration;
+
+/**
+ * Base implementation of a {@link PooledConnectionProvider}. Plugin authors
<em>should</em>:
+ * <ol>
+ * <li>create a concrete implementation which overrides the {@link
#getDriverClass()} method</li>
+ * <li>adopt the configuration properties described here or override the
corresponding #get method</li>
+ * </ol>
+ *
+ * The first point is important if a concrete database plugin embeds the JDBC driver: the
database-specific driver class
+ * <strong>must</strong> be loaded by the child plugin classloader.
+ *
+ * @author Elias Ross
+ */
+public abstract class BasePooledConnectionProvider implements PooledConnectionProvider {
+ private static final Log LOG =
LogFactory.getLog(BasePooledConnectionProvider.class);
+
+ /**
+ * Driver class key.
+ */
+ public static final String DRIVER_CLASS = "driverClass";
+
+ /**
+ * JDBC URL config key.
+ */
+ public static final String URL = "url";
+
+ /**
+ * JDBC username config key.
+ */
+ public static final String USERNAME = "username";
+
+ /**
+ * JDBC password config key.
+ */
+ public static final String PASSWORD = "password";
+
+ /**
+ * If true, track connections and statements.
+ */
+ public static final String TRACK = "track";
+
+ /**
+ * Connection timeout setting.
+ */
+ public static final String TIMEOUT = "connectionTimeout";
+
+ protected final Configuration pluginConfig;
+
+ /**
+ * Connection pool.
+ * The connection pool implementation details should not be exposed as
+ * the implementation may change.
+ */
+ private final BoneCP connectionPool;
+
+ protected BasePooledConnectionProvider(Configuration pluginConfig) throws Exception
{
+ this.pluginConfig = pluginConfig;
+ BoneCPConfig bconfig = new BoneCPConfig(getConnectionProperties());
+ Class<Driver> driverClass;
+ try {
+ driverClass = getDriverClass();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("Could not load driver class from: " +
Thread.currentThread().getContextClassLoader());
+ throw e;
+ }
+ if (driverClass != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Using driver class " + driverClass);
+ }
+ Driver driver = driverClass.newInstance();
+ DataSource datasourceBean = new DriverDataSource(driver, getJdbcUrl(),
getConnectionProperties());
+ bconfig.setDatasourceBean(datasourceBean);
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Using driver manager for " + getJdbcUrl());
+ }
+ bconfig.setJdbcUrl(getJdbcUrl());
+ }
+ bconfig.setAcquireIncrement(1);
+ bconfig.setAcquireRetryAttempts(0);
+ bconfig.setAcquireRetryDelayInMs(0);
+ bconfig.setPartitionCount(2);
+ bconfig.setMaxConnectionsPerPartition(5);
+ bconfig.setPassword(getPassword());
+ bconfig.setUsername(getUsername());
+ bconfig.setConnectionTimeoutInMs(getConnectionTimeout());
+ if (isTrack()) {
+ bconfig.setCloseConnectionWatch(true);
+ bconfig.setCloseConnectionWatchTimeout(10, TimeUnit.MINUTES);
+ }
+ bconfig.setLazyInit(false);
+ bconfig.setDisableJMX(true);
+ // Do not manage retry
+ ConnectionHook hook = new AbstractConnectionHook() {
+ public boolean onAcquireFail(Throwable t, AcquireFailConfig acquireConfig) {
+ LOG.error("Failed to obtain connection", t);
+ return false;
+ }
+ };
+ bconfig.setConnectionHook(hook);
+ connectionPool = new BoneCP(bconfig);
+ }
+
+ private boolean isTrack() {
+ return Boolean.valueOf(pluginConfig.getSimpleValue(TRACK, null));
+ }
+
+ @Override
+ public Connection getPooledConnection() throws SQLException {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("get connection for " + getJdbcUrl() + " free "
+ connectionPool.getTotalFree() + "/"
+ + connectionPool.getTotalCreatedConnections());
+ }
+ return connectionPool.getConnection();
+ }
+
+ /**
+ * Return additional database connection pool properties.
+ * By default, returns an empty properties object.
+ */
+ protected Properties getConnectionProperties() {
+ return new Properties();
+ }
+
+ /**
+ * Returns the driver class, by default the name from {@link #getDriverClassName()}.
+ * If not configured, this assumes the plugin will load the appropriate driver.
+ * @throws ClassNotFoundException if the classloader could not load this class
+ */
+ protected Class<Driver> getDriverClass() throws ClassNotFoundException {
+ String cname = getDriverClassName();
+ if (cname != null) {
+ return (Class<Driver>)
Thread.currentThread().getContextClassLoader().loadClass(cname);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the driver class, by default configuration item {@link #DRIVER_CLASS}.
+ */
+ protected String getDriverClassName() throws ClassNotFoundException {
+ return pluginConfig.getSimpleValue(DRIVER_CLASS, null);
+ }
+
+ /**
+ * Implemented by subclasses to return the JDBC connection URL.
+ * By default, returns the configuration item {@link #URL}.
+ */
+ protected String getJdbcUrl() {
+ return pluginConfig.getSimpleValue(URL);
+ }
+
+ /**
+ * Return the JDBC username.
+ * By default, returns the configuration item {@link #USERNAME}.
+ */
+ protected String getUsername() {
+ return pluginConfig.getSimpleValue(USERNAME);
+ }
+
+ /**
+ * Return the JDBC password.
+ * By default, returns the configuration item {@link #PASSWORD}.
+ */
+ protected String getPassword() {
+ return pluginConfig.getSimpleValue(PASSWORD);
+ }
+
+ /**
+ * Return the connection timeout setting, in milliseconds.
+ * By default, returns the configuration item {@link #TIMEOUT}.
+ */
+ protected long getConnectionTimeout() {
+ String s = pluginConfig.getSimpleValue(TIMEOUT);
+ if (s == null) {
+ return 1000 * 10;
+ }
+ return Long.parseLong(s);
+ }
+
+ /**
+ * Shutdown the connection pool.
+ */
+ public void close() {
+ connectionPool.shutdown();
+ }
+}
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/ConnectionPoolingSupport.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/ConnectionPoolingSupport.java
new file mode 100644
index 0000000..a899e44
--- /dev/null
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/ConnectionPoolingSupport.java
@@ -0,0 +1,52 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.plugins.database;
+
+/**
+ * <p>
+ * A contract that all database related resource components should obey to.
+ * </p>
+ * <p>
+ * Results of calls to {@link #supportsConnectionPooling()} and {@link
#getPooledConnectionProvider()}
+ * <strong>MUST</strong> be consistent.
+ * </p>
+ * <p>
+ * In practice, a top level server database component should be able to create a {@link
PooledConnectionProvider}
+ * instance, and child servers and services should indicate they support connection
pooling only if their parent
+ * component does.
+ * </p>
+ *
+ * @author Thomas Segismont
+ */
+public interface ConnectionPoolingSupport {
+
+ /**
+ * @return true if this component can give a reference to a {@link
PooledConnectionProvider}, false otherwise.
+ */
+ boolean supportsConnectionPooling();
+
+ /**
+ * @return a reference to a {@link PooledConnectionProvider} or null if this
component does not support connection
+ * pooling.
+ * @see #supportsConnectionPooling()
+ */
+ PooledConnectionProvider getPooledConnectionProvider();
+
+}
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java
index f2e8fa7..90f3f2f 100644
---
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,12 +13,19 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.database;
+import static org.rhq.plugins.database.DatabasePluginUtil.getConnectionFromComponent;
+import static org.rhq.plugins.database.DatabasePluginUtil.getNumericQueryValueMap;
+import static org.rhq.plugins.database.DatabasePluginUtil.getNumericQueryValues;
+import static org.rhq.plugins.database.DatabasePluginUtil.hasConnectionPoolingSupport;
+
import java.sql.Connection;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
@@ -36,24 +43,40 @@ import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
-import org.rhq.core.util.jdbc.JDBCUtil;
/**
* The component for the {@link CustomTableDiscoveryComponent}.
*
* @author Greg Hinkle
*/
-public class CustomTableComponent implements
DatabaseComponent<DatabaseComponent<?>>, MeasurementFacet {
- private ResourceContext<DatabaseComponent<?>> context;
+public class CustomTableComponent implements
DatabaseComponent<DatabaseComponent<?>>, ConnectionPoolingSupport,
+ MeasurementFacet {
+ private static final Log LOG = LogFactory.getLog(CustomTableComponent.class);
- private static final Log log = LogFactory.getLog(CustomTableComponent.class);
+ private ResourceContext<DatabaseComponent<?>> context;
+ private PooledConnectionProvider pooledConnectionProvider;
public void start(ResourceContext<DatabaseComponent<?>> resourceContext)
throws InvalidPluginConfigurationException, Exception {
this.context = resourceContext;
+ if (hasConnectionPoolingSupport(context.getParentResourceComponent())) {
+ pooledConnectionProvider = ((ConnectionPoolingSupport)
context.getParentResourceComponent())
+ .getPooledConnectionProvider();
+ }
}
public void stop() {
+ pooledConnectionProvider = null;
+ }
+
+ @Override
+ public boolean supportsConnectionPooling() {
+ return pooledConnectionProvider != null;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return pooledConnectionProvider;
}
public String getTable() {
@@ -66,16 +89,22 @@ public class CustomTableComponent implements
DatabaseComponent<DatabaseComponent
return AvailabilityType.UP;
}
Statement statement = null;
+ Connection connection = null;
+ ResultSet resultSet = null;
try {
- statement = getConnection().createStatement();
+ connection = getConnectionFromComponent(this);
+ statement = connection.createStatement();
statement.setMaxRows(1);
statement.setFetchSize(1);
- statement.executeQuery("SELECT * FROM " + getTable()).close();
+ resultSet = statement.executeQuery("SELECT * FROM " + getTable());
return AvailabilityType.UP;
} catch (SQLException e) {
return AvailabilityType.DOWN;
} finally {
- JDBCUtil.safeClose(statement);
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
+ if (supportsConnectionPooling()) {
+ DatabasePluginUtil.safeClose(connection, statement, resultSet);
+ }
}
}
@@ -85,10 +114,10 @@ public class CustomTableComponent implements
DatabaseComponent<DatabaseComponent
String query = config.getSimpleValue("metricQuery", null);
if (query == null) {
- if (log.isTraceEnabled()) {
+ if (LOG.isTraceEnabled()) {
ResourceType type = this.context.getResourceType();
String resourceKey = this.context.getResourceKey();
- log.trace("Resource "
+ LOG.trace("Resource "
+ resourceKey
+ " ("
+ type.getName()
@@ -104,13 +133,13 @@ public class CustomTableComponent implements
DatabaseComponent<DatabaseComponent
Map<String, Double> values;
if (Boolean.parseBoolean(column)) {
// data in column format
- values = DatabaseQueryUtility.getNumericQueryValues(this, query);
+ values = getNumericQueryValues(this, query);
} else {
// data in row format
- values = DatabaseQueryUtility.getNumericQueryValueMap(this, query);
+ values = getNumericQueryValueMap(this, query);
}
- if (log.isDebugEnabled())
- log.debug("returned values " + values);
+ if (LOG.isDebugEnabled())
+ LOG.debug("returned values " + values);
// this is a for loop because the name of each column can be the name of the
metric
for (MeasurementScheduleRequest request : metrics) {
@@ -129,7 +158,9 @@ public class CustomTableComponent implements
DatabaseComponent<DatabaseComponent
if (value != null) {
report.addData(new MeasurementDataNumeric(request, value));
} else {
- log.debug("Missing column in query results - metric not collected:
" + columnName);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Missing column in query results - metric not
collected: " + columnName);
+ }
}
}
}
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableDiscoveryComponent.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableDiscoveryComponent.java
index aeab429..b3aca8d 100644
---
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableDiscoveryComponent.java
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,12 +13,18 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.database;
+import static org.rhq.plugins.database.DatabasePluginUtil.canProvideConnection;
+import static org.rhq.plugins.database.DatabasePluginUtil.getConnectionFromComponent;
+import static org.rhq.plugins.database.DatabasePluginUtil.hasConnectionPoolingSupport;
+
import java.sql.Connection;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
@@ -26,14 +32,15 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ManualAddFacet;
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.util.jdbc.JDBCUtil;
/**
* Discovery for a generic component that can read data out of a table for
@@ -46,62 +53,85 @@ import org.rhq.core.util.jdbc.JDBCUtil;
*
* @author Greg Hinkle
*/
-public class CustomTableDiscoveryComponent implements
ManualAddFacet<DatabaseComponent<?>>,
- ResourceDiscoveryComponent<DatabaseComponent<?>> {
+public class CustomTableDiscoveryComponent implements
ManualAddFacet<ResourceComponent<?>>,
+ ResourceDiscoveryComponent<ResourceComponent<?>> {
protected Log log = LogFactory.getLog(getClass());
+ @Override
public Set<DiscoveredResourceDetails> discoverResources(
- ResourceDiscoveryContext<DatabaseComponent<?>>
resourceDiscoveryContext)
- throws InvalidPluginConfigurationException, Exception {
+ ResourceDiscoveryContext<ResourceComponent<?>> discoveryContext)
throws InvalidPluginConfigurationException,
+ Exception {
- Configuration config = resourceDiscoveryContext.getDefaultPluginConfiguration();
+ ResourceComponent<?> parentComponent =
discoveryContext.getParentResourceComponent();
+
+ Configuration config = discoveryContext.getDefaultPluginConfiguration();
String table = config.getSimpleValue("table", "");
- ResourceType rt = resourceDiscoveryContext.getResourceType();
- String resourceName = config.getSimpleValue("name", rt.getName());
- String resourceDescription = config.getSimpleValue("description",
rt.getDescription());
+ ResourceType resourceType = discoveryContext.getResourceType();
+ String resourceName = config.getSimpleValue("name",
resourceType.getName());
+ String resourceDescription = config.getSimpleValue("description",
resourceType.getDescription());
+
+ if (!canProvideConnection(parentComponent)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Parent component does not provide JDBC connections,
cannot discover" + resourceName);
+ }
+ return Collections.emptySet();
+ }
if (table.isEmpty()) {
- log.debug("'table' value not set, cannot discover " +
resourceName);
+ if (log.isDebugEnabled()) {
+ log.debug("'table' value not set, cannot discover " +
resourceName);
+ }
return Collections.emptySet();
}
Statement statement = null;
+ Connection connection = null;
+ ResultSet resultSet = null;
try {
- Connection conn =
resourceDiscoveryContext.getParentResourceComponent().getConnection();
- if (conn == null)
+ connection = getConnectionFromComponent(parentComponent);
+ if (connection == null) {
throw new InvalidPluginConfigurationException("cannot obtain
connection from parent");
-
- statement = conn.createStatement();
+ }
+ statement = connection.createStatement();
statement.setMaxRows(1);
statement.setFetchSize(1);
// This is more efficient than 'count(*)'
// unless the JDBC driver fails to support setMaxRows or doesn't stream
results
- statement.executeQuery("SELECT * FROM " + table).close();
- DiscoveredResourceDetails details = new DiscoveredResourceDetails(
- resourceDiscoveryContext.getResourceType(), table + resourceName,
resourceName, null,
- resourceDescription, config, null);
+ resultSet = statement.executeQuery("SELECT * FROM " + table);
- log.debug("discovered " + details);
+ DiscoveredResourceDetails details = new
DiscoveredResourceDetails(discoveryContext.getResourceType(), table
+ + resourceName, resourceName, null, resourceDescription, config, null);
+
+ if (log.isDebugEnabled()) {
+ log.debug("discovered " + details);
+ }
return Collections.singleton(details);
+
} catch (SQLException e) {
- log.debug("discovery failed " + e + " for " + table);
+ if (log.isDebugEnabled()) {
+ log.debug("discovery failed " + e + " for " +
table);
+ }
// table not found, don't inventory
} finally {
- JDBCUtil.safeClose(statement);
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
+ if (hasConnectionPoolingSupport(parentComponent)) {
+ DatabasePluginUtil.safeClose(connection, statement, resultSet);
+ }
}
return Collections.emptySet();
}
+ @Override
public DiscoveredResourceDetails discoverResource(Configuration pluginConfiguration,
- ResourceDiscoveryContext<DatabaseComponent<?>> discoveryContext)
throws InvalidPluginConfigurationException {
+ ResourceDiscoveryContext<ResourceComponent<?>> discoveryContext)
throws InvalidPluginConfigurationException {
Configuration config = pluginConfiguration;
String table = config.getSimpleValue("table", null);
String resourceName = config.getSimpleValue("name", table);
- String resourceDescription = config.getSimpleValue("description",
- discoveryContext.getResourceType().getDescription());
+ String resourceDescription = config.getSimpleValue("description",
discoveryContext.getResourceType()
+ .getDescription());
String resourceVersion = config.getSimpleValue("version", null);
DiscoveredResourceDetails details = new
DiscoveredResourceDetails(discoveryContext.getResourceType(), table
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java
index 50da33b..bde426a 100644
---
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,16 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.database;
+import static org.rhq.plugins.database.DatabasePluginUtil.canProvideConnection;
+import static org.rhq.plugins.database.DatabasePluginUtil.getConnectionFromComponent;
+import static org.rhq.plugins.database.DatabasePluginUtil.hasConnectionPoolingSupport;
+
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -29,13 +34,15 @@ import java.util.regex.Matcher;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.util.jdbc.JDBCUtil;
/**
* Discovery for a generic component that can read data out of a table for
@@ -47,57 +54,70 @@ import org.rhq.core.util.jdbc.JDBCUtil;
*
* @author Greg Hinkle
*/
-public class CustomTableRowDiscoveryComponent implements
ResourceDiscoveryComponent<DatabaseComponent<?>> {
-
- private final Log log = LogFactory.getLog(getClass());
+public class CustomTableRowDiscoveryComponent implements
ResourceDiscoveryComponent<ResourceComponent<?>> {
+ private static final Log LOG =
LogFactory.getLog(CustomTableRowDiscoveryComponent.class);
+ @Override
public Set<DiscoveredResourceDetails> discoverResources(
- ResourceDiscoveryContext<DatabaseComponent<?>>
resourceDiscoveryContext)
- throws InvalidPluginConfigurationException, Exception {
- Statement statement = null;
- ResultSet resultSet = null;
+ ResourceDiscoveryContext<ResourceComponent<?>> discoveryContext)
throws InvalidPluginConfigurationException,
+ Exception {
+
+ ResourceComponent<?> parentComponent =
discoveryContext.getParentResourceComponent();
- Configuration config = resourceDiscoveryContext.getDefaultPluginConfiguration();
+ Configuration config = discoveryContext.getDefaultPluginConfiguration();
String table = config.getSimpleValue("table", null);
String keyColumn = config.getSimpleValue("keyColumn", null);
- try {
- Connection conn =
resourceDiscoveryContext.getParentResourceComponent().getConnection();
+ ResourceType resourceType = discoveryContext.getResourceType();
+ String resourceName = config.getSimpleValue("name",
resourceType.getName());
+ String resourceDescription = config.getSimpleValue("description",
"");
- String resourceName = config.getSimpleValue("name", null);
- String resourceDescription = config.getSimpleValue("description",
"");
+ if (!canProvideConnection(parentComponent)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Parent component does not provide JDBC connections,
cannot discover" + resourceName);
+ }
+ return Collections.emptySet();
+ }
- if (resourceName == null) {
- throw new InvalidPluginConfigurationException("The 'name'
connection property has to be specified.");
+ if (resourceName == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("'name' property not set, cannot discover" +
resourceName);
}
+ return Collections.emptySet();
+ }
- statement = conn.createStatement();
+ Statement statement = null;
+ Connection connection = null;
+ ResultSet resultSet = null;
+ try {
+ connection = getConnectionFromComponent(parentComponent);
+ if (connection == null) {
+ throw new InvalidPluginConfigurationException("cannot obtain
connection from parent");
+ }
+ statement = connection.createStatement();
resultSet = statement.executeQuery("SELECT * FROM " + table);
Set<DiscoveredResourceDetails> found = new
HashSet<DiscoveredResourceDetails>();
while (resultSet.next()) {
- config = resourceDiscoveryContext.getDefaultPluginConfiguration();
+ config = discoveryContext.getDefaultPluginConfiguration();
String key = resultSet.getString(keyColumn);
config.put(new PropertySimple("key", key));
- DiscoveredResourceDetails details =
- new DiscoveredResourceDetails(
- resourceDiscoveryContext.getResourceType(),
- key,
- formatMessage(resourceName, key),
- null,
- formatMessage(resourceDescription,
- key), config, null);
+ DiscoveredResourceDetails details = new
DiscoveredResourceDetails(discoveryContext.getResourceType(),
+ key, formatMessage(resourceName, key), null,
formatMessage(resourceDescription, key), config, null);
found.add(details);
}
return found;
+
} catch (SQLException e) {
- log.debug("table " + table + " column " + keyColumn, e);
+ LOG.debug("table " + table + " column " + keyColumn, e);
} finally {
- JDBCUtil.safeClose(resultSet);
- JDBCUtil.safeClose(statement);
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
+ if (hasConnectionPoolingSupport(parentComponent)) {
+ DatabasePluginUtil.safeClose(connection, statement, resultSet);
+ }
}
- return Collections.emptySet();
+ return Collections.emptySet();
}
/**
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseComponent.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseComponent.java
index 5b8ad5f..3878c9d 100644
---
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseComponent.java
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.database;
import java.sql.Connection;
@@ -24,9 +25,14 @@ import org.rhq.core.pluginapi.inventory.ResourceComponent;
/**
* @author Greg Hinkle
+ * @deprecated as of RHQ 4.10. Use {@link ConnectionPoolingSupport} instead.
*/
+@Deprecated
public interface DatabaseComponent<T extends ResourceComponent<?>> extends
ResourceComponent<T> {
+
+ @Deprecated
Connection getConnection();
+ @Deprecated
void removeConnection();
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabasePluginLifecycleListener.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabasePluginLifecycleListener.java
index 38cd949..0a1fdb8 100644
---
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabasePluginLifecycleListener.java
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabasePluginLifecycleListener.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.database;
import java.sql.Driver;
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabasePluginUtil.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabasePluginUtil.java
new file mode 100644
index 0000000..f17c9b4
--- /dev/null
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabasePluginUtil.java
@@ -0,0 +1,379 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.plugins.database;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
+import org.rhq.core.util.exception.ThrowableUtil;
+
+/**
+ * @author Thomas Segismont
+ */
+public class DatabasePluginUtil {
+ private static final Log LOG = LogFactory.getLog(DatabasePluginUtil.class);
+
+ public static final class ComponentCannotProvideConnectionException extends
IllegalArgumentException {
+ private final ResourceComponent component;
+
+ public ComponentCannotProvideConnectionException(ResourceComponent component) {
+ super(component + " cannot provide a JDBC Connection");
+ this.component = component;
+ }
+
+ public ResourceComponent getComponent() {
+ return component;
+ }
+ }
+
+ /**
+ * @return false unless <code>component</code> is not null and supports
connection pooling or is an instance of
+ * {@link DatabaseComponent}.
+ */
+ public static boolean canProvideConnection(ResourceComponent component) {
+ return hasConnectionPoolingSupport(component) || component instanceof
DatabaseComponent;
+ }
+
+ /**
+ * Determines if a resource component supports connection pooling.
+ *
+ * @param component the resource component
+ * @return false unless <code>component</code> is not null, implements
+ * {@link org.rhq.plugins.database.ConnectionPoolingSupport} and a call to
+ * {@link ConnectionPoolingSupport#supportsConnectionPooling()} returns true.
+ */
+ public static boolean hasConnectionPoolingSupport(ResourceComponent component) {
+ if (component instanceof ConnectionPoolingSupport) {
+ return ((ConnectionPoolingSupport) component).supportsConnectionPooling();
+ }
+ return false;
+ }
+
+ /**
+ * Gets a {@link Connection} from the <code>component</code>.
+ *
+ * @param component a resource component that must be able to provide a {@link
Connection}.
+ * @throws SQLException if <code>component</code> supports connection
pooling and a pooled connection could not be
+ * retrieved.
+ * @throws IllegalArgumentException if resource component is null or cannot provide a
{@link Connection} (does not
+ * support connection pooling and does not implement {@link DatabaseComponent}).
+ */
+ public static Connection getConnectionFromComponent(ResourceComponent component)
throws SQLException {
+ if (hasConnectionPoolingSupport(component)) {
+ return getConnectionFromPool((ConnectionPoolingSupport) component);
+ }
+ if (component instanceof DatabaseComponent) {
+ return getConnectionFromDatabaseComponent((DatabaseComponent) component);
+ }
+ throw new ComponentCannotProvideConnectionException(component);
+ }
+
+ /**
+ * Executes a query, returning the results as a map where the keys are the column
names and values are the value of
+ * that column. Note that depending on the database, the column names may be
uppercase (Oracle) or lowercase.
+ *
+ * @param component
+ * @param query SQL query string
+ * @param parameters optional bind parameters
+ *
+ * @return a map of query results
+ */
+ public static Map<String, Double> getNumericQueryValues(ResourceComponent
component, String query,
+ Object... parameters) {
+
+ boolean componentHasConnectionPoolingSupport =
hasConnectionPoolingSupport(component);
+ checkComponent(component, componentHasConnectionPoolingSupport);
+
+ Connection connection = null;
+ PreparedStatement statement = null;
+ ResultSet resultSet = null;
+ try {
+ connection = getConnection0(component,
componentHasConnectionPoolingSupport);
+ statement = connection.prepareStatement(query);
+ bindParameters(statement, parameters);
+
+ resultSet = statement.executeQuery();
+
+ Map<String, Double> row = new HashMap<String, Double>();
+
+ ResultSetMetaData md = resultSet.getMetaData();
+ String[] names = getColumns(md);
+
+ if (resultSet.next()) {
+ for (String name : names) {
+ try {
+ row.put(name, resultSet.getDouble(name));
+ } catch (SQLException e) {
+ // Ignore columns that can't be read as doubles
+ }
+ }
+ }
+
+ return row;
+ } catch (SQLException e) {
+ LOG.debug("Unable to read value", e);
+ if (!componentHasConnectionPoolingSupport) {
+ ((DatabaseComponent) component).removeConnection();
+ }
+ } finally {
+ safeClose(null, statement, resultSet);
+ if (componentHasConnectionPoolingSupport) {
+ safeClose(connection);
+ }
+ }
+
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Returns a mapping of rows as key-value pairs where the key is the first column (a
string) and the second column
+ * is a value numeric.
+ *
+ * @param component the component to execute on
+ * @param query the sql query to run
+ * @param parameters any parameters to bind first
+ *
+ * @return a Map<String,Double> of the keys against the value
+ */
+ public static Map<String, Double> getNumericQueryValueMap(ResourceComponent
component, String query,
+ Object... parameters) {
+
+ boolean componentHasConnectionPoolingSupport =
hasConnectionPoolingSupport(component);
+ checkComponent(component, componentHasConnectionPoolingSupport);
+
+ Connection connection = null;
+ PreparedStatement statement = null;
+ ResultSet resultSet = null;
+ try {
+ connection = getConnection0(component,
componentHasConnectionPoolingSupport);
+ statement = connection.prepareStatement(query);
+ bindParameters(statement, parameters);
+
+ resultSet = statement.executeQuery();
+
+ Map<String, Double> map = new HashMap<String, Double>();
+
+ while (resultSet.next()) {
+ try {
+ map.put(resultSet.getString(1), resultSet.getDouble(2));
+ } catch (SQLException e) {
+ // Ignore columns that can't be read as doubles
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("A query column value is not a double,
ignoring:" + ThrowableUtil.getAllMessages(e));
+ }
+ }
+ }
+
+ return map;
+ } catch (SQLException e) {
+ LOG.info("Unable to read value", e);
+ if (!componentHasConnectionPoolingSupport) {
+ ((DatabaseComponent) component).removeConnection();
+ }
+ } finally {
+ safeClose(null, statement, resultSet);
+ if (componentHasConnectionPoolingSupport) {
+ safeClose(connection);
+ }
+ }
+
+ return Collections.emptyMap();
+ }
+
+ /**
+ * Returns the result of a query as a single Double value.
+ * Returns {@link Double#NaN} if the query fails.
+ */
+ public static Double getSingleNumericQueryValue(ResourceComponent component, String
query, Object... parameters) {
+
+ boolean componentHasConnectionPoolingSupport =
hasConnectionPoolingSupport(component);
+ checkComponent(component, componentHasConnectionPoolingSupport);
+
+ Connection connection = null;
+ PreparedStatement statement = null;
+ ResultSet resultSet = null;
+ try {
+ connection = getConnection0(component,
componentHasConnectionPoolingSupport);
+ statement = connection.prepareStatement(query);
+ bindParameters(statement, parameters);
+ resultSet = statement.executeQuery();
+
+ if (resultSet.next()) {
+ return resultSet.getDouble(1);
+ }
+ } catch (SQLException e) {
+ if (!componentHasConnectionPoolingSupport) {
+ ((DatabaseComponent) component).removeConnection();
+ }
+ } finally {
+ safeClose(null, statement, resultSet);
+ if (componentHasConnectionPoolingSupport) {
+ safeClose(connection);
+ }
+ }
+
+ return Double.NaN;
+ }
+
+ /**
+ * Returns a list of values, one per row, containing a map of column names to values
of that row.
+ * Note depending on the database, the column names may be uppercase (Oracle) or
lowercase.
+ * @param component database to query
+ * @param query SQL query
+ * @param parameters parameters to bind to the query
+ *
+ * @throws SQLException if query fails
+ */
+ public static List<Map<String, Object>> getGridValues(ResourceComponent
component, String query,
+ Object... parameters) throws SQLException {
+
+ boolean componentHasConnectionPoolingSupport =
hasConnectionPoolingSupport(component);
+ checkComponent(component, componentHasConnectionPoolingSupport);
+
+ Connection connection = null;
+ PreparedStatement statement = null;
+ ResultSet resultSet = null;
+ List<Map<String, Object>> l = new ArrayList<Map<String,
Object>>();
+ try {
+ connection = getConnection0(component,
componentHasConnectionPoolingSupport);
+ statement = connection.prepareStatement(query);
+ bindParameters(statement, parameters);
+
+ resultSet = statement.executeQuery();
+
+ while (resultSet.next()) {
+ Map<String, Object> row = new HashMap<String, Object>();
+ l.add(row);
+
+ ResultSetMetaData md = resultSet.getMetaData();
+ String[] names = getColumns(md);
+
+ for (String name : names) {
+ Object o = resultSet.getObject(name);
+ row.put(name, o);
+ }
+ }
+
+ } finally {
+ safeClose(null, statement, resultSet);
+ if (componentHasConnectionPoolingSupport) {
+ safeClose(connection);
+ }
+ }
+ return l;
+
+ }
+
+ public static void safeClose(Connection connection) {
+ if (connection != null) {
+ try {
+ connection.close();
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ public static void safeClose(Connection connection, Statement statement) {
+ safeClose(statement);
+ safeClose(connection);
+ }
+
+ public static void safeClose(Connection connection, Statement statement, ResultSet
resultSet) {
+ safeClose(resultSet);
+ safeClose(statement);
+ safeClose(connection);
+ }
+
+ public static void safeClose(Statement statement) {
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ public static void safeClose(ResultSet resultSet) {
+ if (resultSet != null) {
+ try {
+ resultSet.close();
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ private static void checkComponent(ResourceComponent component, boolean
componentHasConnectionPoolingSupport) {
+ if (!componentHasConnectionPoolingSupport && !(component instanceof
DatabaseComponent)) {
+ throw new ComponentCannotProvideConnectionException(component);
+ }
+ }
+
+ private static Connection getConnection0(ResourceComponent component, boolean
componentHasConnectionPoolingSupport)
+ throws SQLException {
+ return componentHasConnectionPoolingSupport ?
getConnectionFromPool((ConnectionPoolingSupport) component)
+ : getConnectionFromDatabaseComponent((DatabaseComponent) component);
+ }
+
+ private static Connection getConnectionFromPool(ConnectionPoolingSupport component)
throws SQLException {
+ return component.getPooledConnectionProvider().getPooledConnection();
+ }
+
+ private static Connection getConnectionFromDatabaseComponent(DatabaseComponent
component) {
+ return component.getConnection();
+ }
+
+ private static void bindParameters(PreparedStatement statement, Object... parameters)
throws SQLException {
+ int i = 1;
+ for (Object p : parameters) {
+ if (p instanceof String) {
+ statement.setString(i++, (String) p);
+ } else if (p instanceof Number) {
+ statement.setDouble(i++, ((Number) p).doubleValue());
+ } else {
+ statement.setObject(i++, p);
+ }
+ }
+ }
+
+ private static String[] getColumns(ResultSetMetaData rsmd) throws SQLException {
+ String[] names = new String[rsmd.getColumnCount()];
+ for (int i = 0; i < rsmd.getColumnCount(); i++) {
+ names[i] = rsmd.getColumnName(i + 1);
+ }
+ return names;
+ }
+
+ private DatabasePluginUtil() {
+ // Utility class
+ }
+}
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseQueryUtility.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseQueryUtility.java
index d6d83f2..70024c0 100644
---
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseQueryUtility.java
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DatabaseQueryUtility.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.database;
import java.sql.Connection;
@@ -39,7 +40,9 @@ import org.rhq.core.util.exception.ThrowableUtil;
* Various database (JDBC) query functions.
*
* @author Greg Hinkle
+ * @deprecated as of RHQ 4.10, use {@link DatabasePluginUtil} instead.
*/
+@Deprecated
public class DatabaseQueryUtility {
private static final Log LOG = LogFactory.getLog(DatabaseQueryUtility.class);
@@ -59,6 +62,7 @@ public class DatabaseQueryUtility {
* @return
* @throws SQLException
*/
+ @Deprecated
public static int executeUpdate(DatabaseComponent databaseComponent, String query,
Object... parameters)
throws SQLException {
PreparedStatement statement = null;
@@ -79,6 +83,7 @@ public class DatabaseQueryUtility {
* Returns the result of a query as a single Double value.
* Returns {@link Double#NaN} if the query fails.
*/
+ @Deprecated
public static Double getSingleNumericQueryValue(DatabaseComponent databaseComponent,
String query,
Object... parameters) {
PreparedStatement statement = null;
@@ -111,6 +116,7 @@ public class DatabaseQueryUtility {
*
* @return a map of query results
*/
+ @Deprecated
public static Map<String, Double> getNumericQueryValues(DatabaseComponent
databaseComponent, String query,
Object... parameters) {
PreparedStatement statement = null;
@@ -156,6 +162,7 @@ public class DatabaseQueryUtility {
*
* @throws SQLException if query fails
*/
+ @Deprecated
public static List<Map<String, Object>> getGridValues(DatabaseComponent
databaseComponent, String query,
Object... parameters) throws SQLException {
PreparedStatement statement = null;
@@ -197,6 +204,7 @@ public class DatabaseQueryUtility {
*
* @return a Map<String,Double> of the keys against the value
*/
+ @Deprecated
public static Map<String, Double> getNumericQueryValueMap(DatabaseComponent
databaseComponent, String query,
Object... parameters) {
PreparedStatement statement = null;
@@ -251,6 +259,7 @@ public class DatabaseQueryUtility {
/**
* Returns an array of strings as upper-case column names.
*/
+ @Deprecated
public static String[] getColumns(ResultSetMetaData rsmd) throws SQLException {
String[] names = new String[rsmd.getColumnCount()];
for (int i = 0; i < rsmd.getColumnCount(); i++) {
@@ -263,6 +272,7 @@ public class DatabaseQueryUtility {
/**
* Closes statements and result sets.
*/
+ @Deprecated
public static void close(Statement statement, ResultSet resultSet) {
if (resultSet != null) {
try {
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/DriverDataSource.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DriverDataSource.java
new file mode 100644
index 0000000..4fce379
--- /dev/null
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/DriverDataSource.java
@@ -0,0 +1,103 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.plugins.database;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+import javax.sql.DataSource;
+
+/**
+ * Works with BoneCP to provide connections, because DriverManager won't load the
class correctly through BoneCP
+ * (the actual driver class will be loaded by concrete database plugins).
+ */
+class DriverDataSource implements DataSource {
+
+ private final Properties properties;
+ private final Driver driver;
+ private final String url;
+ private PrintWriter out = new PrintWriter(System.out);
+
+ DriverDataSource(Driver driver, String url, Properties properties) {
+ this.driver = driver;
+ this.url = url;
+ if (properties == null) {
+ properties = new Properties();
+ }
+ this.properties = properties;
+ }
+
+ @Override
+ public PrintWriter getLogWriter() throws SQLException {
+ return out;
+ }
+
+ @Override
+ public void setLogWriter(PrintWriter out) throws SQLException {
+ this.out = out;
+ }
+
+ @Override
+ public void setLoginTimeout(int seconds) throws SQLException {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+ @Override
+ public int getLoginTimeout() throws SQLException {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+ return driver.connect(url, properties);
+ }
+
+ @Override
+ public Connection getConnection(String username, String password) throws SQLException
{
+ Properties p = new Properties(properties);
+ if (username != null) {
+ p.put("user", username);
+ }
+ if (password != null) {
+ p.put("password", password);
+ }
+ return driver.connect(url, p);
+ }
+
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+}
diff --git
a/modules/plugins/database/src/main/java/org/rhq/plugins/database/PooledConnectionProvider.java
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/PooledConnectionProvider.java
new file mode 100644
index 0000000..8089152
--- /dev/null
+++
b/modules/plugins/database/src/main/java/org/rhq/plugins/database/PooledConnectionProvider.java
@@ -0,0 +1,39 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.plugins.database;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+/**
+ * Contract for resource components providing pooled {@link Connection} objects.
+ *
+ * @author Thomas Segismont
+ */
+public interface PooledConnectionProvider {
+ /**
+ * Get a pooled connection. It's the responsibility of the caller to return the
connection to the pool by calling
+ * {@link java.sql.Connection#close()} on the returned {@link Connection} object.
+ *
+ * @return a pooled {@link Connection}
+ * @throws SQLException if a pooled connection could not be retrieved
+ */
+ Connection getPooledConnection() throws SQLException;
+}
diff --git
a/modules/plugins/database/src/test/java/org/rhq/plugins/database/ComponentTest.java
b/modules/plugins/database/src/test/java/org/rhq/plugins/database/ComponentTest.java
index 6caba36..8e869e4 100644
--- a/modules/plugins/database/src/test/java/org/rhq/plugins/database/ComponentTest.java
+++ b/modules/plugins/database/src/test/java/org/rhq/plugins/database/ComponentTest.java
@@ -1,3 +1,22 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
package org.rhq.plugins.database;
import static org.testng.AssertJUnit.assertEquals;
diff --git
a/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2Database.java
b/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2Database.java
index a81d998..2d388b6 100644
--- a/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2Database.java
+++ b/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2Database.java
@@ -1,66 +1,97 @@
package org.rhq.plugins.database;
+import static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
+import static org.rhq.core.domain.measurement.AvailabilityType.UP;
+
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceComponent;
import org.rhq.core.pluginapi.inventory.ResourceContext;
-import org.rhq.core.util.jdbc.JDBCUtil;
/**
* Tests using the H2Database.
*/
-public class H2Database implements DatabaseComponent<ResourceComponent<?>> {
+public class H2Database implements DatabaseComponent<ResourceComponent<?>>,
ConnectionPoolingSupport {
+ private static final Log LOG = LogFactory.getLog(H2Database.class);
+
+ static final String DRIVER_CLASS_PROPERTY = "driverClass";
+ static final String URL_PROPERTY = "url";
+ static final String USERNAME_PROPERTY = "username";
+ static final String PASSWORD_PROPERTY = "password";
- private Log log = LogFactory.getLog(this.getClass());
protected ResourceContext resourceContext;
+ @Deprecated
private Connection connection;
- private Configuration configuration;
+ private H2PooledConnectionProvider pooledConnectionProvider;
public void start(ResourceContext resourceContext) throws
InvalidPluginConfigurationException, Exception {
this.resourceContext = resourceContext;
- this.configuration = resourceContext.getPluginConfiguration();
+ buildSharedConnectionIfNeeded();
+ pooledConnectionProvider = new
H2PooledConnectionProvider(resourceContext.getPluginConfiguration());
}
public void stop() {
- removeConnection();
+ resourceContext = null;
+ DatabasePluginUtil.safeClose(connection);
+ connection = null;
+ pooledConnectionProvider.close();
+ pooledConnectionProvider = null;
+ }
+
+ @Override
+ public boolean supportsConnectionPooling() {
+ return true;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return pooledConnectionProvider;
}
public AvailabilityType getAvailability() {
- Connection conn = getConnection();
- AvailabilityType result = AvailabilityType.DOWN;
- if (conn != null) {
- result = AvailabilityType.UP;
+ Connection jdbcConnection = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ return jdbcConnection.isValid(1) ? UP : DOWN;
+ } catch (SQLException e) {
+ return DOWN;
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection);
}
- return result;
-
}
public Connection getConnection() {
+ buildSharedConnectionIfNeeded();
+ return connection;
+ }
+
+ private void buildSharedConnectionIfNeeded() {
try {
- if (this.connection == null || connection.isClosed()) {
- this.connection = buildConnection();
+ if ((connection == null) || connection.isClosed()) {
+ connection = buildConnection(resourceContext.getPluginConfiguration());
}
} catch (SQLException e) {
- log.info("Unable to create connection", e);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Could not build shared connection", e);
+ }
}
- return this.connection;
}
- @Override
public void removeConnection() {
- JDBCUtil.safeClose(connection);
+ DatabasePluginUtil.safeClose(this.connection);
this.connection = null;
}
- private Connection buildConnection() throws SQLException {
- String driverClass = configuration.getSimpleValue("driverClass",
"org.h2.Driver");
+ static Connection buildConnection(Configuration pluginConfig) throws SQLException {
+ String driverClass = pluginConfig.getSimpleValue(DRIVER_CLASS_PROPERTY,
"org.h2.Driver");
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
@@ -68,12 +99,13 @@ public class H2Database implements
DatabaseComponent<ResourceComponent<?>> {
+ ") not found.");
}
- String url = configuration.getSimpleValue("url",
"jdbc:h2:test");
- String username = configuration.getSimpleValue("username",
"sa");
- String password = configuration.getSimpleValue("password",
"");
- log.debug("Attempting JDBC connection to [" + url + "]");
+ String url = pluginConfig.getSimpleValue(URL_PROPERTY,
"jdbc:h2:test");
+ String username = pluginConfig.getSimpleValue(USERNAME_PROPERTY,
"sa");
+ String password = pluginConfig.getSimpleValue(PASSWORD_PROPERTY, "");
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Attempting JDBC connection to [" + url +
"]");
+ }
return DriverManager.getConnection(url, username, password);
}
-
}
diff --git
a/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2DatabaseDiscovery.java
b/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2DatabaseDiscovery.java
index dbce116..97e9d41 100644
---
a/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2DatabaseDiscovery.java
+++
b/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2DatabaseDiscovery.java
@@ -1,9 +1,29 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
package org.rhq.plugins.database;
import java.util.Collections;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
diff --git
a/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2PooledConnectionProvider.java
b/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2PooledConnectionProvider.java
new file mode 100644
index 0000000..9d414c3
--- /dev/null
+++
b/modules/plugins/database/src/test/java/org/rhq/plugins/database/H2PooledConnectionProvider.java
@@ -0,0 +1,59 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.plugins.database;
+
+import static org.rhq.plugins.database.H2Database.DRIVER_CLASS_PROPERTY;
+import static org.rhq.plugins.database.H2Database.PASSWORD_PROPERTY;
+import static org.rhq.plugins.database.H2Database.URL_PROPERTY;
+import static org.rhq.plugins.database.H2Database.USERNAME_PROPERTY;
+
+import java.sql.Driver;
+
+import org.rhq.core.domain.configuration.Configuration;
+
+/**
+ * @author Thomas Segismont
+ */
+class H2PooledConnectionProvider extends BasePooledConnectionProvider {
+
+ public H2PooledConnectionProvider(Configuration pluginConfig) throws Exception {
+ super(pluginConfig);
+ }
+
+ @Override
+ protected Class<Driver> getDriverClass() throws ClassNotFoundException {
+ return (Class<Driver>)
Class.forName(pluginConfig.getSimpleValue(DRIVER_CLASS_PROPERTY,
"org.h2.Driver"));
+ }
+
+ @Override
+ protected String getJdbcUrl() {
+ return pluginConfig.getSimpleValue(URL_PROPERTY, "jdbc:h2:test");
+ }
+
+ @Override
+ protected String getUsername() {
+ return pluginConfig.getSimple(USERNAME_PROPERTY).getStringValue();
+ }
+
+ @Override
+ protected String getPassword() {
+ return pluginConfig.getSimple(PASSWORD_PROPERTY).getStringValue();
+ }
+}
diff --git
a/modules/plugins/database/src/test/java/org/rhq/plugins/database/NonPoolingCustomTableComponent.java
b/modules/plugins/database/src/test/java/org/rhq/plugins/database/NonPoolingCustomTableComponent.java
new file mode 100644
index 0000000..496e654
--- /dev/null
+++
b/modules/plugins/database/src/test/java/org/rhq/plugins/database/NonPoolingCustomTableComponent.java
@@ -0,0 +1,17 @@
+package org.rhq.plugins.database;
+
+/**
+ * @author Thomas Segismont
+ */
+public class NonPoolingCustomTableComponent extends CustomTableComponent {
+
+ @Override
+ public boolean supportsConnectionPooling() {
+ return false;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return null;
+ }
+}
diff --git
a/modules/plugins/database/src/test/java/org/rhq/plugins/database/PluginTest.java
b/modules/plugins/database/src/test/java/org/rhq/plugins/database/PluginTest.java
index 4ce8107..45bac41 100644
--- a/modules/plugins/database/src/test/java/org/rhq/plugins/database/PluginTest.java
+++ b/modules/plugins/database/src/test/java/org/rhq/plugins/database/PluginTest.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,40 +13,94 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.plugins.database;
+import static org.rhq.plugins.database.DatabasePluginUtil.getGridValues;
+import static org.testng.Assert.assertEquals;
+
import java.sql.Connection;
+import java.sql.SQLException;
import java.util.List;
import java.util.Map;
+import org.testng.annotations.Test;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.measurement.MeasurementReport;
import org.rhq.core.domain.resource.ResourceType;
-import org.testng.annotations.Test;
-import org.testng.AssertJUnit;
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
@Test
public class PluginTest extends ComponentTest {
public void test() throws Exception {
- H2Database db = (H2Database)manuallyAdd("H2 Database");
+
+ H2Database db = (H2Database) manuallyAdd("H2 Database");
assertUp(db);
- Connection connection = db.getConnection();
- connection.prepareStatement("create table sometable(a int, b
int)").execute();
- connection.prepareStatement("insert into sometable values(42,
54)").execute();
- ResourceType rt = resourceTypes.get("Generic Query");
+
+ setupData(db);
+
+ // Pooling < Non Pooling < Pooling hierarchy
+
+ ResourceComponent level1 = add("Generic Query", db);
+ assertUp(level1);
+ checkAllMetrics("Generic Query", level1);
+
+ ResourceComponent level2 = add("Generic Query Non Pooling", level1);
+ assertUp(level2);
+ checkAllMetrics("Generic Query Non Pooling", level2);
+
+ ResourceComponent level3 = add("Nested Generic Query", level2);
+ assertUp(level3);
+ checkAllMetrics("Generic Query Non Pooling", level3);
+
+ checkData(db);
+ }
+
+ private ResourceComponent add(String resourceType, ResourceComponent component)
throws Exception {
+ ResourceType rt = resourceTypes.get(resourceType);
Configuration configuration = getConfiguration(rt);
- CustomTableComponent ctc = (CustomTableComponent) manuallyAdd(rt, configuration,
db);
- MeasurementReport report = getMeasurementReport(ctc);
- assertAll(report, getResourceDescriptor("Generic Query"));
- List<Map<String, Object>> grid =
DatabaseQueryUtility.getGridValues(db, "select a, b from sometable");
- assert grid.size() == 1;
- Map<String, Object> map = grid.get(0);
- AssertJUnit.assertEquals(42, map.get("A"));
+ return manuallyAdd(rt, configuration, component);
+ }
+
+ private void checkAllMetrics(String resourceType, ResourceComponent component) throws
Exception {
+ MeasurementReport report = getMeasurementReport(component);
+ assertAll(report, getResourceDescriptor(resourceType));
+ }
+
+ private void setupData(H2Database db) throws SQLException {
+ Connection connection = null;
+ try {
+ connection = db.getPooledConnectionProvider().getPooledConnection();
+ connection.prepareStatement("create table table_a(a int, b
int)").execute();
+ connection.prepareStatement("insert into table_a values(1,
2)").execute();
+ connection.prepareStatement("create table table_b(a int, b
int)").execute();
+ connection.prepareStatement("insert into table_b values(3,
4)").execute();
+ connection.prepareStatement("create table table_c(a int, b
int)").execute();
+ connection.prepareStatement("insert into table_c values(5,
6)").execute();
+ } finally {
+ DatabasePluginUtil.safeClose(connection);
+ }
+ }
+
+ private void checkData(H2Database db) throws SQLException {
+ List<Map<String, Object>> grid = getGridValues(db, "select a, b
from table_a");
+ assertEquals(grid.size(), 1);
+ assertEquals(grid.get(0).get("A"), 1);
+ assertEquals(grid.get(0).get("B"), 2);
+ grid = getGridValues(db, "select a, b from table_b");
+ assertEquals(grid.size(), 1);
+ assertEquals(grid.get(0).get("A"), 3);
+ assertEquals(grid.get(0).get("B"), 4);
+ grid = getGridValues(db, "select a, b from table_c");
+ assertEquals(grid.size(), 1);
+ assertEquals(grid.get(0).get("A"), 5);
+ assertEquals(grid.get(0).get("B"), 6);
+ System.out.println("grid = " + grid);
}
}
diff --git a/modules/plugins/database/src/test/resources/META-INF/rhq-plugin.xml
b/modules/plugins/database/src/test/resources/META-INF/rhq-plugin.xml
index 1e8f7d1..79f6413 100644
--- a/modules/plugins/database/src/test/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/database/src/test/resources/META-INF/rhq-plugin.xml
@@ -5,43 +5,89 @@
description="Plugin supporting H2 database"
package="org.rhq.plugins.database"
pluginLifecycleListener="DatabasePluginLifecycleListener"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="urn:xmlns:rhq-configuration"
xmlns="urn:xmlns:rhq-plugin">
- <depends plugin="Database" useClasses="true"/>
+ <depends plugin="Database" useClasses="true"/>
- <server name="H2 Database"
class="org.rhq.plugins.database.H2Database"
discovery="org.rhq.plugins.database.H2DatabaseDiscovery">
- <plugin-configuration>
- <c:simple-property name="url" type="string"
default="jdbc:h2:mem:"/>
- <c:simple-property name="username" type="string"
default="sa"/>
- <c:simple-property name="password" type="string"
default=""/>
- </plugin-configuration>
+ <server name="H2 Database"
class="org.rhq.plugins.database.H2Database"
+ discovery="org.rhq.plugins.database.H2DatabaseDiscovery">
+ <plugin-configuration>
+ <c:simple-property name="url" type="string"
default="jdbc:h2:mem:testdb"/>
+ <c:simple-property name="username" type="string"
default="sa"/>
+ <c:simple-property name="password" type="string"
default=""/>
+ </plugin-configuration>
- </server>
+ </server>
- <service name="Generic Query"
class="org.rhq.plugins.database.CustomTableComponent"
- discovery="org.rhq.plugins.database.CustomTableDiscoveryComponent"
- description="Query the database for various results"
- supportsManualAdd="true" singleton="false"
- createDeletePolicy="both">
+ <service name="Generic Query"
class="org.rhq.plugins.database.CustomTableComponent"
+ discovery="org.rhq.plugins.database.CustomTableDiscoveryComponent"
+ description="Query the database for various results"
+ supportsManualAdd="true" singleton="false"
+ createDeletePolicy="both">
- <runs-inside>
- <parent-resource-type name="H2 Database"
plugin="H2"/>
- </runs-inside>
+ <runs-inside>
+ <parent-resource-type name="H2 Database" plugin="H2"/>
+ </runs-inside>
- <plugin-configuration>
- <c:simple-property name="metricQuery" type="string"
default="select a, b from sometable"/>
- <c:simple-property name="column" type="boolean"
default="true"/>
- </plugin-configuration>
- <metric property="A" displayName="A results"
displayType="summary"
+ <plugin-configuration>
+ <c:simple-property name="table" type="string"
default="table_a"/>
+ <c:simple-property name="metricQuery" type="string"
default="select a, b from table_a"/>
+ <c:simple-property name="column" type="boolean"
default="true"/>
+ </plugin-configuration>
+ <metric property="A" displayName="A results"
displayType="summary"
description="Number appearing in A column"
units="none" dataType="measurement"/>
- <metric property="B" displayName="B results"
displayType="summary"
+ <metric property="B" displayName="B results"
displayType="summary"
description="Number appearing in B column"
units="none" dataType="measurement"/>
- </service>
+ </service>
+ <service name="Generic Query Non Pooling"
class="org.rhq.plugins.database.NonPoolingCustomTableComponent"
+ discovery="org.rhq.plugins.database.CustomTableDiscoveryComponent"
+ description="Query the database for various results"
+ supportsManualAdd="true" singleton="false"
+ createDeletePolicy="both">
+
+ <runs-inside>
+ <parent-resource-type name="Generic Query" plugin="H2"/>
+ </runs-inside>
+
+ <plugin-configuration>
+ <c:simple-property name="table" type="string"
default="table_b"/>
+ <c:simple-property name="metricQuery" type="string"
default="select a, b from table_b"/>
+ <c:simple-property name="column" type="boolean"
default="true"/>
+ </plugin-configuration>
+ <metric property="A" displayName="A results"
displayType="summary"
+ description="Number appearing in A column"
+ units="none" dataType="measurement"/>
+ <metric property="B" displayName="B results"
displayType="summary"
+ description="Number appearing in B column"
+ units="none" dataType="measurement"/>
+ </service>
+
+ <service name="Nested Generic Query"
class="org.rhq.plugins.database.CustomTableComponent"
+ discovery="org.rhq.plugins.database.CustomTableDiscoveryComponent"
+ description="Query the database for various results"
+ supportsManualAdd="true" singleton="false"
+ createDeletePolicy="both">
+
+ <runs-inside>
+ <parent-resource-type name="Generic Query Non Pooling"
plugin="H2"/>
+ </runs-inside>
+
+ <plugin-configuration>
+ <c:simple-property name="table" type="string"
default="table_c"/>
+ <c:simple-property name="metricQuery" type="string"
default="select a, b from table_c"/>
+ <c:simple-property name="column" type="boolean"
default="true"/>
+ </plugin-configuration>
+ <metric property="A" displayName="A results"
displayType="summary"
+ description="Number appearing in A column"
+ units="none" dataType="measurement"/>
+ <metric property="B" displayName="B results"
displayType="summary"
+ description="Number appearing in B column"
+ units="none" dataType="measurement"/>
+ </service>
</plugin>
diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java
index 9d7169e..3cd2401 100644
--- a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java
+++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,15 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.mysql;
+import static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
+import static org.rhq.core.domain.measurement.AvailabilityType.UP;
+
import java.io.File;
import java.io.FileReader;
import java.sql.Connection;
@@ -43,78 +47,104 @@ import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
import org.rhq.core.system.AggregateProcessInfo;
import org.rhq.core.system.ProcessInfo;
+import org.rhq.plugins.database.ConnectionPoolingSupport;
import org.rhq.plugins.database.DatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
+import org.rhq.plugins.database.PooledConnectionProvider;
/**
* @author Greg Hinkle
* @author Steve Millidge
*/
-public class MySqlComponent implements
DatabaseComponent<ResourceComponent<?>>,
+public class MySqlComponent implements
DatabaseComponent<ResourceComponent<?>>, ConnectionPoolingSupport,
ResourceComponent<ResourceComponent<?>>, MeasurementFacet {
+ private static final Log LOG = LogFactory.getLog(MySqlComponent.class);
+
private ResourceContext resourceContext;
private AggregateProcessInfo aggregateProcessInfo;
- private MySqlConnectionInfo info;
- private Log log = LogFactory.getLog(this.getClass());
private Map<String, String> globalStatusValues = new HashMap<String,
String>();
private Map<String, String> globalVariables = new HashMap<String,
String>();
+ private MySqlPooledConnectionProvider pooledConnectionProvider;
+ @Deprecated
+ private Connection sharedConnection;
public void start(ResourceContext resourceContext) throws
InvalidPluginConfigurationException, Exception {
this.resourceContext = resourceContext;
- info =
MySqlDiscoveryComponent.buildConnectionInfo(resourceContext.getPluginConfiguration());
+ buildSharedConnectionIfNeeded();
+ pooledConnectionProvider = new
MySqlPooledConnectionProvider(resourceContext.getPluginConfiguration());
ProcessInfo processInfo = resourceContext.getNativeProcess();
if (processInfo != null) {
aggregateProcessInfo = processInfo.getAggregateProcessTree();
} else {
- //findProcessInfo();
- //log.debug("Unable to locate native process information. Process level
statistics will be unavailable.");
+ findProcessInfo();
+ }
+ }
+
+ private void buildSharedConnectionIfNeeded() {
+ try {
+ if ((sharedConnection == null) || sharedConnection.isClosed()) {
+ sharedConnection =
MySqlDiscoveryComponent.buildConnection(this.resourceContext
+ .getPluginConfiguration());
+ }
+ } catch (SQLException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Could not build shared connection", e);
+ }
}
}
public void stop() {
- MySqlConnectionManager.getConnectionManager().closeConnection(info);
+ resourceContext = null;
+ DatabasePluginUtil.safeClose(sharedConnection);
+ sharedConnection = null;
+ pooledConnectionProvider.close();
+ pooledConnectionProvider = null;
+ aggregateProcessInfo = null;
}
- public AvailabilityType getAvailability() {
- if (log.isDebugEnabled()) {
- log.debug("Doing an availability check on " + info.buildURL());
- }
+ @Override
+ public boolean supportsConnectionPooling() {
+ return true;
+ }
- Connection conn = getConnection();
- AvailabilityType result = AvailabilityType.DOWN;
- if (conn != null) {
- // the connection must be OK as the validity check will have worked
- result = AvailabilityType.UP;
- }
- if (log.isDebugEnabled()) {
- log.debug("Availability check on " + info.buildURL() + " gives
" + result);
- }
- return result;
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return pooledConnectionProvider;
+ }
+ public AvailabilityType getAvailability() {
+ Connection jdbcConnection = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ return jdbcConnection.isValid(1) ? UP : DOWN;
+ } catch (SQLException e) {
+ return DOWN;
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection);
+ }
}
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) throws Exception {
- Connection conn = getConnection();
- if (conn != null) {
- ResultSet rs = null;
- Statement stmt = null;
- try {
- stmt = conn.createStatement();
- rs = stmt.executeQuery("SHOW GLOBAL STATUS");
- while (rs.next()) {
- globalStatusValues.put(rs.getString(1), rs.getString(2));
- }
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("SHOW GLOBAL STATUS");
+ while (resultSet.next()) {
+ globalStatusValues.put(resultSet.getString(1), resultSet.getString(2));
+ }
- rs.close();
- rs = stmt.executeQuery("select * from
information_schema.global_variables");
- while (rs.next()) {
- globalVariables.put(rs.getString(1), rs.getString(2));
- }
- } catch (SQLException sqle) {
- } finally {
- DatabaseQueryUtility.close(stmt, rs);
+ resultSet.close();
+ resultSet = statement.executeQuery("select * from
information_schema.global_variables");
+ while (resultSet.next()) {
+ globalVariables.put(resultSet.getString(1), resultSet.getString(2));
}
+ } catch (SQLException ignore) {
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
// get process information
@@ -154,7 +184,7 @@ public class MySqlComponent implements
DatabaseComponent<ResourceComponent<?>>,
String strVal = globalStatusValues.get(request.getName());
double val = Double.parseDouble(strVal);
report.addData(new MeasurementDataNumeric(request, val));
- } catch (Exception e) {
+ } catch (Exception ignore) {
}
}
}
@@ -162,17 +192,14 @@ public class MySqlComponent implements
DatabaseComponent<ResourceComponent<?>>,
}
public Connection getConnection() {
- try {
- return MySqlConnectionManager.getConnectionManager().getConnection(info);
- } catch (SQLException ex) {
- log.warn("Unable to obtain database connection ", ex);
- return null;
- }
+ buildSharedConnectionIfNeeded();
+ return sharedConnection;
}
@Override
public void removeConnection() {
- MySqlConnectionManager.getConnectionManager().closeConnection(info);
+ DatabasePluginUtil.safeClose(this.sharedConnection);
+ this.sharedConnection = null;
}
private AggregateProcessInfo findProcessInfo() {
@@ -212,7 +239,7 @@ public class MySqlComponent implements
DatabaseComponent<ResourceComponent<?>>,
pidFileReader.close();
}
} catch (Exception ex) {
- log.warn("Unable to read MySQL pid file " + pidFile);
+ LOG.warn("Unable to read MySQL pid file " + pidFile);
}
}
return result;
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionInfo.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionInfo.java
deleted file mode 100644
index 4fa0a4f..0000000
--- a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionInfo.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.plugins.mysql;
-
-/**
- * A class to act as a key to a specific MySQL connection
- * @author Steve Millidge (C2B2 Consulting Limited)
- */
-class MySqlConnectionInfo {
-
- private String host;
- private String port;
- private String db;
- private String user;
- private String password;
- private int hashCode;
-
- MySqlConnectionInfo(String host, String port, String db, String user, String password
) {
- this.host = host;
- this.port = port;
- this.db = db;
- this.user = user;
- this.password = password;
- this.hashCode = new StringBuilder().append(host).
- append(port).
- append(db).
- append(user).
- append(password).toString().hashCode();
-
- }
-
- public String getDb() {
- return db;
- }
-
- @Override
- public int hashCode() {
- return hashCode;
- }
-
- public String getHost() {
- return host;
- }
-
- public String getPassword() {
- return password;
- }
-
- public String getPort() {
- return port;
- }
-
- public String getUser() {
- return user;
- }
-
- public String buildURL() {
- return new StringBuilder().append("jdbc:mysql://")
- .append(host)
- .append(":")
- .append(port)
- .append("/")
- .append(db).toString();
- }
-
- @Override
- public boolean equals(Object other) {
- boolean result = false;
- if ((other instanceof MySqlConnectionInfo) && (other.hashCode() ==
this.hashCode())) {
- result = true;
- }
- return result;
- }
-
-}
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java
deleted file mode 100644
index 6c81332..0000000
---
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.plugins.mysql;
-
-import java.sql.Connection;
-import java.sql.Driver;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.HashMap;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * A class to manage the connections to MySQL
- * This class keeps a cache of connections to MySQL and reuses them on demand
- * We assume single threaded access to the Connection in the agent
- * this will need to be reworked if that assumption is not correct
- * @author Steve Millidge (C2B2 Consulting Limited)
- */
-class MySqlConnectionManager {
-
- private HashMap<MySqlConnectionInfo, Connection> connections;
- private static MySqlConnectionManager singleton;
- private Log logger = LogFactory.getLog(MySqlConnectionManager.class);
-
- private MySqlConnectionManager() {
- connections = new HashMap<MySqlConnectionInfo,Connection>();
- }
-
- static MySqlConnectionManager getConnectionManager() {
- if (singleton == null) {
- singleton = new MySqlConnectionManager();
- }
- return singleton;
- }
-
- public void shutdown() {
- Driver driver = null;
- for (Connection conn : connections.values()) {
- try {
- if (driver == null) {
- String driverName = conn.getMetaData().getDriverName();
- driver = DriverManager.getDriver(driverName);
- }
- conn.close();
- }catch(SQLException e) { logger.info("Problem closing connection on
Shutdown ignoring...");}
- }
- // deregister driver as well
- if (driver != null) {
- try {
- DriverManager.deregisterDriver(driver);
- } catch (SQLException ex) {
- logger.warn("Unable to deregister MySQL Driver on shutdown");
- }
- }
- }
-
- void closeConnection(MySqlConnectionInfo info) {
- Connection conn = connections.get(info);
- if (conn != null) {
- try {
- if (logger.isDebugEnabled()) {
- logger.debug("Closing Connection to " + info.buildURL());
- }
- conn.close();
- } catch (SQLException e) {
- logger.warn("Problem closing connection to " + info.buildURL()
+ " on close");
- }
- }
- connections.remove(info);
- }
-
- Connection getConnection (MySqlConnectionInfo info) throws SQLException {
- try {
- Class.forName("com.mysql.jdbc.Driver");
- } catch (Exception ex) {
- logger.error("Unable to find com.mysql.jdbc.Driver");
- }
-
- Connection conn = connections.get(info);
- String url = info.buildURL();
- if (conn == null) {
- if (logger.isInfoEnabled()) {
- logger.info("Attemping connection to " + url);
- }
- conn = DriverManager.getConnection(url,info.getUser(), info.getPassword());
- if (logger.isInfoEnabled()) {
- logger.info("Successfully connected to " + url);
- }
- connections.put(info, conn);
- } else {
- if (logger.isDebugEnabled()) {
- logger.debug("Reusing existing connection to " + url);
- }
- }
-
- // check the validity of the connection
- if (!conn.isValid(0)) {
- // attempt a single reconnect here and now
- conn.close();
- conn = DriverManager.getConnection(url,info.getUser(), info.getPassword());
- connections.put(info, conn);
- logger.info("Refreshed a connection to " + url);
- }
- return conn;
- }
-
-}
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseComponent.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseComponent.java
index 43747bc..be436af 100644
---
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseComponent.java
+++
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,40 +13,45 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
-package org.rhq.plugins.mysql;
+package org.rhq.plugins.mysql;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.pluginapi.availability.AvailabilityFacet;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
+import org.rhq.plugins.database.ConnectionPoolingSupport;
import org.rhq.plugins.database.DatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
-import org.rhq.core.domain.configuration.PropertySimple;
-import org.rhq.core.domain.measurement.AvailabilityType;
+import org.rhq.plugins.database.DatabasePluginUtil;
+import org.rhq.plugins.database.PooledConnectionProvider;
/**
- *
* @author Steve Millidge (C2B2 Consulting Limited)
*/
-public class MySqlDatabaseComponent implements DatabaseComponent, AvailabilityFacet,
OperationFacet {
+public class MySqlDatabaseComponent implements DatabaseComponent,
ConnectionPoolingSupport, AvailabilityFacet,
+ OperationFacet {
+
+ private static final Log LOG = LogFactory.getLog(MySqlDatabaseComponent.class);
private ResourceContext resourceContext;
private MySqlComponent parent;
private String databaseName;
- private static Log log = LogFactory.getLog(MySqlDatabaseComponent.class);
@Override
public Connection getConnection() {
@@ -59,109 +64,120 @@ public class MySqlDatabaseComponent implements DatabaseComponent,
AvailabilityFa
}
@Override
+ public boolean supportsConnectionPooling() {
+ return true;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return parent.getPooledConnectionProvider();
+ }
+
+ @Override
public void start(ResourceContext rc) throws InvalidPluginConfigurationException,
Exception {
resourceContext = rc;
databaseName = rc.getResourceKey();
- parent = (MySqlComponent)resourceContext.getParentResourceComponent();
+ parent = (MySqlComponent) resourceContext.getParentResourceComponent();
}
- public String getName() { return databaseName; }
+ public String getName() {
+ return databaseName;
+ }
@Override
public void stop() {
+ resourceContext = null;
+ databaseName = null;
+ parent = null;
}
@Override
public AvailabilityType getAvailability() {
AvailabilityType result = AvailabilityType.DOWN;
- if (log.isDebugEnabled()) {
- log.debug("Availability check for " + databaseName);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Availability check for " + databaseName);
}
- Connection conn = getConnection();
- if (conn != null) {
- Statement statement = null;
- ResultSet resultSet = null;
- try {
- statement = conn.createStatement();
- resultSet = statement.executeQuery("SHOW DATABASES LIKE '"
+ databaseName + "'");
- if (resultSet.next()) {
- if (resultSet.getString(1).equalsIgnoreCase(databaseName)) {
- result = AvailabilityType.UP;
- }
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("SHOW DATABASES LIKE '" +
databaseName + "'");
+ if (resultSet.next()) {
+ if (resultSet.getString(1).equalsIgnoreCase(databaseName)) {
+ result = AvailabilityType.UP;
}
- }catch(SQLException e) {
- if (log.isDebugEnabled()) {
- log.debug("Got Exception when determining database
availability",e);
- }
- } finally {
- DatabaseQueryUtility.close(statement, resultSet);
}
+ } catch (SQLException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Got Exception when determining database
availability", e);
+ }
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
return result;
}
@Override
- public OperationResult invokeOperation(String name, Configuration parameters)
- throws InterruptedException, Exception {
-
+ public OperationResult invokeOperation(String name, Configuration parameters) throws
InterruptedException,
+ Exception {
if ("invokeSql".equals(name)) {
- Statement stmt = null;
- ResultSet rs = null;
- try {
- stmt = getConnection().createStatement();
- String sql = parameters.getSimple("sql").getStringValue();
- OperationResult result = new OperationResult();
-
- if
(parameters.getSimple("type").getStringValue().equals("update")) {
- int updateCount = stmt.executeUpdate(sql);
- result.getComplexResults().put(new PropertySimple("result",
"Query updated " + updateCount + " rows"));
-
- } else {
- rs =
stmt.executeQuery(parameters.getSimple("sql").getStringValue());
-
- ResultSetMetaData md = rs.getMetaData();
- StringBuilder buf = new StringBuilder();
- int rowCount = 0;
-
- buf.append("<table>");
- buf.append("<th>");
+ return invokeSql(parameters);
+ } else {
+ throw new UnsupportedOperationException("Operation [" + name +
"] is not supported yet.");
+ }
+ }
+
+ private OperationResult invokeSql(Configuration parameters) throws SQLException {
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = getConnection().createStatement();
+ String sql = parameters.getSimple("sql").getStringValue();
+ OperationResult result = new OperationResult();
+
+ if
(parameters.getSimple("type").getStringValue().equals("update")) {
+ int updateCount = statement.executeUpdate(sql);
+ result.getComplexResults().put(new PropertySimple("result",
"Query updated " + updateCount + " rows"));
+
+ } else {
+ resultSet =
statement.executeQuery(parameters.getSimple("sql").getStringValue());
+
+ ResultSetMetaData md = resultSet.getMetaData();
+ StringBuilder buf = new StringBuilder();
+ int rowCount = 0;
+
+ buf.append("<table>");
+ buf.append("<th>");
+ for (int i = 1; i <= md.getColumnCount(); i++) {
+ buf.append("<td>");
+ buf.append(md.getColumnName(i) + " (" +
md.getColumnTypeName(i) + ")");
+ buf.append("</td>");
+ }
+ buf.append("</th>");
+
+ while (resultSet.next()) {
+ rowCount++;
+ buf.append("<tr>");
for (int i = 1; i <= md.getColumnCount(); i++) {
buf.append("<td>");
- buf.append(md.getColumnName(i) + " (" +
md.getColumnTypeName(i) + ")");
+ buf.append(resultSet.getString(i));
buf.append("</td>");
}
- buf.append("</th>");
-
-
- while (rs.next()) {
- rowCount++;
- buf.append("<tr>");
- for (int i = 1; i <= md.getColumnCount(); i++) {
- buf.append("<td>");
- buf.append(rs.getString(i));
- buf.append("</td>");
- }
- buf.append("</tr>");
- }
-
- buf.append("</table>");
- result.getComplexResults().put(new PropertySimple("result",
"Query returned " + rowCount + " rows"));
- result.getComplexResults().put(new
PropertySimple("contents", buf.toString()));
- }
- return result;
- } finally {
- if (rs != null) {
- rs.close();
+ buf.append("</tr>");
}
- if (stmt != null) {
- stmt.close();
- }
+ buf.append("</table>");
+ result.getComplexResults().put(new PropertySimple("result",
"Query returned " + rowCount + " rows"));
+ result.getComplexResults().put(new PropertySimple("contents",
buf.toString()));
}
- } else {
- throw new UnsupportedOperationException("Operation [" + name +
"] is not supported yet.");
+ return result;
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
}
}
-
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java
index 100e536..8356d56 100644
---
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java
+++
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,78 +13,63 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
-package org.rhq.plugins.mysql;
-import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
-import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
-import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+package org.rhq.plugins.mysql;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
+import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* @author Greg Hinkle
* @author Steve Millidge
*/
public class MySqlDatabaseDiscoveryComponent implements
ResourceDiscoveryComponent<MySqlComponent> {
-
- private Log logger = LogFactory.getLog(this.getClass());
+ private static final Log LOG =
LogFactory.getLog(MySqlDatabaseDiscoveryComponent.class);
@Override
public Set<DiscoveredResourceDetails>
discoverResources(ResourceDiscoveryContext<MySqlComponent> context) {
-
- if (logger.isDebugEnabled()) {
- logger.debug("Database discovery started");
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Database discovery started");
}
- Set<DiscoveredResourceDetails> databases = new
LinkedHashSet<DiscoveredResourceDetails>();
- Connection connection = context.getParentResourceComponent().getConnection();
-
-
+ Connection jdbcConnection = null;
Statement statement = null;
ResultSet resultSet = null;
- if (connection != null) {
- try {
- statement = connection.createStatement();
- resultSet = statement.executeQuery("SHOW DATABASES");
-
- while (resultSet.next()) {
- String databaseName = resultSet.getString(1);
- Configuration config = context.getDefaultPluginConfiguration();
- config.put(new
PropertySimple("databaseName",databaseName));
- DiscoveredResourceDetails details =
- new DiscoveredResourceDetails(
- context.getResourceType(),
- databaseName,
- databaseName + " Database",
- null,
- "A MySql Database",
- config,
- null);
- databases.add(details);
- }
-
- } catch (SQLException e) {
- } finally {
- DatabaseQueryUtility.close(statement, resultSet);
- }
- } else {
- if (logger.isInfoEnabled()) {
- logger.info("No connection to MySQL obtained from connection
manager");
+ try {
+ jdbcConnection =
context.getParentResourceComponent().getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("SHOW DATABASES");
+ Set<DiscoveredResourceDetails> databases = new
LinkedHashSet<DiscoveredResourceDetails>();
+ while (resultSet.next()) {
+ String databaseName = resultSet.getString(1);
+ Configuration config = context.getDefaultPluginConfiguration();
+ config.put(new PropertySimple("databaseName", databaseName));
+ DiscoveredResourceDetails details = new
DiscoveredResourceDetails(context.getResourceType(),
+ databaseName, databaseName + " Database", null, "A
MySql Database", config, null);
+ databases.add(details);
}
+ return databases;
+ } catch (SQLException ignore) {
+ return Collections.emptySet();
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
-
- return databases;
}
}
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java
index c4ada90..30ccef4 100644
---
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java
+++
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,28 +13,31 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.mysql;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.pluginapi.inventory.ManualAddFacet;
import org.rhq.core.pluginapi.inventory.ProcessScanResult;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.pluginapi.inventory.ManualAddFacet;
import org.rhq.core.system.ProcessInfo;
-import org.rhq.core.util.jdbc.JDBCUtil;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* @author Greg Hinkle
@@ -42,7 +45,7 @@ import java.util.Set;
* @author Steve Millidge
*/
public class MySqlDiscoveryComponent implements ResourceDiscoveryComponent,
ManualAddFacet {
- private static final Log log = LogFactory.getLog(MySqlDiscoveryComponent.class);
+ private static final Log LOG = LogFactory.getLog(MySqlDiscoveryComponent.class);
public static final String HOST_CONFIGURATION_PROPERTY = "host";
public static final String PORT_CONFIGURATION_PROPERTY = "port";
@@ -52,81 +55,83 @@ public class MySqlDiscoveryComponent implements
ResourceDiscoveryComponent, Manu
public Set<DiscoveredResourceDetails>
discoverResources(ResourceDiscoveryContext context) {
- if (log.isDebugEnabled()) {
- log.debug("Resource Discovery Started");
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Resource Discovery Started");
}
Set<DiscoveredResourceDetails> servers = new
LinkedHashSet<DiscoveredResourceDetails>();
// Process any auto-discovered resources.
List<ProcessScanResult> autoDiscoveryResults =
context.getAutoDiscoveredProcesses();
for (ProcessScanResult result : autoDiscoveryResults) {
- log.info("Discovered a mysql process: " + result);
+ LOG.info("Discovered a mysql process: " + result);
ProcessInfo procInfo = result.getProcessInfo();
-
servers.add(createResourceDetails(context,context.getDefaultPluginConfiguration(),procInfo));
+ servers.add(createResourceDetails(context,
context.getDefaultPluginConfiguration(), procInfo));
}
return servers;
}
public DiscoveredResourceDetails discoverResource(Configuration pluginConfiguration,
- ResourceDiscoveryContext
resourceDiscoveryContext)
- throws InvalidPluginConfigurationException {
+ ResourceDiscoveryContext resourceDiscoveryContext) throws
InvalidPluginConfigurationException {
ProcessInfo processInfo = null;
- DiscoveredResourceDetails resourceDetails =
createResourceDetails(resourceDiscoveryContext, pluginConfiguration,
- processInfo);
+ DiscoveredResourceDetails resourceDetails =
createResourceDetails(resourceDiscoveryContext,
+ pluginConfiguration, processInfo);
return resourceDetails;
}
protected static DiscoveredResourceDetails
createResourceDetails(ResourceDiscoveryContext discoveryContext,
- Configuration pluginConfiguration,
- ProcessInfo processInfo) throws InvalidPluginConfigurationException {
+ Configuration pluginConfig, ProcessInfo processInfo) throws
InvalidPluginConfigurationException {
- MySqlConnectionInfo ci = buildConnectionInfo(pluginConfiguration);
- Connection conn;
+ Connection conn = null;
String version = "";
try {
- conn = MySqlConnectionManager.getConnectionManager().getConnection(ci);
+ conn = buildConnection(pluginConfig);
version = conn.getMetaData().getDatabaseProductVersion();
} catch (SQLException ex) {
// ignore so we can still add to the inventory even though we can't
currently connect
+ } finally {
+ DatabasePluginUtil.safeClose(conn);
}
- String key = new StringBuilder().append("MySql:")
- .append(ci.getDb())
- .append(":")
- .append(ci.getHost())
- .append(":")
- .append(ci.getPort())
- .append("-")
- .append(ci.getUser()).toString();
+ String key = new StringBuilder().append("MySql:")
+
.append(pluginConfig.getSimple(DB_CONFIGURATION_PROPERTY).getStringValue()).append(":")
+
.append(pluginConfig.getSimple(HOST_CONFIGURATION_PROPERTY).getStringValue()).append(":")
+
.append(pluginConfig.getSimple(PORT_CONFIGURATION_PROPERTY).getStringValue()).append("-")
+
.append(pluginConfig.getSimple(PRINCIPAL_CONFIGURATION_PROPERTY).getStringValue()).toString();
String name = new StringBuilder().append("MySql [")
- .append(ci.getDb())
- .append("]").toString();
-
- DiscoveredResourceDetails result = new DiscoveredResourceDetails(
- discoveryContext.getResourceType(),
- key,
- name,
- version,
- "MySql Server",
- pluginConfiguration,
- processInfo);
-
- if (log.isDebugEnabled()) {
- log.debug("Discovered Database Server for MySQL Database " +
ci.buildURL());
+
.append(pluginConfig.getSimple(DB_CONFIGURATION_PROPERTY).getStringValue()).append("]").toString();
+
+ DiscoveredResourceDetails result = new
DiscoveredResourceDetails(discoveryContext.getResourceType(), key, name,
+ version, "MySql Server", pluginConfig, processInfo);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Discovered Database Server for MySQL Database " +
buildConnectionURL(pluginConfig));
}
return result;
}
- static MySqlConnectionInfo buildConnectionInfo(Configuration configuration) {
- // build the Discovered Resource from the configuration
- String host =
configuration.getSimple(HOST_CONFIGURATION_PROPERTY).getStringValue();
- String port =
configuration.getSimple(PORT_CONFIGURATION_PROPERTY).getStringValue();
- String user =
configuration.getSimple(PRINCIPAL_CONFIGURATION_PROPERTY).getStringValue();
- String pass =
configuration.getSimple(CREDENTIALS_CONFIGURATION_PROPERTY).getStringValue();
- String db =
configuration.getSimple(DB_CONFIGURATION_PROPERTY).getStringValue();
- return new MySqlConnectionInfo(host, port, db, user, pass);
- }
+ static String buildConnectionURL(Configuration pluginConfig) {
+ return new StringBuilder().append("jdbc:mysql://")
+
.append(pluginConfig.getSimple(HOST_CONFIGURATION_PROPERTY).getStringValue()).append(":")
+
.append(pluginConfig.getSimple(PORT_CONFIGURATION_PROPERTY).getStringValue()).append("/")
+
.append(pluginConfig.getSimple(DB_CONFIGURATION_PROPERTY).getStringValue()).toString();
+ }
+
+ static Connection buildConnection(Configuration pluginConfig) throws SQLException {
+ String driverClass = "com.mysql.jdbc.Driver";
+ try {
+ Class.forName(driverClass);
+ } catch (ClassNotFoundException e) {
+ throw new InvalidPluginConfigurationException("Specified JDBC driver
class (" + driverClass
+ + ") not found.");
+ }
+
+ String url = buildConnectionURL(pluginConfig);
+ String principal =
pluginConfig.getSimple(PRINCIPAL_CONFIGURATION_PROPERTY).getStringValue();
+ String credentials =
pluginConfig.getSimple(CREDENTIALS_CONFIGURATION_PROPERTY).getStringValue();
+
+ return DriverManager.getConnection(url, principal, credentials);
+ }
}
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java
index a731aed..db4580e 100644
---
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java
+++
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,34 +13,50 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.mysql;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.util.Enumeration;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.pluginapi.plugin.PluginContext;
import org.rhq.core.pluginapi.plugin.PluginLifecycleListener;
+import org.rhq.core.util.exception.ThrowableUtil;
/**
- *
* @author Steve Millidge (C2B2 Consulting Limited)
*/
public class MySqlPluginLifecycleListener implements PluginLifecycleListener {
- private final Log log = LogFactory.getLog(MySqlPluginLifecycleListener.class);
- private String pluginName;
+ private static final Log LOG =
LogFactory.getLog(MySqlPluginLifecycleListener.class);
public void initialize(PluginContext context) throws Exception {
- pluginName = context.getPluginName();
}
public void shutdown() {
- if (log.isDebugEnabled()) {
- log.debug(new StringBuilder().append(pluginName).append(" Plugin
Shutdown").toString());
+ // so we do not cause our classloader to leak perm gen, we need to de-register
+ // any and all JDBC drivers this plugin registered
+ Enumeration<Driver> drivers = DriverManager.getDrivers();
+ while (drivers.hasMoreElements()) {
+ try {
+ Driver driver = drivers.nextElement();
+ DriverManager.deregisterDriver(driver);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Deregistered JDBC driver: " +
driver.getClass());
+ }
+ } catch (Exception e) {
+ LOG.warn("Failed to deregister JDBC drivers - memory might
leak" + ThrowableUtil.getAllMessages(e));
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(this.getClass().getSimpleName() + " completed
shutdown.");
}
- MySqlConnectionManager.getConnectionManager().shutdown();
}
}
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPooledConnectionProvider.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPooledConnectionProvider.java
new file mode 100644
index 0000000..56f5782
--- /dev/null
+++
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPooledConnectionProvider.java
@@ -0,0 +1,61 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.plugins.mysql;
+
+import static
org.rhq.plugins.mysql.MySqlDiscoveryComponent.CREDENTIALS_CONFIGURATION_PROPERTY;
+import static
org.rhq.plugins.mysql.MySqlDiscoveryComponent.PRINCIPAL_CONFIGURATION_PROPERTY;
+import static org.rhq.plugins.mysql.MySqlDiscoveryComponent.buildConnectionURL;
+
+import java.sql.Driver;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.plugins.database.BasePooledConnectionProvider;
+
+/**
+ * A MySql plugin adapted {@link org.rhq.plugins.database.PooledConnectionProvider}.
+ *
+ * @author Thomas Segismont
+ */
+public class MySqlPooledConnectionProvider extends BasePooledConnectionProvider {
+
+ public MySqlPooledConnectionProvider(Configuration pluginConfig) throws Exception {
+ super(pluginConfig);
+ }
+
+ @Override
+ protected Class<Driver> getDriverClass() throws ClassNotFoundException {
+ return (Class<Driver>) Class.forName("com.mysql.jdbc.Driver");
+ }
+
+ @Override
+ protected String getJdbcUrl() {
+ return buildConnectionURL(pluginConfig);
+ }
+
+ @Override
+ protected String getUsername() {
+ return
pluginConfig.getSimple(PRINCIPAL_CONFIGURATION_PROPERTY).getStringValue();
+ }
+
+ @Override
+ protected String getPassword() {
+ return
pluginConfig.getSimple(CREDENTIALS_CONFIGURATION_PROPERTY).getStringValue();
+ }
+}
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableComponent.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableComponent.java
index 73354f9..ecbde73 100644
--- a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableComponent.java
+++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,18 +13,24 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.mysql;
+import static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
+import static org.rhq.core.domain.measurement.AvailabilityType.UP;
+
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDataTrait;
@@ -33,19 +39,20 @@ import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
+import org.rhq.plugins.database.ConnectionPoolingSupport;
import org.rhq.plugins.database.DatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
+import org.rhq.plugins.database.PooledConnectionProvider;
/**
- *
* @author Steve Millidge (C2B2 Consulting Limited)
*/
-public class MySqlTableComponent implements DatabaseComponent, MeasurementFacet {
+public class MySqlTableComponent implements DatabaseComponent, ConnectionPoolingSupport,
MeasurementFacet {
+ private static final Log LOG = LogFactory.getLog(MySqlTableComponent.class);
private String tableName;
private MySqlDatabaseComponent parent;
private String databaseName;
- private Log log = LogFactory.getLog(this.getClass());
@Override
public Connection getConnection() {
@@ -58,72 +65,85 @@ public class MySqlTableComponent implements DatabaseComponent,
MeasurementFacet
}
@Override
+ public boolean supportsConnectionPooling() {
+ return true;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return parent.getPooledConnectionProvider();
+ }
+
+ @Override
public void start(ResourceContext rc) throws InvalidPluginConfigurationException,
Exception {
tableName = rc.getResourceKey();
- parent = (MySqlDatabaseComponent)rc.getParentResourceComponent();
+ parent = (MySqlDatabaseComponent) rc.getParentResourceComponent();
databaseName = parent.getName();
}
@Override
public void stop() {
+ tableName = null;
+ parent = null;
+ databaseName = null;
}
@Override
public AvailabilityType getAvailability() {
- AvailabilityType result = AvailabilityType.DOWN;
- Connection conn = parent.getConnection();
- if (conn != null) {
- Statement stmt = null;
- ResultSet rs = null;
- try {
- stmt = conn.createStatement();
- rs = stmt.executeQuery("show tables from " + databaseName +
" like '" + tableName + "'");
- if (rs.first()) {
- result = AvailabilityType.UP;
- }
- }catch (SQLException se) {
- // ignore as unablailable if we can't execute the query
- }finally {
- DatabaseQueryUtility.close(stmt, rs);
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("show tables from " +
databaseName + " like '" + tableName + "'");
+ if (resultSet.first()) {
+ return UP;
}
+ } catch (SQLException se) {
+ // Will return down
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
- return result;
+ return DOWN;
}
@Override
public void getValues(MeasurementReport mr, Set<MeasurementScheduleRequest>
set) throws Exception {
- Connection conn = parent.getConnection();
- if (conn != null ) {
- Statement stmt = null;
- ResultSet rs = null;
- try {
- stmt = conn.createStatement();
- rs = stmt.executeQuery("show table status from " +
databaseName+ " like '" + tableName + "'");
- if (rs.next()) {
- for (MeasurementScheduleRequest request : set) {
- String value = rs.getString(request.getName());
- if (value == null) {value = "0";}
- switch (request.getDataType()) {
- case MEASUREMENT: {
- mr.addData(new MeasurementDataNumeric(request,
Double.valueOf(value)));
- break;
- } case TRAIT: {
- mr.addData(new MeasurementDataTrait(request, value));
- break;
- } default: {
- break;
- }
- }
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("show table status from " +
databaseName + " like '" + tableName + "'");
+ if (resultSet.next()) {
+ for (MeasurementScheduleRequest request : set) {
+ String value = resultSet.getString(request.getName());
+ if (value == null) {
+ value = "0";
+ }
+ switch (request.getDataType()) {
+ case MEASUREMENT: {
+ mr.addData(new MeasurementDataNumeric(request,
Double.valueOf(value)));
+ break;
+ }
+ case TRAIT: {
+ mr.addData(new MeasurementDataTrait(request, value));
+ break;
+ }
+ default: {
+ break;
+ }
}
}
- } catch(Exception se) {
- if (log.isInfoEnabled()) {
- log.info("Unable to measure table statistics", se);
- }
- }finally {
- DatabaseQueryUtility.close(stmt, rs);
}
+ } catch (Exception se) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Unable to measure table statistics", se);
+ }
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
}
-
}
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableDiscoveryComponent.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableDiscoveryComponent.java
index 4d7b354..83535e2 100644
---
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableDiscoveryComponent.java
+++
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.mysql;
import java.sql.Connection;
@@ -24,71 +25,66 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* Discovers MySQL tables.
* @author Steve Millidge (C2B2 Consulting Limited)
*/
public class MySqlTableDiscoveryComponent implements ResourceDiscoveryComponent {
+ private static final Log LOG =
LogFactory.getLog(MySqlTableDiscoveryComponent.class);
private static final String TABLE_DISCOVERY = "tableDiscovery";
- private Log log = LogFactory.getLog(this.getClass());
@Override
public Set discoverResources(ResourceDiscoveryContext rdc) throws
InvalidPluginConfigurationException, Exception {
-
- HashSet<DiscoveredResourceDetails> set = new
HashSet<DiscoveredResourceDetails>();
- MySqlDatabaseComponent parent =
(MySqlDatabaseComponent)rdc.getParentResourceComponent();
+ Set<DiscoveredResourceDetails> set = new
HashSet<DiscoveredResourceDetails>();
+ MySqlDatabaseComponent parent = (MySqlDatabaseComponent)
rdc.getParentResourceComponent();
Configuration pconfig = rdc.getParentResourceContext().getPluginConfiguration();
// If the user has disabled table discovery on the parent, we don't
autodiscover
// them, as we may hit temporary ones that go away any time soon again
// See BZ-797356
if (!Boolean.parseBoolean(pconfig.getSimpleValue(TABLE_DISCOVERY,
"true"))) {
- log.debug("table discovery disabled");
+ LOG.debug("table discovery disabled");
return set;
}
- Connection conn = parent.getConnection();
- if (conn != null) {
- Statement stmt = null;
- ResultSet rs = null;
- try {
- stmt = conn.createStatement();
- rs = stmt.executeQuery("show tables from " +
parent.getName());
- while (rs.next()) {
- String tableName = rs.getString(1);
- if (log.isDebugEnabled()) {
- log.debug("Discovered Table "+ tableName);
- }
- Configuration config = new Configuration();
- config.put(new PropertySimple("tableName",tableName));
- DiscoveredResourceDetails details = new DiscoveredResourceDetails(
- rdc.getResourceType(),
- tableName,
- tableName + " Table",
- null,
- tableName + " MySql Table", config, null);
- set.add(details);
- }
- } catch(SQLException se) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to Discover Tables",se);
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = parent.getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("show tables from " +
parent.getName());
+ while (resultSet.next()) {
+ String tableName = resultSet.getString(1);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Discovered Table " + tableName);
}
-
- }finally {
- DatabaseQueryUtility.close(stmt, rs);
+ Configuration config = new Configuration();
+ config.put(new PropertySimple("tableName", tableName));
+ DiscoveredResourceDetails details = new
DiscoveredResourceDetails(rdc.getResourceType(), tableName,
+ tableName + " Table", null, tableName + " MySql
Table", config, null);
+ set.add(details);
+ }
+ } catch (SQLException se) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Unable to Discover Tables", se);
}
+
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
return set;
}
-
}
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserComponent.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserComponent.java
index 32525c2..d0ffb26 100644
--- a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserComponent.java
+++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,20 +13,24 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.plugins.mysql;
+import static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
+import static org.rhq.core.domain.measurement.AvailabilityType.UP;
+
import java.sql.Connection;
-import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementReport;
@@ -34,20 +38,21 @@ import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
+import org.rhq.plugins.database.ConnectionPoolingSupport;
import org.rhq.plugins.database.DatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
+import org.rhq.plugins.database.PooledConnectionProvider;
/**
- *
* @author Steve Millidge (C2B2 Consulting Limited)
*/
-public class MySqlUserComponent implements MeasurementFacet, DatabaseComponent {
+public class MySqlUserComponent implements MeasurementFacet, DatabaseComponent,
ConnectionPoolingSupport {
+ private static final Log LOG = LogFactory.getLog(MySqlUserComponent.class);
private String userName;
private String host;
private MySqlComponent parent;
- private Log log = LogFactory.getLog(this.getClass());
- private ResourceContext context;
+ private ResourceContext resourceContext;
@Override
public Connection getConnection() {
@@ -60,69 +65,85 @@ public class MySqlUserComponent implements MeasurementFacet,
DatabaseComponent {
}
@Override
- public void start(ResourceContext rc) throws InvalidPluginConfigurationException,
Exception {
- parent = (MySqlComponent)rc.getParentResourceComponent();
- context = rc;
- userName =
context.getPluginConfiguration().getSimple("userName").getStringValue();
- host =
context.getPluginConfiguration().getSimple("host").getStringValue();
+ public boolean supportsConnectionPooling() {
+ return true;
}
@Override
- public void stop() {
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return parent.getPooledConnectionProvider();
}
+ @Override
+ public void start(ResourceContext resourceContext) throws
InvalidPluginConfigurationException, Exception {
+ parent = (MySqlComponent) resourceContext.getParentResourceComponent();
+ this.resourceContext = resourceContext;
+ userName =
this.resourceContext.getPluginConfiguration().getSimple("userName").getStringValue();
+ host =
this.resourceContext.getPluginConfiguration().getSimple("host").getStringValue();
+ }
+
+ @Override
+ public void stop() {
+ parent = null;
+ resourceContext = null;
+ userName = null;
+ host = null;
+ }
public void getValues(MeasurementReport mr, Set<MeasurementScheduleRequest>
requests) throws Exception {
- Connection conn = getConnection();
- ResultSet rs = null;
- Statement stmt = null;
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
int activeConnections = 0;
int totalConnections = 0;
try {
- stmt = conn.createStatement();
- rs = stmt.executeQuery("select User,Host,State from
information_schema.processlist where User='"+userName+"'");
- while(rs.next()) {
- String hostVal = rs.getString(2);
- String state = rs.getString(3);
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("select User,Host,State from
information_schema.processlist where User='" + userName
+ + "'");
+ while (resultSet.next()) {
+ String hostVal = resultSet.getString(2);
+ String state = resultSet.getString(3);
if (hostVal.startsWith(host)) {
if (state.length() > 1) {
- activeConnections ++;
+ activeConnections++;
}
totalConnections++;
}
}
- }catch(SQLException sqle) {
-
+ } catch (SQLException ignore) {
} finally {
- DatabaseQueryUtility.close(stmt, rs);
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
for (MeasurementScheduleRequest request : requests) {
if (request.getName().equals("TotalConnections")) {
- mr.addData(new MeasurementDataNumeric(request, new
Double((double)totalConnections)));
+ mr.addData(new MeasurementDataNumeric(request, new Double((double)
totalConnections)));
} else if (request.getName().equals("ActiveConnections")) {
- mr.addData(new MeasurementDataNumeric(request, new
Double((double)activeConnections)));
+ mr.addData(new MeasurementDataNumeric(request, new Double((double)
activeConnections)));
}
}
}
public AvailabilityType getAvailability() {
- AvailabilityType result = AvailabilityType.DOWN;
- Connection conn = getConnection();
- ResultSet rs = null;
- Statement stmt = null;
+ Connection jdbcConnection = null;
+ ResultSet resultSet = null;
+ Statement statement = null;
try {
- stmt = conn.createStatement();
- rs = stmt.executeQuery("select User from mysql.user where
User='"+userName+"' and Host='" + host +"'");
- if (rs.first()) {
- result = AvailabilityType.UP;
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("select User from mysql.user where
User='" + userName + "' and Host='"
+ + host + "'");
+ if (resultSet.first()) {
+ return UP;
}
- }catch(SQLException sqle) {
-
+ } catch (SQLException sqle) {
+ // Will return DOWN
+ System.out.println("sqle = " + sqle);
} finally {
- DatabaseQueryUtility.close(stmt, rs);
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
- return result;
+ return DOWN;
}
}
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserDiscoveryComponent.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserDiscoveryComponent.java
index d05682a..9075b1c 100644
---
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserDiscoveryComponent.java
+++
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.mysql;
import java.sql.Connection;
@@ -23,53 +24,44 @@ import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
+
import org.rhq.core.domain.configuration.Configuration;
-import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
- *
* @author Steve Millidge (C2B2 Consulting Limited)
*/
public class MySqlUserDiscoveryComponent implements ResourceDiscoveryComponent {
public Set discoverResources(ResourceDiscoveryContext rdc) throws
InvalidPluginConfigurationException, Exception {
- HashSet<DiscoveredResourceDetails> set = new
HashSet<DiscoveredResourceDetails>();
+ Set<DiscoveredResourceDetails> set = new
HashSet<DiscoveredResourceDetails>();
MySqlComponent parent = (MySqlComponent) rdc.getParentResourceComponent();
- Connection conn = parent.getConnection();
- if (conn != null) {
- Statement statement = null;
- ResultSet resultSet = null;
- try {
- statement = conn.createStatement();
- resultSet = statement.executeQuery("select User,Host from
mysql.user");
- while (resultSet.next()) {
- String user = resultSet.getString(1);
- String host = resultSet.getString(2);
- String userName = user + "@" + host;
- Configuration config = new Configuration();
- config.put(new PropertySimple("userName",user));
- config.put(new PropertySimple("host",host));
- DiscoveredResourceDetails discoveredUser =
- new DiscoveredResourceDetails(
- rdc.getResourceType(),
- userName,
- userName,
- null,
- "A MySql User",
- config,
- null);
- set.add(discoveredUser);
- }
- } catch (Exception e) {
- } finally {
- DatabaseQueryUtility.close(statement, resultSet);
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = parent.getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("select User,Host from
mysql.user");
+ while (resultSet.next()) {
+ String user = resultSet.getString(1);
+ String host = resultSet.getString(2);
+ String userName = user + "@" + host;
+ Configuration config = new Configuration();
+ config.put(new PropertySimple("userName", user));
+ config.put(new PropertySimple("host", host));
+ DiscoveredResourceDetails discoveredUser = new
DiscoveredResourceDetails(rdc.getResourceType(),
+ userName, userName, null, "A MySql User", config, null);
+ set.add(discoveredUser);
}
+ } catch (Exception e) {
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
return set;
}
diff --git a/modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/ComponentTest.java
b/modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/ComponentTest.java
index 3b431d6..fdcce4a 100644
--- a/modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/ComponentTest.java
+++ b/modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/ComponentTest.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,8 +13,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.plugins.mysql;
diff --git a/modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/PluginTest.java
b/modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/PluginTest.java
index 498fe22..90703ca 100644
--- a/modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/PluginTest.java
+++ b/modules/plugins/mysql/src/test/java/org/rhq/plugins/mysql/PluginTest.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,16 +13,17 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.plugins.mysql;
+import org.testng.annotations.Test;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.inventory.ResourceComponent;
-import org.testng.annotations.Test;
/**
* Tests MySql Server.
diff --git
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupComponent.java
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupComponent.java
index 09e1a80..129b971 100644
---
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupComponent.java
+++
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,15 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.oracle;
+import static org.rhq.plugins.database.DatabasePluginUtil.getConnectionFromComponent;
+
+import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -26,6 +30,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
@@ -33,9 +38,8 @@ import org.rhq.core.domain.measurement.MeasurementDataTrait;
import org.rhq.core.domain.measurement.MeasurementReport;
import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
-import org.rhq.core.util.jdbc.JDBCUtil;
import org.rhq.plugins.database.AbstractDatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* Oracle ASM Disk Group Component.
@@ -43,75 +47,72 @@ import org.rhq.plugins.database.DatabaseQueryUtility;
* @author Richard Hensman
*/
@SuppressWarnings("rawtypes")
-public class OracleAsmDiskGroupComponent extends AbstractDatabaseComponent
- implements MeasurementFacet {
-
- private static final String SQL_AVAILABLE = "SELECT COUNT(*) FROM v$asm_diskgroup
WHERE group_number = ? and STATE <> 'BROKEN'";
-
- private static final String SQL_VALUES = "SELECT GROUP_NUMBER, " + "NAME,
"
- + "SECTOR_SIZE sectorSize, " + "BLOCK_SIZE blockSize, "
- + "ALLOCATION_UNIT_SIZE allocationUnitSize, " + "STATE state, "
- + "TYPE type, " + "TOTAL_MB totalMb, " + "FREE_MB freeMb,
"
- + "((TOTAL_MB-FREE_MB)/TOTAL_MB) usedPercent, "
- + "REQUIRED_MIRROR_FREE_MB requiredMirrorFreeMb, "
- + "USABLE_FILE_MB usableFileMb, " + "OFFLINE_DISKS offlineDisks,
"
- + "COMPATIBILITY compatibility, "
- + "DATABASE_COMPATIBILITY databaseCompatibility "
- + "FROM v$asm_diskgroup WHERE group_number = ?";
+public class OracleAsmDiskGroupComponent extends AbstractDatabaseComponent implements
MeasurementFacet {
+ private static final Log LOG = LogFactory.getLog(OracleAsmDiskGroupComponent.class);
- private static Log log = LogFactory
- .getLog(OracleAsmDiskGroupComponent.class);
+ private static final String SQL_AVAILABLE = "SELECT COUNT(*) FROM
v$asm_diskgroup WHERE group_number = ? and STATE <> 'BROKEN'";
+ private static final String SQL_VALUES = "SELECT GROUP_NUMBER, " +
"NAME, " + "SECTOR_SIZE sectorSize, "
+ + "BLOCK_SIZE blockSize, " + "ALLOCATION_UNIT_SIZE
allocationUnitSize, " + "STATE state, " + "TYPE type, "
+ + "TOTAL_MB totalMb, " + "FREE_MB freeMb, " +
"((TOTAL_MB-FREE_MB)/TOTAL_MB) usedPercent, "
+ + "REQUIRED_MIRROR_FREE_MB requiredMirrorFreeMb, " +
"USABLE_FILE_MB usableFileMb, "
+ + "OFFLINE_DISKS offlineDisks, " + "COMPATIBILITY compatibility,
"
+ + "DATABASE_COMPATIBILITY databaseCompatibility " + "FROM
v$asm_diskgroup WHERE group_number = ?";
- public AvailabilityType getAvailability() {
- PreparedStatement statement = null;
- ResultSet resultSet = null;
- try {
- statement = getConnection().prepareStatement(SQL_AVAILABLE);
- statement.setString(1, this.resourceContext.getResourceKey());
- resultSet = statement.executeQuery();
- if (resultSet.next() && (resultSet.getInt(1) == 1)) {
- return AvailabilityType.UP;
- }
- } catch (SQLException e) {
- log.debug("unable to query", e);
- } finally {
- JDBCUtil.safeClose(statement, resultSet);
- }
+ public AvailabilityType getAvailability() {
+ Connection jdbcConnection = null;
+ PreparedStatement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = getConnectionFromComponent(this);
+ statement = jdbcConnection.prepareStatement(SQL_AVAILABLE);
+ statement.setString(1, this.resourceContext.getResourceKey());
+ resultSet = statement.executeQuery();
+ if (resultSet.next() && (resultSet.getInt(1) == 1)) {
+ return AvailabilityType.UP;
+ }
+ } catch (SQLException e) {
+ LOG.debug("unable to query", e);
+ } finally {
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
+ if (supportsConnectionPooling()) {
+ DatabasePluginUtil.safeClose(jdbcConnection);
+ }
+ }
- return AvailabilityType.DOWN;
- }
+ return AvailabilityType.DOWN;
+ }
- public void getValues(MeasurementReport report,
- Set<MeasurementScheduleRequest> metrics) throws Exception {
- PreparedStatement statement = null;
- ResultSet resultSet = null;
- try {
- statement = this.getConnection().prepareStatement(SQL_VALUES);
- statement.setString(1, this.resourceContext.getResourceKey());
- resultSet = statement.executeQuery();
- if (resultSet.next()) {
- for (MeasurementScheduleRequest request : metrics) {
- String name = request.getName().toUpperCase(Locale.US);
- if (request.getDataType().equals(DataType.TRAIT)) {
- report.addData(new MeasurementDataTrait(request,
- resultSet.getString(name)));
- } else {
- try {
- report.addData(new MeasurementDataNumeric(request,
- resultSet.getDouble(name)));
- } catch (SQLException e) {
- // Ignoring metrics that cannot be read as a double
- log.warn("Ignoring metric " + name
- + " as it cannot be read as a double");
- }
- }
- }
- }
- } catch (SQLException e) {
- log.debug("Unable to read value", e);
- removeConnection();
- } finally {
- DatabaseQueryUtility.close(statement, resultSet);
- }
- }
-}
\ No newline at end of file
+ public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) throws Exception {
+ Connection jdbcConnection = null;
+ PreparedStatement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = getConnectionFromComponent(this);
+ statement = jdbcConnection.prepareStatement(SQL_VALUES);
+ statement.setString(1, this.resourceContext.getResourceKey());
+ resultSet = statement.executeQuery();
+ if (resultSet.next()) {
+ for (MeasurementScheduleRequest request : metrics) {
+ String name = request.getName().toUpperCase(Locale.US);
+ if (request.getDataType().equals(DataType.TRAIT)) {
+ report.addData(new MeasurementDataTrait(request,
resultSet.getString(name)));
+ } else {
+ try {
+ report.addData(new MeasurementDataNumeric(request,
resultSet.getDouble(name)));
+ } catch (SQLException e) {
+ // Ignoring metrics that cannot be read as a double
+ LOG.warn("Ignoring metric " + name + " as it
cannot be read as a double");
+ }
+ }
+ }
+ }
+ } catch (SQLException e) {
+ LOG.debug("Unable to read value", e);
+ } finally {
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
+ if (supportsConnectionPooling()) {
+ DatabasePluginUtil.safeClose(jdbcConnection);
+ }
+ }
+ }
+}
diff --git
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupDiscoveryComponent.java
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupDiscoveryComponent.java
index c023b1b..f4b49ef 100644
---
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupDiscoveryComponent.java
+++
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleAsmDiskGroupDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,15 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.oracle;
+import static org.rhq.plugins.database.DatabasePluginUtil.getConnectionFromComponent;
+import static org.rhq.plugins.database.DatabasePluginUtil.hasConnectionPoolingSupport;
+
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -28,65 +32,66 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.util.jdbc.JDBCUtil;
-import org.rhq.plugins.database.DatabaseComponent;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* Discovery Oracle ASM Disk Groups.
*
* @author Richard Hensman
*/
-public class OracleAsmDiskGroupDiscoveryComponent implements
ResourceDiscoveryComponent<DatabaseComponent<?>> {
-
- private final Log log = LogFactory.getLog(getClass());
+public class OracleAsmDiskGroupDiscoveryComponent implements
ResourceDiscoveryComponent<ResourceComponent<?>> {
+ private static final Log LOG =
LogFactory.getLog(OracleAsmDiskGroupDiscoveryComponent.class);
public Set<DiscoveredResourceDetails> discoverResources(
- ResourceDiscoveryContext<DatabaseComponent<?>>
resourceDiscoveryContext)
+ ResourceDiscoveryContext<ResourceComponent<?>>
resourceDiscoveryContext)
throws InvalidPluginConfigurationException, Exception {
- Statement statement = null;
- ResultSet resultSet = null;
-
+
String table = "V$ASM_DISKGROUP";
String keyColumn = "GROUP_NUMBER";
String nameColumn = "NAME";
String description = "Oracle ASM Disk Groups";
-
- try {
- Connection conn =
resourceDiscoveryContext.getParentResourceComponent().getConnection();
- statement = conn.createStatement();
+ ResourceComponent<?> parentComponent =
resourceDiscoveryContext.getParentResourceComponent();
+
+ Connection connection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ connection = getConnectionFromComponent(parentComponent);
+ statement = connection.createStatement();
resultSet = statement.executeQuery("SELECT * FROM " + table);
Configuration config = null;
Set<DiscoveredResourceDetails> found = new
HashSet<DiscoveredResourceDetails>();
while (resultSet.next()) {
- config = resourceDiscoveryContext.getDefaultPluginConfiguration();
+ config = resourceDiscoveryContext.getDefaultPluginConfiguration();
String key = resultSet.getString(keyColumn);
String name = resultSet.getString(nameColumn);
- DiscoveredResourceDetails details =
- new DiscoveredResourceDetails(
- resourceDiscoveryContext.getResourceType(),
- key,
- name,
- null,
- description, config, null);
+ DiscoveredResourceDetails details = new DiscoveredResourceDetails(
+ resourceDiscoveryContext.getResourceType(), key, name, null,
description, config, null);
found.add(details);
}
return found;
} catch (SQLException e) {
- log.debug("table " + table + " column " + keyColumn, e);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("table " + table + " column " + keyColumn,
e);
+ }
} finally {
- JDBCUtil.safeClose(resultSet);
- JDBCUtil.safeClose(statement);
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
+ if (hasConnectionPoolingSupport(parentComponent)) {
+ DatabasePluginUtil.safeClose(connection);
+ }
}
- return Collections.emptySet();
- }
+ return Collections.emptySet();
+ }
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleDiscoveryComponent.java
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleDiscoveryComponent.java
index 79d67fd..f3ab7b6 100644
---
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleDiscoveryComponent.java
+++
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.oracle;
import java.sql.Connection;
@@ -23,26 +24,27 @@ import java.sql.DatabaseMetaData;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.Nullable;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.pluginapi.inventory.ManualAddFacet;
import org.rhq.core.pluginapi.inventory.ProcessScanResult;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.pluginapi.inventory.ManualAddFacet;
import org.rhq.core.system.ProcessInfo;
-import org.rhq.core.util.jdbc.JDBCUtil;
-
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* @author Greg Hinkle
*/
public class OracleDiscoveryComponent implements ResourceDiscoveryComponent,
ManualAddFacet {
- private static Log log = LogFactory.getLog(OracleDiscoveryComponent.class);
+ private static final Log LOG = LogFactory.getLog(OracleDiscoveryComponent.class);
public Set<DiscoveredResourceDetails>
discoverResources(ResourceDiscoveryContext resourceDiscoveryContext)
throws InvalidPluginConfigurationException, Exception {
@@ -51,7 +53,7 @@ public class OracleDiscoveryComponent implements
ResourceDiscoveryComponent, Man
for (ProcessScanResult process : autoDiscoveryResults) {
String sid =
process.getProcessInfo().getEnvironmentVariable("ORACLE_SID");
if ((sid == null) || (sid.length() == 0)) {
- log.info("Unable to discover Oracle instance SID. Use manual
inventory to complete setup.");
+ LOG.info("Unable to discover Oracle instance SID. Use manual
inventory to complete setup.");
continue;
}
@@ -74,22 +76,21 @@ public class OracleDiscoveryComponent implements
ResourceDiscoveryComponent, Man
}
public DiscoveredResourceDetails discoverResource(Configuration pluginConfig,
- ResourceDiscoveryContext
resourceDiscoveryContext)
- throws InvalidPluginConfigurationException {
-
+ ResourceDiscoveryContext resourceDiscoveryContext) throws
InvalidPluginConfigurationException {
+
Connection connection = null;
try {
connection = OracleServerComponent.buildConnection(pluginConfig);
DatabaseMetaData dbmd = connection.getMetaData();
String version = dbmd.getDatabaseMajorVersion() + "." +
dbmd.getDatabaseMinorVersion();
- DiscoveredResourceDetails details =
createResourceDetails(resourceDiscoveryContext, pluginConfig,
- version, null);
+ DiscoveredResourceDetails details =
createResourceDetails(resourceDiscoveryContext, pluginConfig, version,
+ null);
return details;
} catch (Exception e) {
- log.warn("Could not connect to oracle with supplied configuration",
e);
- throw new InvalidPluginConfigurationException("Unable to connect to
Oracle",e);
+ LOG.warn("Could not connect to oracle with supplied configuration",
e);
+ throw new InvalidPluginConfigurationException("Unable to connect to
Oracle", e);
} finally {
- JDBCUtil.safeClose(connection);
+ DatabasePluginUtil.safeClose(connection);
}
}
@@ -102,4 +103,4 @@ public class OracleDiscoveryComponent implements
ResourceDiscoveryComponent, Man
return new DiscoveredResourceDetails(discoveryContext.getResourceType(), key,
name, version, description,
pluginConfig, processInfo);
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleFlashRecoveryAreaComponent.java
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleFlashRecoveryAreaComponent.java
index 0446d7f..c1ef458 100644
---
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleFlashRecoveryAreaComponent.java
+++
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleFlashRecoveryAreaComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,16 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.oracle;
+import static org.rhq.plugins.database.DatabasePluginUtil.getConnectionFromComponent;
+import static org.rhq.plugins.database.DatabasePluginUtil.getNumericQueryValues;
+
+import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -27,14 +32,14 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementReport;
import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
-import org.rhq.core.util.jdbc.JDBCUtil;
import org.rhq.plugins.database.AbstractDatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* Oracle Flash Recovery Area Component.
@@ -42,37 +47,38 @@ import org.rhq.plugins.database.DatabaseQueryUtility;
* @author Richard Hensman
*/
public class OracleFlashRecoveryAreaComponent extends AbstractDatabaseComponent
implements MeasurementFacet {
+ private static final Log LOG =
LogFactory.getLog(OracleFlashRecoveryAreaComponent.class);
private static final String SQL_AVAILABLE = "SELECT COUNT(*) FROM
v$recovery_file_dest WHERE name = ?";
- private static final String SQL_VALUES =
- "SELECT space_limit spaceLimit, space_used spaceUsed, space_reclaimable
spaceReclaimable, number_of_files numberOfFiles, (space_used/space_limit) usedPercent
" +
- "FROM v$recovery_file_dest WHERE name = ?";
-
-
- private static Log log = LogFactory.getLog(OracleFlashRecoveryAreaComponent.class);
+ private static final String SQL_VALUES = "SELECT space_limit spaceLimit,
space_used spaceUsed, space_reclaimable spaceReclaimable, number_of_files numberOfFiles,
(space_used/space_limit) usedPercent "
+ + "FROM v$recovery_file_dest WHERE name = ?";
public AvailabilityType getAvailability() {
+ Connection jdbcConnection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
- statement = getConnection().prepareStatement(SQL_AVAILABLE);
+ jdbcConnection = getConnectionFromComponent(this);
+ statement = jdbcConnection.prepareStatement(SQL_AVAILABLE);
statement.setString(1, this.resourceContext.getResourceKey());
resultSet = statement.executeQuery();
if (resultSet.next() && (resultSet.getInt(1) == 1)) {
return AvailabilityType.UP;
}
} catch (SQLException e) {
- log.debug("unable to query", e);
+ LOG.debug("unable to query", e);
} finally {
- JDBCUtil.safeClose(statement, resultSet);
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
+ if (supportsConnectionPooling()) {
+ DatabasePluginUtil.safeClose(jdbcConnection);
+ }
}
return AvailabilityType.DOWN;
}
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) throws Exception {
- Map<String, Double> values =
DatabaseQueryUtility.getNumericQueryValues(this, SQL_VALUES,
- this.resourceContext.getResourceKey());
+ Map<String, Double> values = getNumericQueryValues(this, SQL_VALUES,
this.resourceContext.getResourceKey());
for (MeasurementScheduleRequest request : metrics) {
Double d = values.get(request.getName().toUpperCase(Locale.US));
if (d != null) {
@@ -80,4 +86,4 @@ public class OracleFlashRecoveryAreaComponent extends
AbstractDatabaseComponent
}
}
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OraclePluginLifecycleListener.java
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OraclePluginLifecycleListener.java
index 488404f..a6e390b 100644
---
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OraclePluginLifecycleListener.java
+++
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OraclePluginLifecycleListener.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.oracle;
import java.sql.Driver;
@@ -30,7 +31,7 @@ import org.rhq.core.pluginapi.plugin.PluginLifecycleListener;
import org.rhq.core.util.exception.ThrowableUtil;
public class OraclePluginLifecycleListener implements PluginLifecycleListener {
- private final Log log = LogFactory.getLog(OraclePluginLifecycleListener.class);
+ private static final Log LOG =
LogFactory.getLog(OraclePluginLifecycleListener.class);
public void initialize(PluginContext context) throws Exception {
// no-op
@@ -44,13 +45,17 @@ public class OraclePluginLifecycleListener implements
PluginLifecycleListener {
try {
Driver driver = drivers.nextElement();
DriverManager.deregisterDriver(driver);
- log.debug("Deregistered JDBC driver: " + driver.getClass());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Deregistered JDBC driver: " +
driver.getClass());
+ }
} catch (Exception e) {
- log.warn("Failed to deregister JDBC drivers - memory might
leak" + ThrowableUtil.getAllMessages(e));
+ LOG.warn("Failed to deregister JDBC drivers - memory might
leak" + ThrowableUtil.getAllMessages(e));
}
}
- log.debug(this.getClass().getSimpleName() + " completed shutdown.");
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(this.getClass().getSimpleName() + " completed
shutdown.");
+ }
return;
}
}
diff --git
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OraclePooledConnectionProvider.java
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OraclePooledConnectionProvider.java
new file mode 100644
index 0000000..b057a40
--- /dev/null
+++
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OraclePooledConnectionProvider.java
@@ -0,0 +1,71 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.plugins.oracle;
+
+import java.sql.Driver;
+import java.util.Properties;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.plugins.database.BasePooledConnectionProvider;
+
+/**
+ * An Oracle plugin adapted {@link org.rhq.plugins.database.PooledConnectionProvider}.
+ *
+ * @author Thomas Segismont
+ */
+public class OraclePooledConnectionProvider extends BasePooledConnectionProvider {
+
+ static final String DRIVER_CLASS_PROPERTY = "driverClass";
+ static final String PRINCIPAL_PROPERTY = "principal";
+ static final String CREDENTIALS_PROPERTY = "credentials";
+
+ public OraclePooledConnectionProvider(Configuration pluginConfig) throws Exception {
+ super(pluginConfig);
+ }
+
+ @Override
+ protected Class<Driver> getDriverClass() throws ClassNotFoundException {
+ return (Class<Driver>)
Class.forName(pluginConfig.getSimple(DRIVER_CLASS_PROPERTY).getStringValue());
+ }
+
+ @Override
+ protected String getJdbcUrl() {
+ return OracleServerComponent.buildUrl(pluginConfig);
+ }
+
+ @Override
+ protected String getUsername() {
+ return pluginConfig.getSimple(PRINCIPAL_PROPERTY).getStringValue();
+ }
+
+ @Override
+ protected String getPassword() {
+ return pluginConfig.getSimple(CREDENTIALS_PROPERTY).getStringValue();
+ }
+
+ @Override
+ protected Properties getConnectionProperties() {
+ Properties connectionProperties = super.getConnectionProperties();
+ if (getUsername().equalsIgnoreCase("SYS")) {
+ connectionProperties.put("internal_logon", "sysdba");
+ }
+ return connectionProperties;
+ }
+}
diff --git
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java
index 3849657..6e6b6b9 100644
---
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java
+++
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,20 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.oracle;
+import static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
+import static org.rhq.core.domain.measurement.AvailabilityType.UP;
+import static org.rhq.plugins.database.DatabasePluginUtil.getNumericQueryValueMap;
+import static org.rhq.plugins.database.DatabasePluginUtil.getSingleNumericQueryValue;
+import static
org.rhq.plugins.oracle.OraclePooledConnectionProvider.CREDENTIALS_PROPERTY;
+import static
org.rhq.plugins.oracle.OraclePooledConnectionProvider.DRIVER_CLASS_PROPERTY;
+import static org.rhq.plugins.oracle.OraclePooledConnectionProvider.PRINCIPAL_PROPERTY;
+
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
@@ -36,48 +45,69 @@ import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
-import org.rhq.core.util.jdbc.JDBCUtil;
+import org.rhq.plugins.database.ConnectionPoolingSupport;
import org.rhq.plugins.database.DatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
+import org.rhq.plugins.database.PooledConnectionProvider;
/**
* @author Greg Hinkle
*/
-public class OracleServerComponent implements DatabaseComponent, MeasurementFacet {
+public class OracleServerComponent implements DatabaseComponent,
ConnectionPoolingSupport, MeasurementFacet {
private static final Log LOG = LogFactory.getLog(OracleServerComponent.class);
- private Connection connection;
-
private ResourceContext resourceContext;
-
- private boolean started;
+ @Deprecated
+ private Connection connection;
+ private OraclePooledConnectionProvider pooledConnectionProvider;
public void start(ResourceContext resourceContext) throws
InvalidPluginConfigurationException, Exception {
this.resourceContext = resourceContext;
- this.connection = buildConnection(resourceContext.getPluginConfiguration());
- this.started = true;
+ buildSharedConnectionIfNeeded();
+ pooledConnectionProvider = new
OraclePooledConnectionProvider(resourceContext.getPluginConfiguration());
}
public void stop() {
removeConnection();
- this.started = false;
+ }
+
+ @Override
+ public boolean supportsConnectionPooling() {
+ return true;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return pooledConnectionProvider;
+ }
+
+ private void buildSharedConnectionIfNeeded() {
+ try {
+ if (this.connection == null || connection.isClosed()) {
+ this.connection =
buildConnection(this.resourceContext.getPluginConfiguration());
+ }
+ } catch (SQLException e) {
+ LOG.debug("Unable to create oracle connection", e);
+ }
}
public AvailabilityType getAvailability() {
- if (started && getConnection() != null) {
- return AvailabilityType.UP;
- } else {
- return AvailabilityType.DOWN;
+ Connection jdbcConnection = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ return jdbcConnection.isValid(1) ? UP : DOWN;
+ } catch (SQLException e) {
+ return DOWN;
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection);
}
}
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) throws Exception {
- Map<String, Double> values =
DatabaseQueryUtility.getNumericQueryValueMap(this,
- "SELECT name, value FROM V$SYSSTAT");
+ Map<String, Double> values = getNumericQueryValueMap(this, "SELECT
name, value FROM V$SYSSTAT");
for (MeasurementScheduleRequest request : metrics) {
if (request.getName().equals("totalSize")) {
- Double val = DatabaseQueryUtility.getSingleNumericQueryValue(this,
- "SELECT SUM(bytes) FROM SYS.DBA_DATA_FILES");
+ Double val = getSingleNumericQueryValue(this, "SELECT SUM(bytes)
FROM SYS.DBA_DATA_FILES");
report.addData(new MeasurementDataNumeric(request, val));
} else {
Double value = values.get(request.getName());
@@ -89,23 +119,17 @@ public class OracleServerComponent implements DatabaseComponent,
MeasurementFace
}
public Connection getConnection() {
- try {
- if (this.connection == null || connection.isClosed()) {
- this.connection =
buildConnection(this.resourceContext.getPluginConfiguration());
- }
- } catch (SQLException e) {
- LOG.info("Unable to create oracle connection", e);
- }
+ buildSharedConnectionIfNeeded();
return this.connection;
}
public void removeConnection() {
- JDBCUtil.safeClose(connection);
+ DatabasePluginUtil.safeClose(this.connection);
this.connection = null;
}
public static Connection buildConnection(Configuration configuration) throws
SQLException {
- String driverClass =
configuration.getSimple("driverClass").getStringValue();
+ String driverClass =
configuration.getSimple(DRIVER_CLASS_PROPERTY).getStringValue();
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
@@ -114,10 +138,12 @@ public class OracleServerComponent implements DatabaseComponent,
MeasurementFace
}
String url = buildUrl(configuration);
- LOG.debug("Attempting JDBC connection to [" + url + "]");
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Attempting JDBC connection to [" + url +
"]");
+ }
- String principal =
configuration.getSimple("principal").getStringValue();
- String credentials =
configuration.getSimple("credentials").getStringValue();
+ String principal = configuration.getSimple(PRINCIPAL_PROPERTY).getStringValue();
+ String credentials =
configuration.getSimple(CREDENTIALS_PROPERTY).getStringValue();
Properties props = new Properties();
props.put("user", principal);
@@ -129,7 +155,7 @@ public class OracleServerComponent implements DatabaseComponent,
MeasurementFace
return DriverManager.getConnection(url, props);
}
- private static String buildUrl(Configuration configuration) {
+ static String buildUrl(Configuration configuration) {
String connMethod = configuration.getSimpleValue("connectionMethod",
"SID");
if (connMethod.equalsIgnoreCase("SID")) {
return "jdbc:oracle:thin:@" +
configuration.getSimpleValue("host", "localhost") + ":"
@@ -139,4 +165,4 @@ public class OracleServerComponent implements DatabaseComponent,
MeasurementFace
+ configuration.getSimpleValue("port", "1521") +
"/" + configuration.getSimpleValue("sid", "XE");
}
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleTablespaceComponent.java
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleTablespaceComponent.java
index e99787b..e7e457e 100644
---
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleTablespaceComponent.java
+++
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleTablespaceComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,16 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.oracle;
+import static org.rhq.plugins.database.DatabasePluginUtil.getConnectionFromComponent;
+import static org.rhq.plugins.database.DatabasePluginUtil.getNumericQueryValues;
+
+import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -27,14 +32,14 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementReport;
import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
-import org.rhq.core.util.jdbc.JDBCUtil;
import org.rhq.plugins.database.AbstractDatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* Oracle Tablespace Component.
@@ -42,37 +47,38 @@ import org.rhq.plugins.database.DatabaseQueryUtility;
* @author Richard Hensman
*/
public class OracleTablespaceComponent extends AbstractDatabaseComponent implements
MeasurementFacet {
+ private static final Log LOG = LogFactory.getLog(OracleTablespaceComponent.class);
private static final String SQL_AVAILABLE = "SELECT COUNT(*) FROM
dba_tablespaces WHERE tablespace_name = ?";
- private static final String SQL_VALUES =
- "SELECT USED_SPACE usedSpace, TABLESPACE_SIZE totalSize, (USED_PERCENT/100)
usedPercent " +
- "FROM dba_tablespace_usage_metrics where tablespace_name = ?";
-
-
- private static Log log = LogFactory.getLog(OracleTablespaceComponent.class);
+ private static final String SQL_VALUES = "SELECT USED_SPACE usedSpace,
TABLESPACE_SIZE totalSize, (USED_PERCENT/100) usedPercent "
+ + "FROM dba_tablespace_usage_metrics where tablespace_name = ?";
public AvailabilityType getAvailability() {
+ Connection jdbcConnection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
- statement = getConnection().prepareStatement(SQL_AVAILABLE);
+ jdbcConnection = getConnectionFromComponent(this);
+ statement = jdbcConnection.prepareStatement(SQL_AVAILABLE);
statement.setString(1, this.resourceContext.getResourceKey());
resultSet = statement.executeQuery();
if (resultSet.next() && (resultSet.getInt(1) == 1)) {
return AvailabilityType.UP;
}
} catch (SQLException e) {
- log.debug("unable to query", e);
+ LOG.debug("unable to query", e);
} finally {
- JDBCUtil.safeClose(statement, resultSet);
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
+ if (supportsConnectionPooling()) {
+ DatabasePluginUtil.safeClose(jdbcConnection);
+ }
}
return AvailabilityType.DOWN;
}
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) throws Exception {
- Map<String, Double> values =
DatabaseQueryUtility.getNumericQueryValues(this, SQL_VALUES,
- this.resourceContext.getResourceKey());
+ Map<String, Double> values = getNumericQueryValues(this, SQL_VALUES,
this.resourceContext.getResourceKey());
for (MeasurementScheduleRequest request : metrics) {
Double d = values.get(request.getName().toUpperCase(Locale.US));
if (d != null) {
@@ -80,4 +86,4 @@ public class OracleTablespaceComponent extends AbstractDatabaseComponent
impleme
}
}
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java
index 49999fd..63b9985 100644
---
a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java
+++
b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,16 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.oracle;
+import static org.rhq.plugins.database.DatabasePluginUtil.getConnectionFromComponent;
+import static org.rhq.plugins.database.DatabasePluginUtil.getNumericQueryValues;
+
+import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -27,50 +32,51 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementReport;
import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
-import org.rhq.core.util.jdbc.JDBCUtil;
import org.rhq.plugins.database.AbstractDatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* @author Greg Hinkle
*/
public class OracleUserComponent extends AbstractDatabaseComponent implements
MeasurementFacet {
+ private static final Log LOG = LogFactory.getLog(OracleUserComponent.class);
private static final String SQL_USER = "SELECT COUNT(*) FROM DBA_USERS WHERE
username = ?";
- private static final String SESSIONS =
- "SELECT SUM(DECODE(Status, 'ACTIVE', 1, 0)) active, COUNT(1)
connections " +
- "FROM V$SESSION where username = ?";
-
-
- private static Log log = LogFactory.getLog(OracleUserComponent.class);
+ private static final String SESSIONS = "SELECT SUM(DECODE(Status,
'ACTIVE', 1, 0)) active, COUNT(1) connections "
+ + "FROM V$SESSION where username = ?";
public AvailabilityType getAvailability() {
+ Connection jdbcConnection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
- statement = getConnection().prepareStatement(SQL_USER);
+ jdbcConnection = getConnectionFromComponent(this);
+ statement = jdbcConnection.prepareStatement(SQL_USER);
statement.setString(1, this.resourceContext.getResourceKey());
resultSet = statement.executeQuery();
if (resultSet.next() && (resultSet.getInt(1) == 1)) {
return AvailabilityType.UP;
}
} catch (SQLException e) {
- log.debug("unable to query", e);
+ LOG.debug("unable to query", e);
} finally {
- JDBCUtil.safeClose(statement, resultSet);
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
+ if (supportsConnectionPooling()) {
+ DatabasePluginUtil.safeClose(jdbcConnection);
+ }
}
return AvailabilityType.DOWN;
}
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) throws Exception {
- Map<String, Double> values =
DatabaseQueryUtility.getNumericQueryValues(this, SESSIONS,
- this.resourceContext.getResourceKey());
+ Map<String, Double> values = getNumericQueryValues(this, SESSIONS,
this.resourceContext.getResourceKey());
for (MeasurementScheduleRequest request : metrics) {
Double d = values.get(request.getName().toUpperCase(Locale.US));
if (d != null) {
@@ -78,4 +84,4 @@ public class OracleUserComponent extends AbstractDatabaseComponent
implements Me
}
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml
b/modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml
index b8ac5cb..4820785 100644
--- a/modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml
@@ -641,14 +641,6 @@
discovery="org.rhq.plugins.oracle.OracleAsmDiskGroupDiscoveryComponent"
class="org.rhq.plugins.oracle.OracleAsmDiskGroupComponent">
- <!--plugin-configuration>
- <c:simple-property name="table"
default="V$ASM_DISKGROUP"/>
- <c:simple-property name="metricQuery" default="SELECT {key}
FROM V$ASM_DISKGROUP"/>
- <c:simple-property name="keyColumn"
default="GROUP_NUMBER"/>
- <c:simple-property name="name" default="NAME"/>
- <c:simple-property name="description" default="Oracle ASM
Disk Groups"/>
- </plugin-configuration -->
-
<metric property="sectorSize" displayName="Sector Size"
description="Physical block size (in bytes)" units="bytes"
dataType="trait"/>
<metric property="blockSize" displayName="Block Size"
description="Automatic Storage Management metadata block size (in bytes)"
units="bytes" dataType="trait"/>
<metric property="allocationUnitSize" displayName="Allocation
Unit Size" description="Size of the allocation unit (in bytes)"
units="bytes" dataType="trait"/>
diff --git
a/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/ComponentTest.java
b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/ComponentTest.java
index e98c2e9..346565b 100644
--- a/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/ComponentTest.java
+++ b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/ComponentTest.java
@@ -1,3 +1,22 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
package org.rhq.plugins.oracle;
import static org.testng.AssertJUnit.assertEquals;
diff --git
a/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
index d9d2fb0..dfb16ac 100644
---
a/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
+++
b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
@@ -1,3 +1,22 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
package org.rhq.plugins.oracle;
import static org.testng.AssertJUnit.assertNotNull;
@@ -6,15 +25,16 @@ import static org.testng.AssertJUnit.assertTrue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.rhq.core.domain.configuration.Configuration;
-import org.rhq.core.domain.measurement.MeasurementReport;
-import org.rhq.core.domain.resource.ResourceType;
-import org.rhq.core.pluginapi.inventory.ResourceComponent;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.measurement.MeasurementReport;
+import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
+
public class OracleServerComponentTest extends ComponentTest {
private static final String ORACLE_SERVER = "Oracle Server";
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseComponent.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseComponent.java
index f235f93..ec58833 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseComponent.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,20 +13,29 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres;
+import static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
+import static org.rhq.core.domain.measurement.AvailabilityType.UP;
+import static org.rhq.core.domain.resource.CreateResourceStatus.FAILURE;
+import static org.rhq.core.domain.resource.CreateResourceStatus.SUCCESS;
+import static org.rhq.plugins.postgres.PostgresDiscoveryComponent.buildConnection;
+
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
-import java.sql.ResultSetMetaData;
import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
@@ -36,43 +45,71 @@ import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementReport;
import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
-import org.rhq.core.domain.resource.CreateResourceStatus;
import org.rhq.core.pluginapi.inventory.CreateChildResourceFacet;
import org.rhq.core.pluginapi.inventory.CreateResourceReport;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
-import org.rhq.core.util.jdbc.JDBCUtil;
+import org.rhq.plugins.database.ConnectionPoolingSupport;
import org.rhq.plugins.database.DatabaseComponent;
+import org.rhq.plugins.database.DatabasePluginUtil;
+import org.rhq.plugins.database.PooledConnectionProvider;
-public class PostgresDatabaseComponent implements
DatabaseComponent<PostgresServerComponent<?>>, MeasurementFacet,
- CreateChildResourceFacet, OperationFacet {
- private Log log = LogFactory.getLog(PostgresDatabaseComponent.class);
+public class PostgresDatabaseComponent implements
DatabaseComponent<PostgresServerComponent<?>>,
+ ConnectionPoolingSupport, MeasurementFacet, CreateChildResourceFacet, OperationFacet
{
- private ResourceContext<PostgresServerComponent<?>> resourceContext;
+ private static final Log LOG = LogFactory.getLog(PostgresDatabaseComponent.class);
- private Connection databaseConnection;
+ private static final String QUERY_DATABASE_SIZE = "SELECT *,
pg_database_size(datname) AS size FROM pg_stat_database where datname = ?";
+ private ResourceContext<PostgresServerComponent<?>> resourceContext;
private String databaseName;
+ private PostgresServerComponent<?> postgresServerComponent;
+ private boolean useOwnJdbcConnections;
+ @Deprecated
+ private Connection databaseConnection;
+ private PostgresPooledConnectionProvider pooledConnectionProvider;
+
+ public void start(ResourceContext<PostgresServerComponent<?>> context)
throws Exception {
+ this.resourceContext = context;
+ databaseName =
resourceContext.getPluginConfiguration().getSimple("databaseName").getStringValue();
+ postgresServerComponent = resourceContext.getParentResourceComponent();
+ useOwnJdbcConnections =
!databaseName.equals(postgresServerComponent.getResourceContext()
+ .getPluginConfiguration().getSimple("db").getStringValue());
+ if (useOwnJdbcConnections) {
+ buildDatabaseConnectionIfNeeded();
+ pooledConnectionProvider = new
PostgresPooledConnectionProvider(createDatabaseSpecificConfig());
+ }
+ }
+
+ public void stop() {
+ this.resourceContext = null;
+ databaseName = null;
+ postgresServerComponent = null;
+ if (useOwnJdbcConnections) {
+ DatabasePluginUtil.safeClose(databaseConnection);
+ databaseConnection = null;
+ pooledConnectionProvider.close();
+ pooledConnectionProvider = null;
+ }
+ }
+
+ @Override
+ public boolean supportsConnectionPooling() {
+ return true;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return useOwnJdbcConnections ? pooledConnectionProvider :
postgresServerComponent.getPooledConnectionProvider();
+ }
public Connection getConnection() {
- this.databaseName =
resourceContext.getPluginConfiguration().getSimple("databaseName").getStringValue();
- if
(this.databaseName.equals(resourceContext.getParentResourceComponent().getResourceContext()
- .getPluginConfiguration().getSimple("db").getStringValue())) {
- return resourceContext.getParentResourceComponent().getConnection();
+ if (useOwnJdbcConnections) {
+ return postgresServerComponent.getConnection();
} else {
- // ??? Need to use a different connection to talk to a different db?
- if (this.databaseConnection == null) {
- Configuration config =
resourceContext.getParentResourceComponent().getResourceContext()
- .getPluginConfiguration();
- config = config.deepCopy();
- config.put(new PropertySimple("db", databaseName));
- log.debug("Getting db specific connection to postgres for [" +
databaseName + "] database");
- this.databaseConnection =
PostgresDiscoveryComponent.buildConnection(config, true);
- }
-
- // TODO GH: Attempt to load other db connections? or only monitor this dbs
stuff? Weird situation.
+ buildDatabaseConnectionIfNeeded();
return this.databaseConnection;
}
}
@@ -82,23 +119,47 @@ public class PostgresDatabaseComponent implements
DatabaseComponent<PostgresServ
if ((this.databaseConnection != null) &&
!this.databaseConnection.isClosed()) {
this.databaseConnection.close();
}
- } catch (SQLException se) {
- log.debug("Closing and removing postgres connection");
+ } catch (SQLException e) {
+ LOG.debug("Could not remove connection", e);
}
-
this.databaseConnection = null;
}
- public void start(ResourceContext<PostgresServerComponent<?>> context) {
- this.resourceContext = context;
+ private void buildDatabaseConnectionIfNeeded() {
+ try {
+ if (this.databaseConnection == null || this.databaseConnection.isClosed()) {
+ this.databaseConnection = buildConnection(createDatabaseSpecificConfig(),
true);
+ }
+ } catch (SQLException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Could not build shared connection", e);
+ }
+ }
}
- public void stop() {
- this.resourceContext = null;
+ private Configuration createDatabaseSpecificConfig() {
+ Configuration config =
postgresServerComponent.getResourceContext().getPluginConfiguration();
+ config = config.deepCopy();
+ config.put(new PropertySimple("db", databaseName));
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Getting db specific connection to postgres for [" +
databaseName + "] database");
+ }
+ return config;
}
public AvailabilityType getAvailability() {
- return resourceContext.getParentResourceComponent().getAvailability();
+ if (useOwnJdbcConnections) {
+ Connection jdbcConnection = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ return jdbcConnection.isValid(1) ? UP : DOWN;
+ } catch (SQLException e) {
+ return DOWN;
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection);
+ }
+ }
+ return postgresServerComponent.getAvailability();
}
public String getDatabaseName() {
@@ -106,35 +167,27 @@ public class PostgresDatabaseComponent implements
DatabaseComponent<PostgresServ
}
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) {
+ Connection jdbcConnection = null;
PreparedStatement statement = null;
+ ResultSet resultSet = null;
try {
- statement =
this.resourceContext.getParentResourceComponent().getConnection().prepareStatement(
- "SELECT *, pg_database_size(datname) AS size FROM pg_stat_database
where datname = ?");
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.prepareStatement(QUERY_DATABASE_SIZE);
statement.setString(1,
this.resourceContext.getPluginConfiguration().getSimple("databaseName")
.getStringValue());
- ResultSet results = statement.executeQuery();
- try {
- if (!results.next()) {
- throw new RuntimeException("Couldn't get the data"); //
TODO Error handling system
- }
-
- for (MeasurementScheduleRequest request : metrics) {
- // Only size expected
- double val = results.getDouble(request.getName());
- report.addData(new MeasurementDataNumeric(request, val));
- }
- } finally {
- results.close();
+ resultSet = statement.executeQuery();
+ if (!resultSet.next()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Result set is empty: " + QUERY_DATABASE_SIZE);
+ }
+ }
+ for (MeasurementScheduleRequest request : metrics) {
+ report.addData(new MeasurementDataNumeric(request,
resultSet.getDouble(request.getName())));
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
- try {
- if (statement != null) {
- statement.close();
- }
- } catch (SQLException e) {
- }
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
}
@@ -188,7 +241,8 @@ public class PostgresDatabaseComponent implements
DatabaseComponent<PostgresServ
buf.append("\n)");
- log.info("Creating table with: " + buf.toString());
+ String createTableSql = buf.toString();
+ LOG.info("Creating table with: " + createTableSql);
PropertyList constraintList = configuration.getList("constraints");
if (constraintList != null) {
for (Property c : constraintList.getList()) {
@@ -197,99 +251,105 @@ public class PostgresDatabaseComponent implements
DatabaseComponent<PostgresServ
}
}
+ Connection jdbcConnection = null;
Statement statement = null;
try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ statement.executeUpdate(createTableSql);
+ report.setStatus(SUCCESS);
report.setResourceKey(tableName);
- statement = getConnection().createStatement();
- statement.executeUpdate(buf.toString());
- report.setStatus(CreateResourceStatus.SUCCESS);
report.setResourceName(tableName);
} catch (SQLException e) {
report.setException(e);
- report.setStatus(CreateResourceStatus.FAILURE);
+ report.setStatus(FAILURE);
} finally {
- JDBCUtil.safeClose(statement);
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, null);
}
return report;
}
- public OperationResult invokeOperation(String name, Configuration parameters)
- throws InterruptedException, Exception {
-
+ public OperationResult invokeOperation(String name, Configuration parameters) throws
InterruptedException,
+ Exception {
if ("resetStatistics".equals(name)) {
- Statement stmt = null;
- ResultSet rs = null;
- try {
- stmt = getConnection().createStatement();
- rs = stmt.executeQuery("select * from pg_stat_reset()");
-
- } finally {
- if (rs != null) {
- rs.close();
- }
-
- if (stmt != null) {
- stmt.close();
- }
- }
- return null;
+ return resetStatistics();
} else if ("invokeSql".equals(name)) {
- Statement stmt = null;
- ResultSet rs = null;
- try {
- stmt = getConnection().createStatement();
- String sql = parameters.getSimple("sql").getStringValue();
- OperationResult result = new OperationResult();
-
- if
(parameters.getSimple("type").getStringValue().equals("update")) {
- int updateCount = stmt.executeUpdate(sql);
- result.getComplexResults().put(new PropertySimple("result",
"Query updated " + updateCount + " rows"));
+ return invokeSql(parameters);
+ } else {
+ throw new UnsupportedOperationException("Operation [" + name +
"] is not supported yet.");
+ }
+ }
- } else {
- rs =
stmt.executeQuery(parameters.getSimple("sql").getStringValue());
+ private OperationResult resetStatistics() {
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("select * from
pg_stat_reset()");
+ return null; // does not return results
+ } catch (SQLException e) {
+ OperationResult result = new OperationResult("Failed to reset
statistics");
+ result.setErrorMessage(e.getMessage());
+ return result;
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
+ }
+ }
- ResultSetMetaData md = rs.getMetaData();
- StringBuilder buf = new StringBuilder();
- int rowCount = 0;
+ private OperationResult invokeSql(Configuration parameters) throws SQLException {
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ String sql = parameters.getSimple("sql").getStringValue();
+
+ OperationResult result = new OperationResult();
+ if
(parameters.getSimple("type").getStringValue().equals("update")) {
+ int updateCount = statement.executeUpdate(sql);
+ result.getComplexResults().put(new PropertySimple("result",
"Query updated " + updateCount + " rows"));
+ } else {
+ resultSet = statement.executeQuery(sql);
+
+ ResultSetMetaData md = resultSet.getMetaData();
+ StringBuilder buf = new StringBuilder();
+ int rowCount = 0;
+
+ buf.append("<table>");
+ buf.append("<th>");
+ for (int i = 1; i <= md.getColumnCount(); i++) {
+ buf.append("<td>");
+ buf.append(md.getColumnName(i) + " (" +
md.getColumnTypeName(i) + ")");
+ buf.append("</td>");
+ }
+ buf.append("</th>");
- buf.append("<table>");
- buf.append("<th>");
+ while (resultSet.next()) {
+ rowCount++;
+ buf.append("<tr>");
for (int i = 1; i <= md.getColumnCount(); i++) {
buf.append("<td>");
- buf.append(md.getColumnName(i) + " (" +
md.getColumnTypeName(i) + ")");
+ buf.append(resultSet.getString(i));
buf.append("</td>");
}
- buf.append("</th>");
-
-
- while (rs.next()) {
- rowCount++;
- buf.append("<tr>");
- for (int i = 1; i <= md.getColumnCount(); i++) {
- buf.append("<td>");
- buf.append(rs.getString(i));
- buf.append("</td>");
- }
- buf.append("</tr>");
- }
-
- buf.append("</table>");
- result.getComplexResults().put(new PropertySimple("result",
"Query returned " + rowCount + " rows"));
- result.getComplexResults().put(new
PropertySimple("contents", buf.toString()));
- }
- return result;
- } finally {
- if (rs != null) {
- rs.close();
+ buf.append("</tr>");
}
- if (stmt != null) {
- stmt.close();
- }
+ buf.append("</table>");
+ result.getComplexResults().put(new PropertySimple("result",
"Query returned " + rowCount + " rows"));
+ result.getComplexResults().put(new PropertySimple("contents",
buf.toString()));
}
- } else {
- throw new UnsupportedOperationException("Operation [" + name +
"] is not supported yet.");
+ return result;
+ } catch (SQLException e) {
+ OperationResult result = new OperationResult("Failed to invoke
SQL");
+ result.setErrorMessage(e.getMessage());
+ return result;
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseDiscoveryComponent.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseDiscoveryComponent.java
index cfc60b2..d4c89dc 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseDiscoveryComponent.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDatabaseDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,13 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres;
+import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashSet;
@@ -27,7 +29,7 @@ import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.util.jdbc.JDBCUtil;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* @author Greg Hinkle
@@ -37,10 +39,12 @@ public class PostgresDatabaseDiscoveryComponent implements
ResourceDiscoveryComp
throws Exception {
Set<DiscoveredResourceDetails> databases = new
HashSet<DiscoveredResourceDetails>();
+ Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
- statement =
context.getParentResourceComponent().getConnection().createStatement();
+ connection =
context.getParentResourceComponent().getPooledConnectionProvider().getPooledConnection();
+ statement = connection.createStatement();
resultSet = statement
.executeQuery("SELECT *, pg_database_size(datname) FROM pg_database
where datistemplate = false");
while (resultSet.next()) {
@@ -51,9 +55,9 @@ public class PostgresDatabaseDiscoveryComponent implements
ResourceDiscoveryComp
databases.add(database);
}
} finally {
- JDBCUtil.safeClose(statement, resultSet);
+ DatabasePluginUtil.safeClose(connection, statement, resultSet);
}
return databases;
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDiscoveryComponent.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDiscoveryComponent.java
index b62c029..59150c4 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDiscoveryComponent.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres;
import java.io.File;
@@ -39,6 +40,7 @@ import org.apache.commons.logging.LogFactory;
import org.hyperic.sigar.ProcExe;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
@@ -51,7 +53,7 @@ import org.rhq.core.system.ProcessExecution;
import org.rhq.core.system.ProcessExecutionResults;
import org.rhq.core.system.ProcessInfo;
import org.rhq.core.system.SystemInfo;
-import org.rhq.core.util.jdbc.JDBCUtil;
+import org.rhq.plugins.database.DatabasePluginUtil;
import org.rhq.plugins.postgres.util.PostgresqlConfFile;
/**
@@ -59,8 +61,7 @@ import org.rhq.plugins.postgres.util.PostgresqlConfFile;
* @author Ian Springer
*/
public class PostgresDiscoveryComponent implements ResourceDiscoveryComponent,
ManualAddFacet {
-
- private static final Log log = LogFactory.getLog(PostgresDiscoveryComponent.class);
+ private static final Log LOG = LogFactory.getLog(PostgresDiscoveryComponent.class);
public static final String PGDATA_DIR_CONFIGURATION_PROPERTY =
"pgdataDir";
public static final String CONFIG_FILE_CONFIGURATION_PROPERTY =
"configFile";
@@ -82,15 +83,15 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
// Process any auto-discovered resources.
List<ProcessScanResult> autoDiscoveryResults =
context.getAutoDiscoveredProcesses();
for (ProcessScanResult result : autoDiscoveryResults) {
- log.info("Discovered a postgres process: " + result);
+ LOG.info("Discovered a postgres process: " + result);
ProcessInfo procInfo = result.getProcessInfo();
String pgDataPath = getDataDirPath(procInfo);
if (pgDataPath == null) {
- log.error("Unable to obtain data directory for postgres process with
pid " + procInfo.getPid()
- + " (tried checking both -D command line argument, as well as
" + PGDATA_ENV_VAR
- + " environment variable).");
+ LOG.error("Unable to obtain data directory for postgres process with
pid " + procInfo.getPid()
+ + " (tried checking both -D command line argument, as well
as " + PGDATA_ENV_VAR
+ + " environment variable).");
continue;
}
@@ -99,26 +100,28 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
PostgresqlConfFile confFile = null;
if (!pgData.exists()) {
- log.warn("PostgreSQL data directory (" + pgData + ") does
not exist or is not readable. "
+ LOG.warn("PostgreSQL data directory ("
+ + pgData
+ + ") does not exist or is not readable. "
+ "Make sure the user the RHQ Agent is running as has read
permissions on the directory and its parent directory.");
} else {
- log.debug("PostgreSQL data directory: " + pgData);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("PostgreSQL data directory: " + pgData);
+ }
File postgresConfFile = (configFilePath != null) ? new
File(configFilePath) : new File(pgData,
PostgresServerComponent.DEFAULT_CONFIG_FILE_NAME);
- log.debug("PostgreSQL configuration file: " +
postgresConfFile);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("PostgreSQL configuration file: " +
postgresConfFile);
+ }
if (!postgresConfFile.exists()) {
- log.warn("PostgreSQL configuration file (" +
postgresConfFile + ") does not exist.");
+ LOG.warn("PostgreSQL configuration file (" +
postgresConfFile + ") does not exist.");
} else {
try {
confFile = new PostgresqlConfFile(postgresConfFile);
} catch (IOException e) {
- if (log.isDebugEnabled()) {
- log.debug("Could not load PostgreSQL configuration file
[" + postgresConfFile + "].", e);
- } else {
- log.warn("Could not load PostgreSQL configuration file
[" + postgresConfFile + "]: " + e);
- }
+ LOG.warn("Could not load PostgreSQL configuration file
[" + postgresConfFile + "]: " + e);
}
}
}
@@ -167,14 +170,19 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
}
protected static DiscoveredResourceDetails
createResourceDetails(ResourceDiscoveryContext discoveryContext,
- Configuration pluginConfiguration, @Nullable ProcessInfo processInfo, boolean
logConnectionFailure) {
+ Configuration pluginConfiguration, @Nullable
+ ProcessInfo processInfo, boolean logConnectionFailure) {
String key = buildUrl(pluginConfiguration);
- Connection conn = buildConnection(pluginConfiguration, logConnectionFailure);
- String name = getServerResourceName(pluginConfiguration, conn);
- String version = getVersion(processInfo, discoveryContext.getSystemInformation(),
conn);
- JDBCUtil.safeClose(conn);
- return new DiscoveredResourceDetails(discoveryContext.getResourceType(), key,
name, version,
- DEFAULT_RESOURCE_DESCRIPTION, pluginConfiguration, processInfo);
+ Connection conn = null;
+ try {
+ conn = buildConnection(pluginConfiguration, logConnectionFailure);
+ String name = getServerResourceName(pluginConfiguration, conn);
+ String version = getVersion(processInfo,
discoveryContext.getSystemInformation(), conn);
+ return new DiscoveredResourceDetails(discoveryContext.getResourceType(), key,
name, version,
+ DEFAULT_RESOURCE_DESCRIPTION, pluginConfiguration, processInfo);
+ } finally {
+ DatabasePluginUtil.safeClose(conn);
+ }
}
protected static String buildUrl(Configuration config) {
@@ -193,7 +201,7 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
}
} catch (SQLException e) {
// TODO GH: How to put this back to the server while inventorying this
resource in an unconfigured state
- log.info("Exception detecting postgres instance version.", e);
+ LOG.info("Exception detecting postgres instance version.", e);
}
//now try to extract the version information by asking the server executable
itself
@@ -211,11 +219,11 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
if (m.find()) {
version = versionInfo.substring(m.start(), m.end());
} else {
- log.debug("Can't get the process executable - does the
agent have the right permissions?");
+ LOG.debug("Can't get the process executable - does the
agent have the right permissions?");
}
}
} catch (Exception e) {
- log.info("Failed to obtain Postgres version information from the
executable file.", e);
+ LOG.info("Failed to obtain Postgres version information from the
executable file.", e);
}
}
@@ -240,16 +248,19 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
return DriverManager.getConnection(url, principal, credentials);
} catch (SQLException e) {
if (logFailure) {
- log.info("Failed to connect to the database: " +
e.getMessage());
+ LOG.info("Failed to connect to the database: " +
e.getMessage());
} else {
- log.debug("Failed to connect to the database: " +
e.getMessage());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Failed to connect to the database: " +
e.getMessage());
+ }
}
return null;
}
}
@Nullable
- protected static String getDataDirPath(@NotNull ProcessInfo procInfo) {
+ protected static String getDataDirPath(@NotNull
+ ProcessInfo procInfo) {
String dataDirPath = null;
String[] cmdLine = procInfo.getCommandLine();
for (int i = 0; i < cmdLine.length; i++) {
@@ -258,7 +269,7 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
dataDirPath = cmdLine[i + 1];
break;
} else {
- log.error("-D option was last option on postgres command line:
" + Arrays.asList(cmdLine));
+ LOG.error("-D option was last option on postgres command line:
" + Arrays.asList(cmdLine));
}
}
}
@@ -274,7 +285,8 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
}
@Nullable
- private static String getConfigFilePath(@NotNull ProcessInfo procInfo) {
+ private static String getConfigFilePath(@NotNull
+ ProcessInfo procInfo) {
String configFilePath = null;
String[] cmdLine = procInfo.getCommandLine();
for (int i = 0; i < cmdLine.length; i++) {
@@ -283,8 +295,8 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
String paramString = cmdLine[i + 1];
int equalsIndex = paramString.indexOf('=');
if (equalsIndex == -1) {
- log.error("Invalid value '" + paramString +
"' for -c option on postgres command line: "
- + Arrays.asList(cmdLine));
+ LOG.error("Invalid value '" + paramString +
"' for -c option on postgres command line: "
+ + Arrays.asList(cmdLine));
continue;
}
@@ -294,7 +306,7 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
break;
}
} else {
- log.error("-c option was last option on postgres command line:
" + Arrays.asList(cmdLine));
+ LOG.error("-c option was last option on postgres command line:
" + Arrays.asList(cmdLine));
}
}
}
@@ -303,13 +315,12 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
}
private static List<String> getDatabaseNames(Connection conn) {
- Statement statement = null;
- ResultSet resultSet = null;
-
if (conn == null) {
return Collections.emptyList();
}
+ Statement statement = null;
+ ResultSet resultSet = null;
try {
List<String> ret = new ArrayList<String>();
@@ -323,10 +334,10 @@ public class PostgresDiscoveryComponent implements
ResourceDiscoveryComponent, M
return ret;
} catch (SQLException e) {
- log.info("Failed to obtain the list of databases in a postgres
instance", e);
+ LOG.error("Failed to obtain the list of databases in a postgres
instance", e);
return Collections.emptyList();
} finally {
- JDBCUtil.safeClose(statement, resultSet);
+ DatabasePluginUtil.safeClose(null, statement, resultSet);
}
}
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresPluginLifecycleListener.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresPluginLifecycleListener.java
index 526caeb..d651506 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresPluginLifecycleListener.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresPluginLifecycleListener.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres;
import java.sql.Driver;
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresPooledConnectionProvider.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresPooledConnectionProvider.java
new file mode 100644
index 0000000..c505bae
--- /dev/null
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresPooledConnectionProvider.java
@@ -0,0 +1,62 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.plugins.postgres;
+
+import static
org.rhq.plugins.postgres.PostgresDiscoveryComponent.CREDENTIALS_CONFIGURATION_PROPERTY;
+import static
org.rhq.plugins.postgres.PostgresDiscoveryComponent.DRIVER_CONFIGURATION_PROPERTY;
+import static
org.rhq.plugins.postgres.PostgresDiscoveryComponent.PRINCIPAL_CONFIGURATION_PROPERTY;
+import static org.rhq.plugins.postgres.PostgresDiscoveryComponent.buildUrl;
+
+import java.sql.Driver;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.plugins.database.BasePooledConnectionProvider;
+
+/**
+ * A Postgres plugin adapated {@link org.rhq.plugins.database.PooledConnectionProvider}
+ *
+ * @author Thomas Segismont
+ */
+public class PostgresPooledConnectionProvider extends BasePooledConnectionProvider {
+
+ public PostgresPooledConnectionProvider(Configuration pluginConfig) throws Exception
{
+ super(pluginConfig);
+ }
+
+ @Override
+ protected Class<Driver> getDriverClass() throws ClassNotFoundException {
+ return (Class<Driver>)
Class.forName(pluginConfig.getSimple(DRIVER_CONFIGURATION_PROPERTY).getStringValue());
+ }
+
+ @Override
+ protected String getJdbcUrl() {
+ return buildUrl(pluginConfig);
+ }
+
+ @Override
+ protected String getPassword() {
+ return
pluginConfig.getSimple(CREDENTIALS_CONFIGURATION_PROPERTY).getStringValue();
+ }
+
+ @Override
+ protected String getUsername() {
+ return
pluginConfig.getSimple(PRINCIPAL_CONFIGURATION_PROPERTY).getStringValue();
+ }
+}
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresServerComponent.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresServerComponent.java
index d132598..3fb7354 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresServerComponent.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresServerComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,15 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres;
+import static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
+import static org.rhq.core.domain.measurement.AvailabilityType.UP;
+
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
@@ -61,8 +65,10 @@ import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
import org.rhq.core.system.AggregateProcessInfo;
import org.rhq.core.system.ProcessInfo;
-import org.rhq.core.util.jdbc.JDBCUtil;
+import org.rhq.plugins.database.ConnectionPoolingSupport;
import org.rhq.plugins.database.DatabaseComponent;
+import org.rhq.plugins.database.DatabasePluginUtil;
+import org.rhq.plugins.database.PooledConnectionProvider;
import org.rhq.plugins.postgres.util.PostgresqlConfFile;
/**
@@ -70,43 +76,48 @@ import org.rhq.plugins.postgres.util.PostgresqlConfFile;
*
* @author Greg Hinkle
*/
-public class PostgresServerComponent<T extends ResourceComponent<?>>
implements DatabaseComponent<T>, ConfigurationFacet, MeasurementFacet,
- OperationFacet, CreateChildResourceFacet {
+public class PostgresServerComponent<T extends ResourceComponent<?>>
implements DatabaseComponent<T>,
+ ConnectionPoolingSupport, ConfigurationFacet, MeasurementFacet, OperationFacet,
CreateChildResourceFacet {
- private static Log log = LogFactory.getLog(PostgresServerComponent.class);
+ private static final Log LOG = LogFactory.getLog(PostgresServerComponent.class);
- private Connection connection;
+ static final String DEFAULT_CONFIG_FILE_NAME = "postgresql.conf";
private AggregateProcessInfo aggregateProcessInfo;
-
+ @Deprecated
+ private Connection connection;
private ResourceContext resourceContext;
+ private PostgresPooledConnectionProvider pooledConnectionProvider;
- static final String DEFAULT_CONFIG_FILE_NAME = "postgresql.conf";
-
- /*
- * TODO: Other things to support active sessions: select * from pg_stat_activity
- */
-
- public void start(ResourceContext context) throws SQLException {
+ public void start(ResourceContext context) throws Exception {
this.resourceContext = context;
- Configuration config = context.getPluginConfiguration();
-
- JDBCUtil.safeClose(this.connection); // just to be sure we don't leak a
connection
- this.connection = PostgresDiscoveryComponent.buildConnection(config, true);
-
+ buildSharedConnectionIfNeeded();
+ pooledConnectionProvider = new
PostgresPooledConnectionProvider(resourceContext.getPluginConfiguration());
ProcessInfo processInfo = resourceContext.getNativeProcess();
if (processInfo != null) {
aggregateProcessInfo = processInfo.getAggregateProcessTree();
} else {
findProcessInfo();
- //log.debug("Unable to locate native process information. Process level
statistics will be unavailable.");
}
}
public void stop() {
- this.resourceContext = null;
- JDBCUtil.safeClose(this.connection);
- this.connection = null;
+ resourceContext = null;
+ DatabasePluginUtil.safeClose(connection);
+ connection = null;
+ pooledConnectionProvider.close();
+ pooledConnectionProvider = null;
+ aggregateProcessInfo = null;
+ }
+
+ @Override
+ public boolean supportsConnectionPooling() {
+ return true;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return pooledConnectionProvider;
}
protected String getJDBCUrl() {
@@ -114,15 +125,15 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
}
public AvailabilityType getAvailability() {
- AvailabilityType type;
- getConnection(); // This retries the connection if its null
- if (connection == null) {
- type = AvailabilityType.DOWN;
- } else {
- type = AvailabilityType.UP;
+ Connection jdbcConnection = null;
+ try {
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ return jdbcConnection.isValid(1) ? UP : DOWN;
+ } catch (SQLException e) {
+ return DOWN;
+ } finally {
+ DatabasePluginUtil.safeClose(jdbcConnection);
}
-
- return type;
}
ResourceContext getResourceContext() {
@@ -130,20 +141,25 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
}
public Connection getConnection() {
- // TODO: This method should probably be synchronized to prevent connection leaks.
(ips, 10/4/07)
+ buildSharedConnectionIfNeeded();
+ return connection;
+ }
+
+ private void buildSharedConnectionIfNeeded() {
try {
if ((connection == null) || connection.isClosed()) {
- connection =
PostgresDiscoveryComponent.buildConnection(this.resourceContext.getPluginConfiguration(),
true);
+ connection =
PostgresDiscoveryComponent.buildConnection(this.resourceContext.getPluginConfiguration(),
+ true);
}
} catch (SQLException e) {
- // TODO Should we throw this?
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Could not build shared connection", e);
+ }
}
-
- return connection;
}
public void removeConnection() {
- JDBCUtil.safeClose(this.connection);
+ DatabasePluginUtil.safeClose(this.connection);
this.connection = null;
}
@@ -177,12 +193,12 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
}
// Runtime settings (session params) - obtained via SQL.
- // TODO (ips, 05/16/12): We should move these to a separate Resource, since they
are loaded via a completely
- // separate mechanism than the static config above.
+ Connection jdbcConnection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
- statement = connection.createStatement();
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
resultSet = statement.executeQuery("show all");
PropertyMap runtimeSettings = new PropertyMap("runtimeSettings");
@@ -201,7 +217,7 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
}
}
} finally {
- JDBCUtil.safeClose(statement, resultSet);
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
return config;
@@ -230,69 +246,80 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
PostgresqlConfFile confFile = getConfigurationFile();
confFile.setProperties(parameters);
} catch (IOException e) {
- log.error("Unable to update postgres configuration file", e);
+ LOG.error("Unable to update postgres configuration file", e);
}
report.setStatus(ConfigurationUpdateStatus.SUCCESS);
}
- /**
- * Get data about the database server. Currently we have two categories:
- * <ul>
- * <li>Database.* are metrics that are obtained from the database server
itself</li>
- * <li>Process.* are metrics obtained from the native system.</li>
- * </ul>
- *
- * @param report the report where all collected measurement data will be added
- * @param metrics the schedule of what needs to be collected when
- */
+ /**
+ * Get data about the database server. Currently we have two categories:
+ * <ul>
+ * <li>Database.* are metrics that are obtained from the database server
itself</li>
+ * <li>Process.* are metrics obtained from the native system.</li>
+ * </ul>
+ *
+ * @param report the report where all collected measurement data will be added
+ * @param metrics the schedule of what needs to be collected when
+ */
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) {
- for (MeasurementScheduleRequest request : metrics) {
- String property = request.getName();
- if (property.startsWith("Process.")) {
- if (aggregateProcessInfo != null) {
- aggregateProcessInfo.refresh();
+ for (MeasurementScheduleRequest request : metrics) {
+ String property = request.getName();
+ if (property.startsWith("Process.")) {
+ if (aggregateProcessInfo != null) {
+ aggregateProcessInfo.refresh();
- //report.addData(new MeasurementDataNumeric(request,
getProcessProperty(request.getName())));
+ //report.addData(new MeasurementDataNumeric(request,
getProcessProperty(request.getName())));
- Object val = lookupAttributeProperty(aggregateProcessInfo,
property.substring("Process.".length()));
- if (val != null && val instanceof Number) {
-// aggregateProcessInfo.getAggregateMemory().Cpu().getTotal()
- report.addData(new MeasurementDataNumeric(request, ((Number)
val).doubleValue()));
+ Object val = lookupAttributeProperty(aggregateProcessInfo,
property.substring("Process.".length()));
+ if (val != null && val instanceof Number) {
+ //
aggregateProcessInfo.getAggregateMemory().Cpu().getTotal()
+ report.addData(new MeasurementDataNumeric(request, ((Number)
val).doubleValue()));
+ }
}
- }
- } else if (property.startsWith("Database")) {
- try {
+ } else if (property.startsWith("Database")) {
if (property.endsWith("startTime")) {
- // db start time
- ResultSet rs =
getConnection().createStatement().executeQuery("SELECT
pg_postmaster_start_time()");
+ // db start time
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
try {
- if (rs.next()) {
- report.addData(new MeasurementDataTrait(request,
rs.getTimestamp(1).toString()));
+ jdbcConnection =
getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("SELECT
pg_postmaster_start_time()");
+ if (resultSet.next()) {
+ report.addData(new MeasurementDataTrait(request,
resultSet.getTimestamp(1).toString()));
+ }
+ } catch (SQLException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Can not collect property: " + property +
": " + e.getLocalizedMessage());
}
} finally {
- rs.close();
+ DatabasePluginUtil.safeClose(jdbcConnection, statement,
resultSet);
}
- }
- else if (property.endsWith("backends")) {
+ } else if (property.endsWith("backends")) {
// number of connected backends
- ResultSet rs =
getConnection().createStatement().executeQuery("select count(*) from
pg_stat_activity");
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
try {
- if (rs.next()) {
- report.addData(new MeasurementDataNumeric(request, (double)
rs.getLong(1)));
+ jdbcConnection =
getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("select count(*) from
pg_stat_activity");
+ if (resultSet.next()) {
+ report.addData(new MeasurementDataNumeric(request, (double)
resultSet.getLong(1)));
+ }
+ } catch (SQLException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Can not collect property: " + property +
": " + e.getLocalizedMessage());
}
} finally {
- rs.close();
+ DatabasePluginUtil.safeClose(jdbcConnection, statement,
resultSet);
}
}
-
- }
- catch (SQLException e) {
- log.warn("Can not collect property: " + property + ":
" + e.getLocalizedMessage());
- }
- }
- }
+ }
+ }
}
private Double getProcessProperty(String property) {
@@ -320,8 +347,10 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
}
}
} catch (Exception e) {
- log.debug("Unable to read property from measurement attribute [" +
searchProperty + "] not found on ["
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Unable to read property from measurement attribute
[" + searchProperty + "] not found on ["
+ this.resourceContext.getResourceKey() + "]");
+ }
}
if (ps.length > 1) {
@@ -340,34 +369,31 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
}
}
} catch (Exception e) {
- log.error("Error occurred while retrieving property '" + name +
"' from object [" + object + "]", e);
+ LOG.error("Error occurred while retrieving property '" + name +
"' from object [" + object + "]", e);
}
return Double.NaN;
}
- /*private ProcessInfo getProcess(String pgdata)
- * { List<ProcessScanResult> matches =
this.resourceContext.getNativeProcessesForType(); for (ProcessScanResult
- * process : matches) { if
(pgdata.equals(process.getProcessInfo().getEnvironmentProperty("PGDATA")))
return
- * process.getProcessInfo(); } return null;}*/
-
public OperationResult invokeOperation(String name, Configuration parameters) throws
InterruptedException,
Exception {
if (name.equals("listProcessStatistics")) {
- Statement stmt = null;
- ResultSet rs = null;
+ Connection jdbcConnection = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
try {
- stmt = getConnection().createStatement();
- rs = stmt.executeQuery("SELECT * FROM pg_stat_activity ORDER BY
current_query desc");
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
+ resultSet = statement.executeQuery("SELECT * FROM pg_stat_activity
ORDER BY current_query desc");
PropertyList procList = new PropertyList("processList");
- while (rs.next()) {
+ while (resultSet.next()) {
PropertyMap pm = new PropertyMap("process");
- pm.put(new PropertySimple("pid",
rs.getInt("procpid")));
- pm.put(new PropertySimple("userName",
rs.getString("usename")));
- pm.put(new PropertySimple("query",
rs.getString("current_query")));
- pm.put(new PropertySimple("address",
rs.getString("client_addr")));
- pm.put(new PropertySimple("port",
rs.getInt("client_port")));
+ pm.put(new PropertySimple("pid",
resultSet.getInt("procpid")));
+ pm.put(new PropertySimple("userName",
resultSet.getString("usename")));
+ pm.put(new PropertySimple("query",
resultSet.getString("current_query")));
+ pm.put(new PropertySimple("address",
resultSet.getString("client_addr")));
+ pm.put(new PropertySimple("port",
resultSet.getInt("client_port")));
procList.add(pm);
}
@@ -376,13 +402,7 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
result.getComplexResults().put(procList);
return result;
} finally {
- if (rs != null) {
- rs.close();
- }
-
- if (stmt != null) {
- stmt.close();
- }
+ DatabasePluginUtil.safeClose(jdbcConnection, statement, resultSet);
}
}
@@ -393,11 +413,12 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
Configuration userConfig = report.getResourceConfiguration();
String user = userConfig.getSimpleValue("user", null);
+ Connection jdbcConnection = null;
Statement statement = null;
String sql = PostgresUserComponent.getUserSQL(userConfig,
PostgresUserComponent.UpdateType.CREATE);
try {
- statement = getConnection().createStatement();
-
+ jdbcConnection = getPooledConnectionProvider().getPooledConnection();
+ statement = jdbcConnection.createStatement();
// NOTE: Postgres doesn't seem to indicate the expect count of 1 row
updated but this work
// Postgres returns 0 for DDL that does not return rows
statement.executeUpdate(sql);
@@ -406,7 +427,7 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
} catch (SQLException e) {
report.setException(e);
} finally {
- JDBCUtil.safeClose(statement);
+ DatabasePluginUtil.safeClose(jdbcConnection, statement);
}
return report;
@@ -436,7 +457,7 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
jonValue = Boolean.FALSE.toString();
} else {
jonValue = (propDef.isRequired()) ? Boolean.FALSE.toString() : null;
- log.warn("Boolean PostgreSQL configuration parameter '" +
propDef.getName()
+ LOG.warn("Boolean PostgreSQL configuration parameter '" +
propDef.getName()
+ "' has an invalid value: '" + value + "'
- defaulting value to '" + jonValue + "'");
}
} else {
@@ -446,16 +467,15 @@ public class PostgresServerComponent<T extends
ResourceComponent<?>> implements
return new PropertySimple(propDef.getName(), jonValue);
}
-
public void findProcessInfo() {
- List<ProcessInfo> processes =
- this.resourceContext.getSystemInformation().getProcesses(
+ List<ProcessInfo> processes = this.resourceContext
+ .getSystemInformation()
+ .getProcesses(
"process|basename|match=^(?i)(postgres|postmaster)\\.exe$,process|basename|nomatch|parent=^(?i)(postgres|postmaster)\\.exe$");
- processes.addAll(
- this.resourceContext.getSystemInformation().getProcesses(
-
"process|basename|match=^(postgres|postmaster)$,process|basename|nomatch|parent=^(postgres|postmaster)$"));
+ processes.addAll(this.resourceContext.getSystemInformation().getProcesses(
+
"process|basename|match=^(postgres|postmaster)$,process|basename|nomatch|parent=^(postgres|postmaster)$"));
for (ProcessInfo processInfo : processes) {
String pgDataPath = PostgresDiscoveryComponent.getDataDirPath(processInfo);
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableComponent.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableComponent.java
index 9dc07bd..c65a97d 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableComponent.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,13 +13,18 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres;
+import static org.rhq.plugins.database.DatabasePluginUtil.getNumericQueryValues;
+import static org.rhq.plugins.database.DatabasePluginUtil.getSingleNumericQueryValue;
+
import java.sql.Connection;
import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
@@ -27,6 +32,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
import org.rhq.core.domain.configuration.Property;
@@ -44,16 +50,20 @@ import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
+import org.rhq.plugins.database.ConnectionPoolingSupport;
import org.rhq.plugins.database.DatabaseComponent;
+import org.rhq.plugins.database.DatabasePluginUtil;
import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.PooledConnectionProvider;
/**
* Represents a postgres table
*
* @author Greg Hinkle
*/
-public class PostgresTableComponent implements
DatabaseComponent<PostgresDatabaseComponent>, MeasurementFacet,
- ConfigurationFacet, DeleteResourceFacet, OperationFacet {
+public class PostgresTableComponent implements
DatabaseComponent<PostgresDatabaseComponent>, ConnectionPoolingSupport,
+ MeasurementFacet, ConfigurationFacet, DeleteResourceFacet, OperationFacet {
+
private static final List<String> PG_STAT_USER_TABLE_STATS =
Arrays.asList("seq_scan", "seq_tup_read", "idx_scan",
"idx_tup_fetch", "n_tup_ins", "n_tup_upd",
"n_tup_del", "table_size", "total_size");
@@ -77,6 +87,16 @@ public class PostgresTableComponent implements
DatabaseComponent<PostgresDatabas
this.resourceContext = null;
}
+ @Override
+ public boolean supportsConnectionPooling() {
+ return true;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return
resourceContext.getParentResourceComponent().getPooledConnectionProvider();
+ }
+
public String getTableName() {
return
this.resourceContext.getPluginConfiguration().getSimple("tableName").getStringValue();
}
@@ -88,28 +108,35 @@ public class PostgresTableComponent implements
DatabaseComponent<PostgresDatabas
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
requests) {
this.resourceContext.getParentResourceComponent().getConnection();
- Map<String, Double> results =
DatabaseQueryUtility.getNumericQueryValues(this, PG_STAT_USER_TABLES_QUERY,
- getTableName());
+ Map<String, Double> results = getNumericQueryValues(this,
PG_STAT_USER_TABLES_QUERY, getTableName());
for (MeasurementScheduleRequest request : requests) {
String metricName = request.getName();
Double value;
if (metricName.equals("rows")) {
- value = DatabaseQueryUtility.getSingleNumericQueryValue(this,
PG_COUNT_ROWS + getTableName());
+ value = getSingleNumericQueryValue(this, PG_COUNT_ROWS +
getTableName());
} else if (metricName.equals("rows_approx")) {
- value = DatabaseQueryUtility.getSingleNumericQueryValue(this,
PG_COUNT_ROWS_APPROX, getTableName());
+ value = getSingleNumericQueryValue(this, PG_COUNT_ROWS_APPROX,
getTableName());
} else {
value = results.get(metricName);
}
- if (value!=null) {
+ if (value != null) {
MeasurementDataNumeric mdn = new MeasurementDataNumeric(request, value);
report.addData(mdn);
}
}
}
- public void deleteResource() throws SQLException {
- DatabaseQueryUtility.executeUpdate(this, "DROP TABLE " +
getTableName(), new Object[] {});
+ public void deleteResource() throws Exception {
+ Connection connection = null;
+ PreparedStatement statement = null;
+ try {
+ connection = getPooledConnectionProvider().getPooledConnection();
+ statement = connection.prepareStatement("DROP TABLE " +
getTableName());
+ statement.executeUpdate();
+ } finally {
+ DatabasePluginUtil.safeClose(connection, statement);
+ }
}
public Configuration loadResourceConfiguration() throws Exception {
@@ -117,29 +144,31 @@ public class PostgresTableComponent implements
DatabaseComponent<PostgresDatabas
config.put(new PropertySimple("tableName",
resourceContext.getPluginConfiguration().getSimple("tableName")
.getStringValue()));
- Connection connection =
this.resourceContext.getParentResourceComponent().getConnection();
-
- DatabaseMetaData dmd = connection.getMetaData();
- ResultSet rs = dmd.getColumns("", "", getTableName(),
"");
+ Connection connection = null;
+ ResultSet columns = null;
try {
+ connection =
this.resourceContext.getParentResourceComponent().getConnection();
+ DatabaseMetaData databaseMetaData = connection.getMetaData();
+ columns = databaseMetaData.getColumns("", "",
getTableName(), "");
+
PropertyList columnList = new PropertyList("columns");
- while (rs.next()) {
+ while (columns.next()) {
PropertyMap col = new PropertyMap("columnDefinition");
- col.put(new PropertySimple("columnName",
rs.getString("COLUMN_NAME")));
- col.put(new PropertySimple("columnType",
rs.getString("TYPE_NAME")));
- col.put(new PropertySimple("columnLength",
rs.getInt("COLUMN_SIZE")));
- col.put(new PropertySimple("columnPrecision",
rs.getInt("DECIMAL_DIGITS")));
- col.put(new PropertySimple("columnDefault",
rs.getString("COLUMN_DEF")));
- col.put(new PropertySimple("columnNullable",
rs.getBoolean("IS_NULLABLE")));
+ col.put(new PropertySimple("columnName",
columns.getString("COLUMN_NAME")));
+ col.put(new PropertySimple("columnType",
columns.getString("TYPE_NAME")));
+ col.put(new PropertySimple("columnLength",
columns.getInt("COLUMN_SIZE")));
+ col.put(new PropertySimple("columnPrecision",
columns.getInt("DECIMAL_DIGITS")));
+ col.put(new PropertySimple("columnDefault",
columns.getString("COLUMN_DEF")));
+ col.put(new PropertySimple("columnNullable",
columns.getBoolean("IS_NULLABLE")));
columnList.add(col);
}
config.put(columnList);
} finally {
- rs.close();
+ DatabasePluginUtil.safeClose(connection);
}
return config;
@@ -177,13 +206,12 @@ public class PostgresTableComponent implements
DatabaseComponent<PostgresDatabas
}
} else {
existingDefs.remove(existingDef.columnName);
- boolean columnLengthChanged = ((existingDef.columnLength != null
&& !existingDef.columnLength.equals(newDef.columnLength)) ||
- (existingDef.columnLength == null
&& existingDef.columnLength != null));
- boolean columnPrecisionChanged = ((existingDef.columnPrecision !=
null && !existingDef.columnPrecision.equals(newDef.columnPrecision)) ||
- (existingDef.columnPrecision == null
&& existingDef.columnPrecision != null));
- if (!existingDef.columnType.equals(newDef.columnType) ||
- columnLengthChanged ||
- columnPrecisionChanged) {
+ boolean columnLengthChanged = ((existingDef.columnLength != null
&& !existingDef.columnLength
+ .equals(newDef.columnLength)) || (existingDef.columnLength ==
null && existingDef.columnLength != null));
+ boolean columnPrecisionChanged = ((existingDef.columnPrecision !=
null && !existingDef.columnPrecision
+ .equals(newDef.columnPrecision)) || (existingDef.columnPrecision
== null && existingDef.columnPrecision != null));
+ if (!existingDef.columnType.equals(newDef.columnType) ||
columnLengthChanged
+ || columnPrecisionChanged) {
String sql = "ALTER TABLE " + getTableName() + "
ALTER COLUMN " + newDef.columnName + " TYPE "
+ newDef.columnType;
if (newDef.columnLength != null) {
@@ -200,8 +228,8 @@ public class PostgresTableComponent implements
DatabaseComponent<PostgresDatabas
}
// Set default separately.
- boolean columnDefaultChanged = ((existingDef.columnDefault != null
&& !existingDef.columnDefault.equals(newDef.columnDefault)) ||
- (existingDef.columnDefault == null &&
newDef.columnDefault != null));
+ boolean columnDefaultChanged = ((existingDef.columnDefault != null
&& !existingDef.columnDefault
+ .equals(newDef.columnDefault)) || (existingDef.columnDefault ==
null && newDef.columnDefault != null));
if (columnDefaultChanged) {
String sql = "ALTER TABLE " + getTableName() + "
ALTER COLUMN " + newDef.columnName;
if (newDef.columnDefault == null) {
@@ -242,7 +270,7 @@ public class PostgresTableComponent implements
DatabaseComponent<PostgresDatabas
Exception {
if ("vacuum".equals(name)) {
- DatabaseQueryUtility.executeUpdate(this,"vacuum " +
getTableName());
+ DatabaseQueryUtility.executeUpdate(this, "vacuum " +
getTableName());
}
return null;
}
@@ -301,4 +329,4 @@ public class PostgresTableComponent implements
DatabaseComponent<PostgresDatabas
return buf.toString();
}
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableDiscoveryComponent.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableDiscoveryComponent.java
index 3114a60..9d5864a 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableDiscoveryComponent.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresTableDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,23 +13,27 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres;
import java.sql.Connection;
import java.sql.ResultSet;
+import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.util.jdbc.JDBCUtil;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* Discovers postgres tables
@@ -37,34 +41,45 @@ import org.rhq.core.util.jdbc.JDBCUtil;
* @author Greg Hinkle
*/
public class PostgresTableDiscoveryComponent implements
ResourceDiscoveryComponent<PostgresDatabaseComponent> {
- private static final Log log =
LogFactory.getLog(PostgresTableDiscoveryComponent.class);
+ private static final Log LOG =
LogFactory.getLog(PostgresTableDiscoveryComponent.class);
public static final String TABLE_NAMES_QUERY = "select relname from
pg_stat_user_tables";
public Set<DiscoveredResourceDetails>
discoverResources(ResourceDiscoveryContext<PostgresDatabaseComponent> context)
throws Exception {
- log.debug("Discovering postgres tables for " +
context.getParentResourceComponent().getDatabaseName() + "...");
- Set<DiscoveredResourceDetails> discoveredTables = new
HashSet<DiscoveredResourceDetails>();
-
- Connection connection = context.getParentResourceComponent().getConnection();
- if (connection == null) // For databases we don't have access to don't
find the tables
- {
- return discoveredTables;
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Discovering postgres tables for " +
context.getParentResourceComponent().getDatabaseName()
+ + "...");
}
+ Set<DiscoveredResourceDetails> discoveredTables = new
HashSet<DiscoveredResourceDetails>();
+ Connection connection = null;
+ Statement statement = null;
ResultSet resultSet = null;
- Statement statement = connection.createStatement();
- resultSet = statement.executeQuery(TABLE_NAMES_QUERY);
- while (resultSet.next()) {
- String tableName = resultSet.getString(1);
- DiscoveredResourceDetails service = new
DiscoveredResourceDetails(context.getResourceType(), tableName,
- tableName, null, null, null, null);
- service.getPluginConfiguration().put(new
PropertySimple("tableName", tableName));
- discoveredTables.add(service);
+ try {
+ connection =
context.getParentResourceComponent().getPooledConnectionProvider().getPooledConnection();
+ statement = connection.createStatement();
+ resultSet = statement.executeQuery(TABLE_NAMES_QUERY);
+ while (resultSet.next()) {
+ String tableName = resultSet.getString(1);
+ DiscoveredResourceDetails service = new
DiscoveredResourceDetails(context.getResourceType(), tableName,
+ tableName, null, null, null, null);
+ service.getPluginConfiguration().put(new
PropertySimple("tableName", tableName));
+ discoveredTables.add(service);
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found " + discoveredTables.size() + " tables in
database "
+ + context.getParentResourceComponent().getDatabaseName());
+ }
+ } catch (SQLException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(
+ "Could not find tables in database " +
context.getParentResourceComponent().getDatabaseName(), e);
+ }
+ } finally {
+ DatabasePluginUtil.safeClose(connection, statement, resultSet);
}
- JDBCUtil.safeClose(statement, resultSet);
-
return discoveredTables;
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserComponent.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserComponent.java
index 92a5203..064c3ec 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserComponent.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,15 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres;
+import static org.rhq.plugins.database.DatabasePluginUtil.getNumericQueryValues;
+import static org.rhq.plugins.database.DatabasePluginUtil.getSingleNumericQueryValue;
+
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@@ -25,6 +29,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.Set;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.ConfigurationUpdateStatus;
import org.rhq.core.domain.configuration.PropertySimple;
@@ -37,15 +42,17 @@ import
org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.pluginapi.inventory.DeleteResourceFacet;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
-import org.rhq.core.util.jdbc.JDBCUtil;
+import org.rhq.plugins.database.ConnectionPoolingSupport;
import org.rhq.plugins.database.DatabaseComponent;
-import org.rhq.plugins.database.DatabaseQueryUtility;
+import org.rhq.plugins.database.DatabasePluginUtil;
+import org.rhq.plugins.database.PooledConnectionProvider;
/**
* @author Greg Hinkle
*/
-public class PostgresUserComponent implements
DatabaseComponent<PostgresServerComponent<?>>, MeasurementFacet,
- ConfigurationFacet, DeleteResourceFacet {
+public class PostgresUserComponent implements
DatabaseComponent<PostgresServerComponent<?>>, ConnectionPoolingSupport,
+ MeasurementFacet, ConfigurationFacet, DeleteResourceFacet {
+
private ResourceContext<PostgresServerComponent<?>> resourceContext;
public void start(ResourceContext<PostgresServerComponent<?>>
resourceContext) {
@@ -56,13 +63,22 @@ public class PostgresUserComponent implements
DatabaseComponent<PostgresServerCo
this.resourceContext = null;
}
+ @Override
+ public boolean supportsConnectionPooling() {
+ return true;
+ }
+
+ @Override
+ public PooledConnectionProvider getPooledConnectionProvider() {
+ return
resourceContext.getParentResourceComponent().getPooledConnectionProvider();
+ }
+
public String getUserName() {
return
this.resourceContext.getPluginConfiguration().getSimpleValue("userName", null);
}
public AvailabilityType getAvailability() {
- if (DatabaseQueryUtility.getSingleNumericQueryValue(this, "SELECT COUNT(*)
FROM PG_ROLES WHERE rolname = ?",
- getUserName()) == 1) {
+ if (getSingleNumericQueryValue(this, "SELECT COUNT(*) FROM PG_ROLES WHERE
rolname = ?", getUserName()) == 1) {
return AvailabilityType.UP;
} else {
return AvailabilityType.DOWN;
@@ -78,7 +94,7 @@ public class PostgresUserComponent implements
DatabaseComponent<PostgresServerCo
}
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) throws Exception {
- Map<String, Double> values =
DatabaseQueryUtility.getNumericQueryValues(this,
+ Map<String, Double> values = getNumericQueryValues(this,
"SELECT (SELECT COUNT(*) FROM pg_stat_activity where usename = ? AND
current_query != '<IDLE>') AS active,\n"
+ " (SELECT COUNT(*) FROM pg_stat_activity WHERE usename = ?) AS
total", getUserName(), getUserName());
@@ -88,49 +104,49 @@ public class PostgresUserComponent implements
DatabaseComponent<PostgresServerCo
}
public Configuration loadResourceConfiguration() throws Exception {
+ Connection connection = null;
PreparedStatement statement = null;
- ResultSet rs = null;
+ ResultSet resultSet = null;
try {
- statement = getConnection().prepareStatement("SELECT * FROM PG_ROLES
WHERE rolname = ?");
+ connection = getPooledConnectionProvider().getPooledConnection();
+ statement = connection.prepareStatement("SELECT * FROM PG_ROLES WHERE
rolname = ?");
statement.setString(1, getUserName());
- rs = statement.executeQuery();
- rs.next();
+ resultSet = statement.executeQuery();
+ resultSet.next();
Configuration config = new Configuration();
- config.put(new PropertySimple("user",
rs.getString("rolname")));
- config.put(new PropertySimple("canLogin",
rs.getBoolean("rolcanlogin")));
- config.put(new PropertySimple("inheritRights",
rs.getBoolean("rolinherit")));
- config.put(new PropertySimple("superuser",
rs.getBoolean("rolsuper")));
- config.put(new PropertySimple("canCreateDatabaseObjects",
rs.getBoolean("rolcreatedb")));
- config.put(new PropertySimple("canCreateRoles",
rs.getBoolean("rolcreaterole")));
- config.put(new PropertySimple("canModifyCatalogDirectly",
rs.getBoolean("rolcatupdate")));
- config.put(new PropertySimple("connectionLimit",
rs.getInt("rolconnlimit")));
+ config.put(new PropertySimple("user",
resultSet.getString("rolname")));
+ config.put(new PropertySimple("canLogin",
resultSet.getBoolean("rolcanlogin")));
+ config.put(new PropertySimple("inheritRights",
resultSet.getBoolean("rolinherit")));
+ config.put(new PropertySimple("superuser",
resultSet.getBoolean("rolsuper")));
+ config.put(new PropertySimple("canCreateDatabaseObjects",
resultSet.getBoolean("rolcreatedb")));
+ config.put(new PropertySimple("canCreateRoles",
resultSet.getBoolean("rolcreaterole")));
+ config.put(new PropertySimple("canModifyCatalogDirectly",
resultSet.getBoolean("rolcatupdate")));
+ config.put(new PropertySimple("connectionLimit",
resultSet.getInt("rolconnlimit")));
return config;
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
- JDBCUtil.safeClose(statement, rs);
+ DatabasePluginUtil.safeClose(connection, statement, resultSet);
}
}
public void updateResourceConfiguration(ConfigurationUpdateReport report) {
Configuration config = report.getConfiguration();
+ String sql = getUserSQL(config, UpdateType.ALTER);
+ Connection connection = null;
Statement statement = null;
- String sql = getUserSQL(config, UpdateType.ALTER);
try {
+ connection = getPooledConnectionProvider().getPooledConnection();
statement = getConnection().createStatement();
- int updates = statement.executeUpdate(sql);
- if (updates != 1) {
- report.setErrorMessage("Failed to update user " +
config.getSimpleValue("user", null));
- } else {
- report.setStatus(ConfigurationUpdateStatus.SUCCESS);
- }
+ statement.executeUpdate(sql);
+ report.setStatus(ConfigurationUpdateStatus.SUCCESS);
} catch (SQLException e) {
report.setErrorMessageFromThrowable(e);
} finally {
- JDBCUtil.safeClose(statement);
+ DatabasePluginUtil.safeClose(connection, statement);
}
}
@@ -145,36 +161,32 @@ public class PostgresUserComponent implements
DatabaseComponent<PostgresServerCo
connectionLimit = connLimit.getIntegerValue();
}
- String sql = type.name()
- + " USER "
- + config.getSimpleValue("user", null)
- + " ";
+ String sql = type.name() + " USER " +
config.getSimpleValue("user", null) + " ";
if (type != UpdateType.DROP) {
- String password = config.getSimpleValue("password",null);
+ String password = config.getSimpleValue("password", null);
if (password != null && password.length() != 0) {
- sql += " WITH PASSWORD '" +
config.getSimpleValue("password",null) + "' ";
+ sql += " WITH PASSWORD '" +
config.getSimpleValue("password", null) + "' ";
}
sql +=
(config.getSimple("canCreateDatabaseObjects").getBooleanValue() ? "CREATEDB
" : "NOCREATEDB ");
sql += (config.getSimple("canCreateRoles").getBooleanValue() ?
"CREATEUSER " : "NOCREATEUSER ");
- sql += (connectionLimit > -1) ? ("CONNECTION LIMIT " +
connectionLimit): "";
+ sql += (connectionLimit > -1) ? ("CONNECTION LIMIT " +
connectionLimit) : "";
}
return sql;
}
public void deleteResource() throws Exception {
- Statement statement = null;
String sql = "DROP USER " + this.resourceContext.getResourceKey();
+ Connection connection = null;
+ Statement statement = null;
try {
+ connection = getPooledConnectionProvider().getPooledConnection();
statement = getConnection().createStatement();
-
- // Note: Postgres doesn't seem to return the expected update count of 1
here... but this does work
- // Note: executeUpdate() returns 0 for statements that don't return rows
like e.g. drop xxx
statement.executeUpdate(sql);
} finally {
- JDBCUtil.safeClose(statement);
+ DatabasePluginUtil.safeClose(connection, statement);
}
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserDiscoveryComponent.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserDiscoveryComponent.java
index 9c7ae80..6301cdb 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserDiscoveryComponent.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/PostgresUserDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres;
import java.sql.Connection;
@@ -31,7 +32,7 @@ import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.util.jdbc.JDBCUtil;
+import org.rhq.plugins.database.DatabasePluginUtil;
/**
* Discovers Postgres Users though shouldn't need super user access
@@ -39,25 +40,22 @@ import org.rhq.core.util.jdbc.JDBCUtil;
* @author Greg Hinkle
*/
public class PostgresUserDiscoveryComponent implements
ResourceDiscoveryComponent<PostgresServerComponent<?>> {
- private static final Log log =
LogFactory.getLog(PostgresUserDiscoveryComponent.class);
+ private static final Log LOG =
LogFactory.getLog(PostgresUserDiscoveryComponent.class);
public static final String USERS_QUERY = "select * from pg_roles";
public Set<DiscoveredResourceDetails>
discoverResources(ResourceDiscoveryContext<PostgresServerComponent<?>>
context)
throws Exception {
- log.debug("Discovering postgres users for " +
context.getParentResourceComponent().getJDBCUrl() + "...");
- Set<DiscoveredResourceDetails> discoveredUsers = new
HashSet<DiscoveredResourceDetails>();
-
- Connection connection = context.getParentResourceComponent().getConnection();
- if (connection == null) // For databases we don't have access to don't
find the tables
- {
- return discoveredUsers;
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Discovering postgres users for " +
context.getParentResourceComponent().getJDBCUrl() + "...");
}
+ Set<DiscoveredResourceDetails> discoveredUsers = new
HashSet<DiscoveredResourceDetails>();
+ Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
-
try {
+ connection =
context.getParentResourceComponent().getPooledConnectionProvider().getPooledConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery(USERS_QUERY);
while (resultSet.next()) {
@@ -68,9 +66,9 @@ public class PostgresUserDiscoveryComponent implements
ResourceDiscoveryComponen
discoveredUsers.add(service);
}
} finally {
- JDBCUtil.safeClose(statement, resultSet);
+ DatabasePluginUtil.safeClose(connection, statement, resultSet);
}
return discoveredUsers;
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/util/PostgresqlConfFile.java
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/util/PostgresqlConfFile.java
index a80652e..3c5765a 100644
---
a/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/util/PostgresqlConfFile.java
+++
b/modules/plugins/postgres/src/main/java/org/rhq/plugins/postgres/util/PostgresqlConfFile.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres.util;
import java.io.BufferedOutputStream;
@@ -33,11 +34,13 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.rhq.core.util.jdbc.JDBCUtil;
+
+import org.rhq.core.util.stream.StreamUtil;
/**
* Represents a PostgreSQL configuration file (i.e. postgresql.conf) - provides methods
for reading and updating
@@ -99,7 +102,7 @@ public class PostgresqlConfFile {
}
}
} finally {
- JDBCUtil.safeClose(r);
+ StreamUtil.safeClose(r);
}
}
@@ -261,4 +264,4 @@ public class PostgresqlConfFile {
return this.configurationFile.toString();
}
-}
\ No newline at end of file
+}
diff --git
a/modules/plugins/postgres/src/test/java/org/rhq/plugins/postgres/test/PostgresPluginTest.java
b/modules/plugins/postgres/src/test/java/org/rhq/plugins/postgres/test/PostgresPluginTest.java
index bc0d247..c1e9e60 100644
---
a/modules/plugins/postgres/src/test/java/org/rhq/plugins/postgres/test/PostgresPluginTest.java
+++
b/modules/plugins/postgres/src/test/java/org/rhq/plugins/postgres/test/PostgresPluginTest.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.plugins.postgres.test;
import java.io.File;
@@ -25,6 +26,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.testng.annotations.AfterSuite;
@@ -171,4 +173,4 @@ public class PostgresPluginTest {
}
}
}
-}
\ No newline at end of file
+}
commit 89f82d19be7b225111a10704db75c97850ba9aa5
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Mon Dec 23 14:50:55 2013 +0100
Plugin validation for mysql plugin was failing because the Class.forName() statement
was invoked from the constructor of the component. I moved this code to the method that
actually opens the connection. This is the same strategy we use with our postgres plugin.
diff --git
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java
index 9dd60ee..6c81332 100644
---
a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java
+++
b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java
@@ -42,11 +42,6 @@ class MySqlConnectionManager {
private MySqlConnectionManager() {
connections = new HashMap<MySqlConnectionInfo,Connection>();
- try {
- Class.forName("com.mysql.jdbc.Driver").newInstance();
- } catch (Exception ex) {
- logger.error("Unable to find com.mysql.jdbc.Driver");
- }
}
static MySqlConnectionManager getConnectionManager() {
@@ -93,6 +88,12 @@ class MySqlConnectionManager {
}
Connection getConnection (MySqlConnectionInfo info) throws SQLException {
+ try {
+ Class.forName("com.mysql.jdbc.Driver");
+ } catch (Exception ex) {
+ logger.error("Unable to find com.mysql.jdbc.Driver");
+ }
+
Connection conn = connections.get(info);
String url = info.buildURL();
if (conn == null) {
commit e649c531e6ff25e706685c99fc3f560d49aaf9dc
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Fri Dec 20 15:26:40 2013 -0800
Upgrade to d3 version version 3.3.13.
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/AvailabilityOverUnderGraphType.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/AvailabilityOverUnderGraphType.java
index 6fcd585..b546776 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/AvailabilityOverUnderGraphType.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/AvailabilityOverUnderGraphType.java
@@ -140,6 +140,7 @@ public class AvailabilityOverUnderGraphType implements
AvailabilityGraphType {
* The magic JSNI to draw the charts with d3.
*/
public native void drawJsniChart() /*-{
+ "use strict";
//console.log("Draw Enhanced Availability chart");
var global = this,
@@ -163,14 +164,11 @@ public class AvailabilityOverUnderGraphType implements
AvailabilityGraphType {
var availabilityGraph = function () {
- "use strict";
- // privates
var margin = {top: 5, right: 5, bottom: 5, left: 40},
barOffset = 10,
width = 750 - margin.left - margin.right + barOffset,
- height = 40 - margin.top - margin.bottom,
- svg;
+ height = 40 - margin.top - margin.bottom;
function drawBars(availChartContext) {
@@ -362,7 +360,6 @@ public class AvailabilityOverUnderGraphType implements
AvailabilityGraphType {
return {
// Public API
draw: function (availChartContext) {
- "use strict";
drawBars(availChartContext);
}
}; // end public closure
@@ -426,4 +423,6 @@ public class AvailabilityOverUnderGraphType implements
AvailabilityGraphType {
public String getChartXaxisTimeFormatHoursMinutes() {
return MSG.chart_xaxis_time_format_hours_minutes();
}
+
+
}
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/StackedBarMetricGraphImpl.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/StackedBarMetricGraphImpl.java
index 33e3d97..17eeec3 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/StackedBarMetricGraphImpl.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/common/graph/graphtype/StackedBarMetricGraphImpl.java
@@ -40,6 +40,7 @@ public class StackedBarMetricGraphImpl extends AbstractMetricGraph {
*/
@Override
public native void drawJsniChart() /*-{
+ "use strict";
//console.log("Draw Stacked Bar jsni chart");
var global = this,
@@ -759,7 +760,6 @@ public class StackedBarMetricGraphImpl extends AbstractMetricGraph {
return {
// Public API
draw: function (chartContext) {
- "use strict";
// Guard condition that can occur when a portlet has not been
configured yet
if (chartContext.data.length > 0) {
//console.log("Creating Chart: "+
chartContext.chartSelection + " --> "+ chartContext.chartTitle);
diff --git
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/CoreGUI.gwt.xml
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/CoreGUI.gwt.xml
index 21eb46b..ba23b4d 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/CoreGUI.gwt.xml
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/CoreGUI.gwt.xml
@@ -57,7 +57,7 @@
-->
<script src="/coregui/js/jquery-1.7.2.min.js"/>
<script src="/coregui/js/jquery.sparkline-2.1.min.js"/>
- <script src="/coregui/js/d3.v3.min.js"/>
+ <script src="/coregui/js/d3.v3.3.13.min.js"/>
<!--
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.3.13.js
b/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.3.13.js
new file mode 100755
index 0000000..16087fd
--- /dev/null
+++ b/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.3.13.js
@@ -0,0 +1,9293 @@
+d3 = function() {
+ var d3 = {
+ version: "3.3.13"
+ };
+ if (!Date.now) Date.now = function() {
+ return +new Date();
+ };
+ var d3_arraySlice = [].slice, d3_array = function(list) {
+ return d3_arraySlice.call(list);
+ };
+ var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window
= window;
+ try {
+ d3_array(d3_documentElement.childNodes)[0].nodeType;
+ } catch (e) {
+ d3_array = function(list) {
+ var i = list.length, array = new Array(i);
+ while (i--) array[i] = list[i];
+ return array;
+ };
+ }
+ try {
+ d3_document.createElement("div").style.setProperty("opacity", 0,
"");
+ } catch (error) {
+ var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute =
d3_element_prototype.setAttribute, d3_element_setAttributeNS =
d3_element_prototype.setAttributeNS, d3_style_prototype =
d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty =
d3_style_prototype.setProperty;
+ d3_element_prototype.setAttribute = function(name, value) {
+ d3_element_setAttribute.call(this, name, value + "");
+ };
+ d3_element_prototype.setAttributeNS = function(space, local, value) {
+ d3_element_setAttributeNS.call(this, space, local, value + "");
+ };
+ d3_style_prototype.setProperty = function(name, value, priority) {
+ d3_style_setProperty.call(this, name, value + "", priority);
+ };
+ }
+ d3.ascending = function(a, b) {
+ return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
+ };
+ d3.descending = function(a, b) {
+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+ };
+ d3.min = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && !((a = array[i]) != null && a <= a)) a =
undefined;
+ while (++i < n) if ((b = array[i]) != null && a > b) a = b;
+ } else {
+ while (++i < n && !((a = f.call(array, array[i], i)) != null &&
a <= a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && a >
b) a = b;
+ }
+ return a;
+ };
+ d3.max = function(array, f) {
+ var i = -1, n = array.length, a, b;
+ if (arguments.length === 1) {
+ while (++i < n && !((a = array[i]) != null && a <= a)) a =
undefined;
+ while (++i < n) if ((b = array[i]) != null && b > a) a = b;
+ } else {
+ while (++i < n && !((a = f.call(array, array[i], i)) != null &&
a <= a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >
a) a = b;
+ }
+ return a;
+ };
+ d3.extent = function(array, f) {
+ var i = -1, n = array.length, a, b, c;
+ if (arguments.length === 1) {
+ while (++i < n && !((a = c = array[i]) != null && a <= a)) a
= c = undefined;
+ while (++i < n) if ((b = array[i]) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ } else {
+ while (++i < n && !((a = c = f.call(array, array[i], i)) != null
&& a <= a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ }
+ return [ a, c ];
+ };
+ d3.sum = function(array, f) {
+ var s = 0, n = array.length, a, i = -1;
+ if (arguments.length === 1) {
+ while (++i < n) if (!isNaN(a = +array[i])) s += a;
+ } else {
+ while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
+ }
+ return s;
+ };
+ function d3_number(x) {
+ return x != null && !isNaN(x);
+ }
+ d3.mean = function(array, f) {
+ var n = array.length, a, m = 0, i = -1, j = 0;
+ if (arguments.length === 1) {
+ while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
+ } else {
+ while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) /
++j;
+ }
+ return j ? m : undefined;
+ };
+ d3.quantile = function(values, p) {
+ var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H -
h;
+ return e ? v + e * (values[h] - v) : v;
+ };
+ d3.median = function(array, f) {
+ if (arguments.length > 1) array = array.map(f);
+ array = array.filter(d3_number);
+ return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
+ };
+ d3.bisector = function(f) {
+ return {
+ left: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid;
+ }
+ return lo;
+ },
+ right: function(a, x, lo, hi) {
+ if (arguments.length < 3) lo = 0;
+ if (arguments.length < 4) hi = a.length;
+ while (lo < hi) {
+ var mid = lo + hi >>> 1;
+ if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1;
+ }
+ return lo;
+ }
+ };
+ };
+ var d3_bisector = d3.bisector(function(d) {
+ return d;
+ });
+ d3.bisectLeft = d3_bisector.left;
+ d3.bisect = d3.bisectRight = d3_bisector.right;
+ d3.shuffle = function(array) {
+ var m = array.length, t, i;
+ while (m) {
+ i = Math.random() * m-- | 0;
+ t = array[m], array[m] = array[i], array[i] = t;
+ }
+ return array;
+ };
+ d3.permute = function(array, indexes) {
+ var i = indexes.length, permutes = new Array(i);
+ while (i--) permutes[i] = array[indexes[i]];
+ return permutes;
+ };
+ d3.pairs = function(array) {
+ var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 :
n);
+ while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ];
+ return pairs;
+ };
+ d3.zip = function() {
+ if (!(n = arguments.length)) return [];
+ for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i <
m; ) {
+ for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
+ zip[j] = arguments[j][i];
+ }
+ }
+ return zips;
+ };
+ function d3_zipLength(d) {
+ return d.length;
+ }
+ d3.transpose = function(matrix) {
+ return d3.zip.apply(d3, matrix);
+ };
+ d3.keys = function(map) {
+ var keys = [];
+ for (var key in map) keys.push(key);
+ return keys;
+ };
+ d3.values = function(map) {
+ var values = [];
+ for (var key in map) values.push(map[key]);
+ return values;
+ };
+ d3.entries = function(map) {
+ var entries = [];
+ for (var key in map) entries.push({
+ key: key,
+ value: map[key]
+ });
+ return entries;
+ };
+ d3.merge = function(arrays) {
+ var n = arrays.length, m, i = -1, j = 0, merged, array;
+ while (++i < n) j += arrays[i].length;
+ merged = new Array(j);
+ while (--n >= 0) {
+ array = arrays[n];
+ m = array.length;
+ while (--m >= 0) {
+ merged[--j] = array[m];
+ }
+ }
+ return merged;
+ };
+ var abs = Math.abs;
+ d3.range = function(start, stop, step) {
+ if (arguments.length < 3) {
+ step = 1;
+ if (arguments.length < 2) {
+ stop = start;
+ start = 0;
+ }
+ }
+ if ((stop - start) / step === Infinity) throw new Error("infinite range");
+ var range = [], k = d3_range_integerScale(abs(step)), i = -1, j;
+ start *= k, stop *= k, step *= k;
+ if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else
while ((j = start + step * ++i) < stop) range.push(j / k);
+ return range;
+ };
+ function d3_range_integerScale(x) {
+ var k = 1;
+ while (x * k % 1) k *= 10;
+ return k;
+ }
+ function d3_class(ctor, properties) {
+ try {
+ for (var key in properties) {
+ Object.defineProperty(ctor.prototype, key, {
+ value: properties[key],
+ enumerable: false
+ });
+ }
+ } catch (e) {
+ ctor.prototype = properties;
+ }
+ }
+ d3.map = function(object) {
+ var map = new d3_Map();
+ if (object instanceof d3_Map) object.forEach(function(key, value) {
+ map.set(key, value);
+ }); else for (var key in object) map.set(key, object[key]);
+ return map;
+ };
+ function d3_Map() {}
+ d3_class(d3_Map, {
+ has: function(key) {
+ return d3_map_prefix + key in this;
+ },
+ get: function(key) {
+ return this[d3_map_prefix + key];
+ },
+ set: function(key, value) {
+ return this[d3_map_prefix + key] = value;
+ },
+ remove: function(key) {
+ key = d3_map_prefix + key;
+ return key in this && delete this[key];
+ },
+ keys: function() {
+ var keys = [];
+ this.forEach(function(key) {
+ keys.push(key);
+ });
+ return keys;
+ },
+ values: function() {
+ var values = [];
+ this.forEach(function(key, value) {
+ values.push(value);
+ });
+ return values;
+ },
+ entries: function() {
+ var entries = [];
+ this.forEach(function(key, value) {
+ entries.push({
+ key: key,
+ value: value
+ });
+ });
+ return entries;
+ },
+ forEach: function(f) {
+ for (var key in this) {
+ if (key.charCodeAt(0) === d3_map_prefixCode) {
+ f.call(this, key.substring(1), this[key]);
+ }
+ }
+ }
+ });
+ var d3_map_prefix = "\x00", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
+ d3.nest = function() {
+ var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
+ function map(mapType, array, depth) {
+ if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues
? array.sort(sortValues) : array;
+ var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter,
valuesByKey = new d3_Map(), values;
+ while (++i < n) {
+ if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
+ values.push(object);
+ } else {
+ valuesByKey.set(keyValue, [ object ]);
+ }
+ }
+ if (mapType) {
+ object = mapType();
+ setter = function(keyValue, values) {
+ object.set(keyValue, map(mapType, values, depth));
+ };
+ } else {
+ object = {};
+ setter = function(keyValue, values) {
+ object[keyValue] = map(mapType, values, depth);
+ };
+ }
+ valuesByKey.forEach(setter);
+ return object;
+ }
+ function entries(map, depth) {
+ if (depth >= keys.length) return map;
+ var array = [], sortKey = sortKeys[depth++];
+ map.forEach(function(key, keyMap) {
+ array.push({
+ key: key,
+ values: entries(keyMap, depth)
+ });
+ });
+ return sortKey ? array.sort(function(a, b) {
+ return sortKey(a.key, b.key);
+ }) : array;
+ }
+ nest.map = function(array, mapType) {
+ return map(mapType, array, 0);
+ };
+ nest.entries = function(array) {
+ return entries(map(d3.map, array, 0), 0);
+ };
+ nest.key = function(d) {
+ keys.push(d);
+ return nest;
+ };
+ nest.sortKeys = function(order) {
+ sortKeys[keys.length - 1] = order;
+ return nest;
+ };
+ nest.sortValues = function(order) {
+ sortValues = order;
+ return nest;
+ };
+ nest.rollup = function(f) {
+ rollup = f;
+ return nest;
+ };
+ return nest;
+ };
+ d3.set = function(array) {
+ var set = new d3_Set();
+ if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]);
+ return set;
+ };
+ function d3_Set() {}
+ d3_class(d3_Set, {
+ has: function(value) {
+ return d3_map_prefix + value in this;
+ },
+ add: function(value) {
+ this[d3_map_prefix + value] = true;
+ return value;
+ },
+ remove: function(value) {
+ value = d3_map_prefix + value;
+ return value in this && delete this[value];
+ },
+ values: function() {
+ var values = [];
+ this.forEach(function(value) {
+ values.push(value);
+ });
+ return values;
+ },
+ forEach: function(f) {
+ for (var value in this) {
+ if (value.charCodeAt(0) === d3_map_prefixCode) {
+ f.call(this, value.substring(1));
+ }
+ }
+ }
+ });
+ d3.behavior = {};
+ d3.rebind = function(target, source) {
+ var i = 1, n = arguments.length, method;
+ while (++i < n) target[method = arguments[i]] = d3_rebind(target, source,
source[method]);
+ return target;
+ };
+ function d3_rebind(target, source, method) {
+ return function() {
+ var value = method.apply(source, arguments);
+ return value === source ? target : value;
+ };
+ }
+ function d3_vendorSymbol(object, name) {
+ if (name in object) return name;
+ name = name.charAt(0).toUpperCase() + name.substring(1);
+ for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
+ var prefixName = d3_vendorPrefixes[i] + name;
+ if (prefixName in object) return prefixName;
+ }
+ }
+ var d3_vendorPrefixes = [ "webkit", "ms", "moz",
"Moz", "o", "O" ];
+ function d3_noop() {}
+ d3.dispatch = function() {
+ var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+ return dispatch;
+ };
+ function d3_dispatch() {}
+ d3_dispatch.prototype.on = function(type, listener) {
+ var i = type.indexOf("."), name = "";
+ if (i >= 0) {
+ name = type.substring(i + 1);
+ type = type.substring(0, i);
+ }
+ if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name,
listener);
+ if (arguments.length === 2) {
+ if (listener == null) for (type in this) {
+ if (this.hasOwnProperty(type)) this[type].on(name, null);
+ }
+ return this;
+ }
+ };
+ function d3_dispatch_event(dispatch) {
+ var listeners = [], listenerByName = new d3_Map();
+ function event() {
+ var z = listeners, i = -1, n = z.length, l;
+ while (++i < n) if (l = z[i].on) l.apply(this, arguments);
+ return dispatch;
+ }
+ event.on = function(name, listener) {
+ var l = listenerByName.get(name), i;
+ if (arguments.length < 2) return l && l.on;
+ if (l) {
+ l.on = null;
+ listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i
+ 1));
+ listenerByName.remove(name);
+ }
+ if (listener) listeners.push(listenerByName.set(name, {
+ on: listener
+ }));
+ return dispatch;
+ };
+ return event;
+ }
+ d3.event = null;
+ function d3_eventPreventDefault() {
+ d3.event.preventDefault();
+ }
+ function d3_eventSource() {
+ var e = d3.event, s;
+ while (s = e.sourceEvent) e = s;
+ return e;
+ }
+ function d3_eventDispatch(target) {
+ var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
+ dispatch.of = function(thiz, argumentz) {
+ return function(e1) {
+ try {
+ var e0 = e1.sourceEvent = d3.event;
+ e1.target = target;
+ d3.event = e1;
+ dispatch[e1.type].apply(thiz, argumentz);
+ } finally {
+ d3.event = e0;
+ }
+ };
+ };
+ return dispatch;
+ }
+ d3.requote = function(s) {
+ return s.replace(d3_requote_re, "\\$&");
+ };
+ var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
+ var d3_subclass = {}.__proto__ ? function(object, prototype) {
+ object.__proto__ = prototype;
+ } : function(object, prototype) {
+ for (var property in prototype) object[property] = prototype[property];
+ };
+ function d3_selection(groups) {
+ d3_subclass(groups, d3_selectionPrototype);
+ return groups;
+ }
+ var d3_select = function(s, n) {
+ return n.querySelector(s);
+ }, d3_selectAll = function(s, n) {
+ return n.querySelectorAll(s);
+ }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement,
"matchesSelector")], d3_selectMatches = function(n, s) {
+ return d3_selectMatcher.call(n, s);
+ };
+ if (typeof Sizzle === "function") {
+ d3_select = function(s, n) {
+ return Sizzle(s, n)[0] || null;
+ };
+ d3_selectAll = function(s, n) {
+ return Sizzle.uniqueSort(Sizzle(s, n));
+ };
+ d3_selectMatches = Sizzle.matchesSelector;
+ }
+ d3.selection = function() {
+ return d3_selectionRoot;
+ };
+ var d3_selectionPrototype = d3.selection.prototype = [];
+ d3_selectionPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, group, node;
+ selector = d3_selection_selector(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(subnode = selector.call(node, node.__data__, i, j));
+ if (subnode && "__data__" in node) subnode.__data__ =
node.__data__;
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selector(selector) {
+ return typeof selector === "function" ? selector : function() {
+ return d3_select(selector, this);
+ };
+ }
+ d3_selectionPrototype.selectAll = function(selector) {
+ var subgroups = [], subgroup, node;
+ selector = d3_selection_selectorAll(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j)));
+ subgroup.parentNode = node;
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_selectorAll(selector) {
+ return typeof selector === "function" ? selector : function() {
+ return d3_selectAll(selector, this);
+ };
+ }
+ var d3_nsPrefix = {
+ 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/"
+ };
+ d3.ns = {
+ prefix: d3_nsPrefix,
+ qualify: function(name) {
+ var i = name.indexOf(":"), prefix = name;
+ if (i >= 0) {
+ prefix = name.substring(0, i);
+ name = name.substring(i + 1);
+ }
+ return d3_nsPrefix.hasOwnProperty(prefix) ? {
+ space: d3_nsPrefix[prefix],
+ local: name
+ } : name;
+ }
+ };
+ d3_selectionPrototype.attr = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node();
+ name = d3.ns.qualify(name);
+ return name.local ? node.getAttributeNS(name.space, name.local) :
node.getAttribute(name);
+ }
+ for (value in name) this.each(d3_selection_attr(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_attr(name, value));
+ };
+ function d3_selection_attr(name, value) {
+ name = d3.ns.qualify(name);
+ function attrNull() {
+ this.removeAttribute(name);
+ }
+ function attrNullNS() {
+ this.removeAttributeNS(name.space, name.local);
+ }
+ function attrConstant() {
+ this.setAttribute(name, value);
+ }
+ function attrConstantNS() {
+ this.setAttributeNS(name.space, name.local, value);
+ }
+ function attrFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
+ }
+ function attrFunctionNS() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttributeNS(name.space, name.local); else
this.setAttributeNS(name.space, name.local, x);
+ }
+ return value == null ? name.local ? attrNullNS : attrNull : typeof value ===
"function" ? name.local ? attrFunctionNS : attrFunction : name.local ?
attrConstantNS : attrConstant;
+ }
+ function d3_collapse(s) {
+ return s.trim().replace(/\s+/g, " ");
+ }
+ d3_selectionPrototype.classed = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") {
+ var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1;
+ if (value = node.classList) {
+ while (++i < n) if (!value.contains(name[i])) return false;
+ } else {
+ value = node.getAttribute("class");
+ while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return
false;
+ }
+ return true;
+ }
+ for (value in name) this.each(d3_selection_classed(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_classed(name, value));
+ };
+ function d3_selection_classedRe(name) {
+ return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)",
"g");
+ }
+ function d3_selection_classes(name) {
+ return name.trim().split(/^|\s+/);
+ }
+ function d3_selection_classed(name, value) {
+ name = d3_selection_classes(name).map(d3_selection_classedName);
+ var n = name.length;
+ function classedConstant() {
+ var i = -1;
+ while (++i < n) name[i](this, value);
+ }
+ function classedFunction() {
+ var i = -1, x = value.apply(this, arguments);
+ while (++i < n) name[i](this, x);
+ }
+ return typeof value === "function" ? classedFunction : classedConstant;
+ }
+ function d3_selection_classedName(name) {
+ var re = d3_selection_classedRe(name);
+ return function(node, value) {
+ if (c = node.classList) return value ? c.add(name) : c.remove(name);
+ var c = node.getAttribute("class") || "";
+ if (value) {
+ re.lastIndex = 0;
+ if (!re.test(c)) node.setAttribute("class", d3_collapse(c + "
" + name));
+ } else {
+ node.setAttribute("class", d3_collapse(c.replace(re, " ")));
+ }
+ };
+ }
+ d3_selectionPrototype.style = function(name, value, priority) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof name !== "string") {
+ if (n < 2) value = "";
+ for (priority in name) this.each(d3_selection_style(priority, name[priority],
value));
+ return this;
+ }
+ if (n < 2) return d3_window.getComputedStyle(this.node(),
null).getPropertyValue(name);
+ priority = "";
+ }
+ return this.each(d3_selection_style(name, value, priority));
+ };
+ function d3_selection_style(name, value, priority) {
+ function styleNull() {
+ this.style.removeProperty(name);
+ }
+ function styleConstant() {
+ this.style.setProperty(name, value, priority);
+ }
+ function styleFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.style.removeProperty(name); else this.style.setProperty(name,
x, priority);
+ }
+ return value == null ? styleNull : typeof value === "function" ?
styleFunction : styleConstant;
+ }
+ d3_selectionPrototype.property = function(name, value) {
+ if (arguments.length < 2) {
+ if (typeof name === "string") return this.node()[name];
+ for (value in name) this.each(d3_selection_property(value, name[value]));
+ return this;
+ }
+ return this.each(d3_selection_property(name, value));
+ };
+ function d3_selection_property(name, value) {
+ function propertyNull() {
+ delete this[name];
+ }
+ function propertyConstant() {
+ this[name] = value;
+ }
+ function propertyFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) delete this[name]; else this[name] = x;
+ }
+ return value == null ? propertyNull : typeof value === "function" ?
propertyFunction : propertyConstant;
+ }
+ d3_selectionPrototype.text = function(value) {
+ return arguments.length ? this.each(typeof value === "function" ?
function() {
+ var v = value.apply(this, arguments);
+ this.textContent = v == null ? "" : v;
+ } : value == null ? function() {
+ this.textContent = "";
+ } : function() {
+ this.textContent = value;
+ }) : this.node().textContent;
+ };
+ d3_selectionPrototype.html = function(value) {
+ return arguments.length ? this.each(typeof value === "function" ?
function() {
+ var v = value.apply(this, arguments);
+ this.innerHTML = v == null ? "" : v;
+ } : value == null ? function() {
+ this.innerHTML = "";
+ } : function() {
+ this.innerHTML = value;
+ }) : this.node().innerHTML;
+ };
+ d3_selectionPrototype.append = function(name) {
+ name = d3_selection_creator(name);
+ return this.select(function() {
+ return this.appendChild(name.apply(this, arguments));
+ });
+ };
+ function d3_selection_creator(name) {
+ return typeof name === "function" ? name : (name =
d3.ns.qualify(name)).local ? function() {
+ return this.ownerDocument.createElementNS(name.space, name.local);
+ } : function() {
+ return this.ownerDocument.createElementNS(this.namespaceURI, name);
+ };
+ }
+ d3_selectionPrototype.insert = function(name, before) {
+ name = d3_selection_creator(name);
+ before = d3_selection_selector(before);
+ return this.select(function() {
+ return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments)
|| null);
+ });
+ };
+ d3_selectionPrototype.remove = function() {
+ return this.each(function() {
+ var parent = this.parentNode;
+ if (parent) parent.removeChild(this);
+ });
+ };
+ d3_selectionPrototype.data = function(value, key) {
+ var i = -1, n = this.length, group, node;
+ if (!arguments.length) {
+ value = new Array(n = (group = this[0]).length);
+ while (++i < n) {
+ if (node = group[i]) {
+ value[i] = node.__data__;
+ }
+ }
+ return value;
+ }
+ function bind(group, groupData) {
+ var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes =
new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
+ if (key) {
+ var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [],
keyValue;
+ for (i = -1; ++i < n; ) {
+ keyValue = key.call(node = group[i], node.__data__, i);
+ if (nodeByKeyValue.has(keyValue)) {
+ exitNodes[i] = node;
+ } else {
+ nodeByKeyValue.set(keyValue, node);
+ }
+ keyValues.push(keyValue);
+ }
+ for (i = -1; ++i < m; ) {
+ keyValue = key.call(groupData, nodeData = groupData[i], i);
+ if (node = nodeByKeyValue.get(keyValue)) {
+ updateNodes[i] = node;
+ node.__data__ = nodeData;
+ } else if (!dataByKeyValue.has(keyValue)) {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ }
+ dataByKeyValue.set(keyValue, nodeData);
+ nodeByKeyValue.remove(keyValue);
+ }
+ for (i = -1; ++i < n; ) {
+ if (nodeByKeyValue.has(keyValues[i])) {
+ exitNodes[i] = group[i];
+ }
+ }
+ } else {
+ for (i = -1; ++i < n0; ) {
+ node = group[i];
+ nodeData = groupData[i];
+ if (node) {
+ node.__data__ = nodeData;
+ updateNodes[i] = node;
+ } else {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ }
+ }
+ for (;i < m; ++i) {
+ enterNodes[i] = d3_selection_dataNode(groupData[i]);
+ }
+ for (;i < n; ++i) {
+ exitNodes[i] = group[i];
+ }
+ }
+ enterNodes.update = updateNodes;
+ enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode =
group.parentNode;
+ enter.push(enterNodes);
+ update.push(updateNodes);
+ exit.push(exitNodes);
+ }
+ var enter = d3_selection_enter([]), update = d3_selection([]), exit =
d3_selection([]);
+ if (typeof value === "function") {
+ while (++i < n) {
+ bind(group = this[i], value.call(group, group.parentNode.__data__, i));
+ }
+ } else {
+ while (++i < n) {
+ bind(group = this[i], value);
+ }
+ }
+ update.enter = function() {
+ return enter;
+ };
+ update.exit = function() {
+ return exit;
+ };
+ return update;
+ };
+ function d3_selection_dataNode(data) {
+ return {
+ __data__: data
+ };
+ }
+ d3_selectionPrototype.datum = function(value) {
+ return arguments.length ? this.property("__data__", value) :
this.property("__data__");
+ };
+ d3_selectionPrototype.filter = function(filter) {
+ var subgroups = [], subgroup, group, node;
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
+ subgroup.push(node);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ function d3_selection_filter(selector) {
+ return function() {
+ return d3_selectMatches(this, selector);
+ };
+ }
+ d3_selectionPrototype.order = function() {
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0;
) {
+ if (node = group[i]) {
+ if (next && next !== node.nextSibling)
next.parentNode.insertBefore(node, next);
+ next = node;
+ }
+ }
+ }
+ return this;
+ };
+ d3_selectionPrototype.sort = function(comparator) {
+ comparator = d3_selection_sortComparator.apply(this, arguments);
+ for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
+ return this.order();
+ };
+ function d3_selection_sortComparator(comparator) {
+ if (!arguments.length) comparator = d3.ascending;
+ return function(a, b) {
+ return a && b ? comparator(a.__data__, b.__data__) : !a - !b;
+ };
+ }
+ d3_selectionPrototype.each = function(callback) {
+ return d3_selection_each(this, function(node, i, j) {
+ callback.call(node, node.__data__, i, j);
+ });
+ };
+ function d3_selection_each(groups, callback) {
+ for (var j = 0, m = groups.length; j < m; j++) {
+ for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
+ if (node = group[i]) callback(node, i, j);
+ }
+ }
+ return groups;
+ }
+ d3_selectionPrototype.call = function(callback) {
+ var args = d3_array(arguments);
+ callback.apply(args[0] = this, args);
+ return this;
+ };
+ d3_selectionPrototype.empty = function() {
+ return !this.node();
+ };
+ d3_selectionPrototype.node = function() {
+ for (var j = 0, m = this.length; j < m; j++) {
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ var node = group[i];
+ if (node) return node;
+ }
+ }
+ return null;
+ };
+ d3_selectionPrototype.size = function() {
+ var n = 0;
+ this.each(function() {
+ ++n;
+ });
+ return n;
+ };
+ function d3_selection_enter(selection) {
+ d3_subclass(selection, d3_selection_enterPrototype);
+ return selection;
+ }
+ var d3_selection_enterPrototype = [];
+ d3.selection.enter = d3_selection_enter;
+ d3.selection.enter.prototype = d3_selection_enterPrototype;
+ d3_selection_enterPrototype.append = d3_selectionPrototype.append;
+ d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
+ d3_selection_enterPrototype.node = d3_selectionPrototype.node;
+ d3_selection_enterPrototype.call = d3_selectionPrototype.call;
+ d3_selection_enterPrototype.size = d3_selectionPrototype.size;
+ d3_selection_enterPrototype.select = function(selector) {
+ var subgroups = [], subgroup, subnode, upgroup, group, node;
+ for (var j = -1, m = this.length; ++j < m; ) {
+ upgroup = (group = this[j]).update;
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = group.parentNode;
+ for (var i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode,
node.__data__, i, j));
+ subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_selection(subgroups);
+ };
+ d3_selection_enterPrototype.insert = function(name, before) {
+ if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);
+ return d3_selectionPrototype.insert.call(this, name, before);
+ };
+ function d3_selection_enterInsertBefore(enter) {
+ var i0, j0;
+ return function(d, i, j) {
+ var group = enter[j].update, n = group.length, node;
+ if (j != j0) j0 = j, i0 = 0;
+ if (i >= i0) i0 = i + 1;
+ while (!(node = group[i0]) && ++i0 < n) ;
+ return node;
+ };
+ }
+ d3_selectionPrototype.transition = function() {
+ var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node,
transition = d3_transitionInherit || {
+ time: Date.now(),
+ ease: d3_ease_cubicInOut,
+ delay: 0,
+ duration: 250
+ };
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) d3_transitionNode(node, i, id, transition);
+ subgroup.push(node);
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_selectionPrototype.interrupt = function() {
+ return this.each(d3_selection_interrupt);
+ };
+ function d3_selection_interrupt() {
+ var lock = this.__transition__;
+ if (lock) ++lock.active;
+ }
+ d3.select = function(node) {
+ var group = [ typeof node === "string" ? d3_select(node, d3_document) :
node ];
+ group.parentNode = d3_documentElement;
+ return d3_selection([ group ]);
+ };
+ d3.selectAll = function(nodes) {
+ var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes,
d3_document) : nodes);
+ group.parentNode = d3_documentElement;
+ return d3_selection([ group ]);
+ };
+ var d3_selectionRoot = d3.select(d3_documentElement);
+ d3_selectionPrototype.on = function(type, listener, capture) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof type !== "string") {
+ if (n < 2) listener = false;
+ for (capture in type) this.each(d3_selection_on(capture, type[capture],
listener));
+ return this;
+ }
+ if (n < 2) return (n = this.node()["__on" + type]) && n._;
+ capture = false;
+ }
+ return this.each(d3_selection_on(type, listener, capture));
+ };
+ function d3_selection_on(type, listener, capture) {
+ var name = "__on" + type, i = type.indexOf("."), wrap =
d3_selection_onListener;
+ if (i > 0) type = type.substring(0, i);
+ var filter = d3_selection_onFilters.get(type);
+ if (filter) type = filter, wrap = d3_selection_onFilter;
+ function onRemove() {
+ var l = this[name];
+ if (l) {
+ this.removeEventListener(type, l, l.$);
+ delete this[name];
+ }
+ }
+ function onAdd() {
+ var l = wrap(listener, d3_array(arguments));
+ onRemove.call(this);
+ this.addEventListener(type, this[name] = l, l.$ = capture);
+ l._ = listener;
+ }
+ function removeAll() {
+ var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"),
match;
+ for (var name in this) {
+ if (match = name.match(re)) {
+ var l = this[name];
+ this.removeEventListener(match[1], l, l.$);
+ delete this[name];
+ }
+ }
+ }
+ return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll;
+ }
+ var d3_selection_onFilters = d3.map({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+ });
+ d3_selection_onFilters.forEach(function(k) {
+ if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
+ });
+ function d3_selection_onListener(listener, argumentz) {
+ return function(e) {
+ var o = d3.event;
+ d3.event = e;
+ argumentz[0] = this.__data__;
+ try {
+ listener.apply(this, argumentz);
+ } finally {
+ d3.event = o;
+ }
+ };
+ }
+ function d3_selection_onFilter(listener, argumentz) {
+ var l = d3_selection_onListener(listener, argumentz);
+ return function(e) {
+ var target = this, related = e.relatedTarget;
+ if (!related || related !== target &&
!(related.compareDocumentPosition(target) & 8)) {
+ l.call(target, e);
+ }
+ };
+ }
+ var d3_event_dragSelect = "onselectstart" in d3_document ? null :
d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0;
+ function d3_event_dragSuppress() {
+ var name = ".dragsuppress-" + ++d3_event_dragId, click = "click"
+ name, w = d3.select(d3_window).on("touchmove" + name,
d3_eventPreventDefault).on("dragstart" + name,
d3_eventPreventDefault).on("selectstart" + name, d3_eventPreventDefault);
+ if (d3_event_dragSelect) {
+ var style = d3_documentElement.style, select = style[d3_event_dragSelect];
+ style[d3_event_dragSelect] = "none";
+ }
+ return function(suppressClick) {
+ w.on(name, null);
+ if (d3_event_dragSelect) style[d3_event_dragSelect] = select;
+ if (suppressClick) {
+ function off() {
+ w.on(click, null);
+ }
+ w.on(click, function() {
+ d3_eventPreventDefault();
+ off();
+ }, true);
+ setTimeout(off, 0);
+ }
+ };
+ }
+ d3.mouse = function(container) {
+ return d3_mousePoint(container, d3_eventSource());
+ };
+ var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0;
+ function d3_mousePoint(container, e) {
+ if (e.changedTouches) e = e.changedTouches[0];
+ var svg = container.ownerSVGElement || container;
+ if (svg.createSVGPoint) {
+ var point = svg.createSVGPoint();
+ if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY))
{
+ svg = d3.select("body").append("svg").style({
+ position: "absolute",
+ top: 0,
+ left: 0,
+ margin: 0,
+ padding: 0,
+ border: "none"
+ }, "important");
+ var ctm = svg[0][0].getScreenCTM();
+ d3_mouse_bug44083 = !(ctm.f || ctm.e);
+ svg.remove();
+ }
+ if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x =
e.clientX,
+ point.y = e.clientY;
+ point = point.matrixTransform(container.getScreenCTM().inverse());
+ return [ point.x, point.y ];
+ }
+ var rect = container.getBoundingClientRect();
+ return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top -
container.clientTop ];
+ }
+ d3.touches = function(container, touches) {
+ if (arguments.length < 2) touches = d3_eventSource().touches;
+ return touches ? d3_array(touches).map(function(touch) {
+ var point = d3_mousePoint(container, touch);
+ point.identifier = touch.identifier;
+ return point;
+ }) : [];
+ };
+ d3.behavior.drag = function() {
+ var event = d3_eventDispatch(drag, "drag", "dragstart",
"dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse,
"mousemove", "mouseup"), touchstart = dragstart(touchid,
touchposition, "touchmove", "touchend");
+ function drag() {
+ this.on("mousedown.drag", mousedown).on("touchstart.drag",
touchstart);
+ }
+ function touchid() {
+ return d3.event.changedTouches[0].identifier;
+ }
+ function touchposition(parent, id) {
+ return d3.touches(parent).filter(function(p) {
+ return p.identifier === id;
+ })[0];
+ }
+ function dragstart(id, position, move, end) {
+ return function() {
+ var target = this, parent = target.parentNode, event_ = event.of(target,
arguments), eventTarget = d3.event.target, eventId = id(), drag = eventId == null ?
"drag" : "drag-" + eventId, origin_ = position(parent, eventId),
dragged = 0, offset, w = d3.select(d3_window).on(move + "." + drag,
moved).on(end + "." + drag, ended), dragRestore = d3_event_dragSuppress();
+ if (origin) {
+ offset = origin.apply(target, arguments);
+ offset = [ offset.x - origin_[0], offset.y - origin_[1] ];
+ } else {
+ offset = [ 0, 0 ];
+ }
+ event_({
+ type: "dragstart"
+ });
+ function moved() {
+ var p = position(parent, eventId), dx = p[0] - origin_[0], dy = p[1] -
origin_[1];
+ dragged |= dx | dy;
+ origin_ = p;
+ event_({
+ type: "drag",
+ x: p[0] + offset[0],
+ y: p[1] + offset[1],
+ dx: dx,
+ dy: dy
+ });
+ }
+ function ended() {
+ w.on(move + "." + drag, null).on(end + "." + drag, null);
+ dragRestore(dragged && d3.event.target === eventTarget);
+ event_({
+ type: "dragend"
+ });
+ }
+ };
+ }
+ drag.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return drag;
+ };
+ return d3.rebind(drag, event, "on");
+ };
+ var Ï = Math.PI, Ï = 2 * Ï, halfÏ = Ï / 2, ε = 1e-6, ε2 = ε * ε, d3_radians =
Ï / 180, d3_degrees = 180 / Ï;
+ function d3_sgn(x) {
+ return x > 0 ? 1 : x < 0 ? -1 : 0;
+ }
+ function d3_acos(x) {
+ return x > 1 ? 0 : x < -1 ? Ï : Math.acos(x);
+ }
+ function d3_asin(x) {
+ return x > 1 ? halfÏ : x < -1 ? -halfÏ : Math.asin(x);
+ }
+ function d3_sinh(x) {
+ return ((x = Math.exp(x)) - 1 / x) / 2;
+ }
+ function d3_cosh(x) {
+ return ((x = Math.exp(x)) + 1 / x) / 2;
+ }
+ function d3_tanh(x) {
+ return ((x = Math.exp(2 * x)) - 1) / (x + 1);
+ }
+ function d3_haversin(x) {
+ return (x = Math.sin(x / 2)) * x;
+ }
+ var Ï = Math.SQRT2, Ï2 = 2, Ï4 = 4;
+ d3.interpolateZoom = function(p0, p1) {
+ var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2];
+ var dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, d1 = Math.sqrt(d2), b0 =
(w1 * w1 - w0 * w0 + Ï4 * d2) / (2 * w0 * Ï2 * d1), b1 = (w1 * w1 - w0 * w0 - Ï4 * d2)
/ (2 * w1 * Ï2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 =
Math.log(Math.sqrt(b1 * b1 + 1) - b1), dr = r1 - r0, S = (dr || Math.log(w1 / w0)) / Ï;
+ function interpolate(t) {
+ var s = t * S;
+ if (dr) {
+ var coshr0 = d3_cosh(r0), u = w0 / (Ï2 * d1) * (coshr0 * d3_tanh(Ï * s + r0) -
d3_sinh(r0));
+ return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(Ï * s + r0) ];
+ }
+ return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(Ï * s) ];
+ }
+ interpolate.duration = S * 1e3;
+ return interpolate;
+ };
+ d3.behavior.zoom = function() {
+ var view = {
+ x: 0,
+ y: 0,
+ k: 1
+ }, translate0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity,
mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup =
"mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom",
touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom",
"zoomend"), x0, x1, y0, y1;
+ function zoom(g) {
+ g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom",
mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom",
dblclicked).on(touchstart, touchstarted);
+ }
+ zoom.event = function(g) {
+ g.each(function() {
+ var event_ = event.of(this, arguments), view1 = view;
+ if (d3_transitionInheritId) {
+ d3.select(this).transition().each("start.zoom", function() {
+ view = this.__chart__ || {
+ x: 0,
+ y: 0,
+ k: 1
+ };
+ zoomstarted(event_);
+ }).tween("zoom:zoom", function() {
+ var dx = size[0], dy = size[1], cx = dx / 2, cy = dy / 2, i =
d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx
- view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]);
+ return function(t) {
+ var l = i(t), k = dx / l[2];
+ this.__chart__ = view = {
+ x: cx - l[0] * k,
+ y: cy - l[1] * k,
+ k: k
+ };
+ zoomed(event_);
+ };
+ }).each("end.zoom", function() {
+ zoomended(event_);
+ });
+ } else {
+ this.__chart__ = view;
+ zoomstarted(event_);
+ zoomed(event_);
+ zoomended(event_);
+ }
+ });
+ };
+ zoom.translate = function(_) {
+ if (!arguments.length) return [ view.x, view.y ];
+ view = {
+ x: +_[0],
+ y: +_[1],
+ k: view.k
+ };
+ rescale();
+ return zoom;
+ };
+ zoom.scale = function(_) {
+ if (!arguments.length) return view.k;
+ view = {
+ x: view.x,
+ y: view.y,
+ k: +_
+ };
+ rescale();
+ return zoom;
+ };
+ zoom.scaleExtent = function(_) {
+ if (!arguments.length) return scaleExtent;
+ scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ];
+ return zoom;
+ };
+ zoom.center = function(_) {
+ if (!arguments.length) return center;
+ center = _ && [ +_[0], +_[1] ];
+ return zoom;
+ };
+ zoom.size = function(_) {
+ if (!arguments.length) return size;
+ size = _ && [ +_[0], +_[1] ];
+ return zoom;
+ };
+ zoom.x = function(z) {
+ if (!arguments.length) return x1;
+ x1 = z;
+ x0 = z.copy();
+ view = {
+ x: 0,
+ y: 0,
+ k: 1
+ };
+ return zoom;
+ };
+ zoom.y = function(z) {
+ if (!arguments.length) return y1;
+ y1 = z;
+ y0 = z.copy();
+ view = {
+ x: 0,
+ y: 0,
+ k: 1
+ };
+ return zoom;
+ };
+ function location(p) {
+ return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ];
+ }
+ function point(l) {
+ return [ l[0] * view.k + view.x, l[1] * view.k + view.y ];
+ }
+ function scaleTo(s) {
+ view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
+ }
+ function translateTo(p, l) {
+ l = point(l);
+ view.x += p[0] - l[0];
+ view.y += p[1] - l[1];
+ }
+ function rescale() {
+ if (x1) x1.domain(x0.range().map(function(x) {
+ return (x - view.x) / view.k;
+ }).map(x0.invert));
+ if (y1) y1.domain(y0.range().map(function(y) {
+ return (y - view.y) / view.k;
+ }).map(y0.invert));
+ }
+ function zoomstarted(event) {
+ event({
+ type: "zoomstart"
+ });
+ }
+ function zoomed(event) {
+ rescale();
+ event({
+ type: "zoom",
+ scale: view.k,
+ translate: [ view.x, view.y ]
+ });
+ }
+ function zoomended(event) {
+ event({
+ type: "zoomend"
+ });
+ }
+ function mousedowned() {
+ var target = this, event_ = event.of(target, arguments), eventTarget =
d3.event.target, dragged = 0, w = d3.select(d3_window).on(mousemove, moved).on(mouseup,
ended), l = location(d3.mouse(target)), dragRestore = d3_event_dragSuppress();
+ d3_selection_interrupt.call(target);
+ zoomstarted(event_);
+ function moved() {
+ dragged = 1;
+ translateTo(d3.mouse(target), l);
+ zoomed(event_);
+ }
+ function ended() {
+ w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup,
null);
+ dragRestore(dragged && d3.event.target === eventTarget);
+ zoomended(event_);
+ }
+ }
+ function touchstarted() {
+ var target = this, event_ = event.of(target, arguments), locations0 = {}, distance0
= 0, scale0, eventId = d3.event.changedTouches[0].identifier, touchmove =
"touchmove.zoom-" + eventId, touchend = "touchend.zoom-" + eventId, w
= d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t =
d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore =
d3_event_dragSuppress();
+ d3_selection_interrupt.call(target);
+ started();
+ zoomstarted(event_);
+ function relocate() {
+ var touches = d3.touches(target);
+ scale0 = view.k;
+ touches.forEach(function(t) {
+ if (t.identifier in locations0) locations0[t.identifier] = location(t);
+ });
+ return touches;
+ }
+ function started() {
+ var changed = d3.event.changedTouches;
+ for (var i = 0, n = changed.length; i < n; ++i) {
+ locations0[changed[i].identifier] = null;
+ }
+ var touches = relocate(), now = Date.now();
+ if (touches.length === 1) {
+ if (now - touchtime < 500) {
+ var p = touches[0], l = locations0[p.identifier];
+ scaleTo(view.k * 2);
+ translateTo(p, l);
+ d3_eventPreventDefault();
+ zoomed(event_);
+ }
+ touchtime = now;
+ } else if (touches.length > 1) {
+ var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1];
+ distance0 = dx * dx + dy * dy;
+ }
+ }
+ function moved() {
+ var touches = d3.touches(target), p0, l0, p1, l1;
+ for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
+ p1 = touches[i];
+ if (l1 = locations0[p1.identifier]) {
+ if (l0) break;
+ p0 = p1, l0 = l1;
+ }
+ }
+ if (l1) {
+ var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] -
p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0);
+ p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
+ l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
+ scaleTo(scale1 * scale0);
+ }
+ touchtime = null;
+ translateTo(p0, l0);
+ zoomed(event_);
+ }
+ function ended() {
+ if (d3.event.touches.length) {
+ var changed = d3.event.changedTouches;
+ for (var i = 0, n = changed.length; i < n; ++i) {
+ delete locations0[changed[i].identifier];
+ }
+ for (var identifier in locations0) {
+ return void relocate();
+ }
+ }
+ w.on(touchmove, null).on(touchend, null);
+ t.on(mousedown, mousedowned).on(touchstart, touchstarted);
+ dragRestore();
+ zoomended(event_);
+ }
+ }
+ function mousewheeled() {
+ var event_ = event.of(this, arguments);
+ if (mousewheelTimer) clearTimeout(mousewheelTimer); else
d3_selection_interrupt.call(this),
+ zoomstarted(event_);
+ mousewheelTimer = setTimeout(function() {
+ mousewheelTimer = null;
+ zoomended(event_);
+ }, 50);
+ d3_eventPreventDefault();
+ var point = center || d3.mouse(this);
+ if (!translate0) translate0 = location(point);
+ scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
+ translateTo(point, translate0);
+ zoomed(event_);
+ }
+ function mousewheelreset() {
+ translate0 = null;
+ }
+ function dblclicked() {
+ var event_ = event.of(this, arguments), p = d3.mouse(this), l = location(p), k =
Math.log(view.k) / Math.LN2;
+ zoomstarted(event_);
+ scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));
+ translateTo(p, l);
+ zoomed(event_);
+ zoomended(event_);
+ }
+ return d3.rebind(zoom, event, "on");
+ };
+ var d3_behavior_zoomInfinity = [ 0, Infinity ];
+ var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ?
(d3_behavior_zoomDelta = function() {
+ return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1);
+ }, "wheel") : "onmousewheel" in d3_document ?
(d3_behavior_zoomDelta = function() {
+ return d3.event.wheelDelta;
+ }, "mousewheel") : (d3_behavior_zoomDelta = function() {
+ return -d3.event.detail;
+ }, "MozMousePixelScroll");
+ function d3_Color() {}
+ d3_Color.prototype.toString = function() {
+ return this.rgb() + "";
+ };
+ d3.hsl = function(h, s, l) {
+ return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) :
d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);
+ };
+ function d3_hsl(h, s, l) {
+ return new d3_Hsl(h, s, l);
+ }
+ function d3_Hsl(h, s, l) {
+ this.h = h;
+ this.s = s;
+ this.l = l;
+ }
+ var d3_hslPrototype = d3_Hsl.prototype = new d3_Color();
+ d3_hslPrototype.brighter = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, this.l / k);
+ };
+ d3_hslPrototype.darker = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_hsl(this.h, this.s, k * this.l);
+ };
+ d3_hslPrototype.rgb = function() {
+ return d3_hsl_rgb(this.h, this.s, this.l);
+ };
+ function d3_hsl_rgb(h, s, l) {
+ var m1, m2;
+ h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
+ s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
+ l = l < 0 ? 0 : l > 1 ? 1 : l;
+ m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
+ m1 = 2 * l - m2;
+ function v(h) {
+ if (h > 360) h -= 360; else if (h < 0) h += 360;
+ if (h < 60) return m1 + (m2 - m1) * h / 60;
+ if (h < 180) return m2;
+ if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
+ return m1;
+ }
+ function vv(h) {
+ return Math.round(v(h) * 255);
+ }
+ return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
+ }
+ d3.hcl = function(h, c, l) {
+ return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h
instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h =
d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l);
+ };
+ function d3_hcl(h, c, l) {
+ return new d3_Hcl(h, c, l);
+ }
+ function d3_Hcl(h, c, l) {
+ this.h = h;
+ this.c = c;
+ this.l = l;
+ }
+ var d3_hclPrototype = d3_Hcl.prototype = new d3_Color();
+ d3_hclPrototype.brighter = function(k) {
+ return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k
: 1)));
+ };
+ d3_hclPrototype.darker = function(k) {
+ return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k :
1)));
+ };
+ d3_hclPrototype.rgb = function() {
+ return d3_hcl_lab(this.h, this.c, this.l).rgb();
+ };
+ function d3_hcl_lab(h, c, l) {
+ if (isNaN(h)) h = 0;
+ if (isNaN(c)) c = 0;
+ return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
+ }
+ d3.lab = function(l, a, b) {
+ return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l
instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) :
d3_lab(+l, +a, +b);
+ };
+ function d3_lab(l, a, b) {
+ return new d3_Lab(l, a, b);
+ }
+ function d3_Lab(l, a, b) {
+ this.l = l;
+ this.a = a;
+ this.b = b;
+ }
+ var d3_lab_K = 18;
+ var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
+ var d3_labPrototype = d3_Lab.prototype = new d3_Color();
+ d3_labPrototype.brighter = function(k) {
+ return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a,
this.b);
+ };
+ d3_labPrototype.darker = function(k) {
+ return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a,
this.b);
+ };
+ d3_labPrototype.rgb = function() {
+ return d3_lab_rgb(this.l, this.a, this.b);
+ };
+ function d3_lab_rgb(l, a, b) {
+ var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
+ x = d3_lab_xyz(x) * d3_lab_X;
+ y = d3_lab_xyz(y) * d3_lab_Y;
+ z = d3_lab_xyz(z) * d3_lab_Z;
+ return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z),
d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259
* y + 1.0572252 * z));
+ }
+ function d3_lab_hcl(l, a, b) {
+ return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l)
: d3_hcl(NaN, NaN, l);
+ }
+ function d3_lab_xyz(x) {
+ return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
+ }
+ function d3_xyz_lab(x) {
+ return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
+ }
+ function d3_xyz_rgb(r) {
+ return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) -
.055));
+ }
+ d3.rgb = function(r, g, b) {
+ return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) :
d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b);
+ };
+ function d3_rgbNumber(value) {
+ return d3_rgb(value >> 16, value >> 8 & 255, value & 255);
+ }
+ function d3_rgbString(value) {
+ return d3_rgbNumber(value) + "";
+ }
+ function d3_rgb(r, g, b) {
+ return new d3_Rgb(r, g, b);
+ }
+ function d3_Rgb(r, g, b) {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ }
+ var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color();
+ d3_rgbPrototype.brighter = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ var r = this.r, g = this.g, b = this.b, i = 30;
+ if (!r && !g && !b) return d3_rgb(i, i, i);
+ if (r && r < i) r = i;
+ if (g && g < i) g = i;
+ if (b && b < i) b = i;
+ return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b
/ k)));
+ };
+ d3_rgbPrototype.darker = function(k) {
+ k = Math.pow(.7, arguments.length ? k : 1);
+ return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b));
+ };
+ d3_rgbPrototype.hsl = function() {
+ return d3_rgb_hsl(this.r, this.g, this.b);
+ };
+ d3_rgbPrototype.toString = function() {
+ return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
+ };
+ function d3_rgb_hex(v) {
+ return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255,
v).toString(16);
+ }
+ function d3_rgb_parse(format, rgb, hsl) {
+ var r = 0, g = 0, b = 0, m1, m2, name;
+ m1 = /([a-z]+)\((.*)\)/i.exec(format);
+ if (m1) {
+ m2 = m1[2].split(",");
+ switch (m1[1]) {
+ case "hsl":
+ {
+ return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) /
100);
+ }
+
+ case "rgb":
+ {
+ return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]),
d3_rgb_parseNumber(m2[2]));
+ }
+ }
+ }
+ if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b);
+ if (format != null && format.charAt(0) === "#") {
+ if (format.length === 4) {
+ r = format.charAt(1);
+ r += r;
+ g = format.charAt(2);
+ g += g;
+ b = format.charAt(3);
+ b += b;
+ } else if (format.length === 7) {
+ r = format.substring(1, 3);
+ g = format.substring(3, 5);
+ b = format.substring(5, 7);
+ }
+ r = parseInt(r, 16);
+ g = parseInt(g, 16);
+ b = parseInt(b, 16);
+ }
+ return rgb(r, g, b);
+ }
+ function d3_rgb_hsl(r, g, b) {
+ var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max -
min, h, s, l = (max + min) / 2;
+ if (d) {
+ s = l < .5 ? d / (max + min) : d / (2 - max - min);
+ if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r)
/ d + 2; else h = (r - g) / d + 4;
+ h *= 60;
+ } else {
+ h = NaN;
+ s = l > 0 && l < 1 ? 0 : h;
+ }
+ return d3_hsl(h, s, l);
+ }
+ function d3_rgb_lab(r, g, b) {
+ r = d3_rgb_xyz(r);
+ g = d3_rgb_xyz(g);
+ b = d3_rgb_xyz(b);
+ var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y =
d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z =
d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
+ return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
+ }
+ function d3_rgb_xyz(r) {
+ return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
+ }
+ function d3_rgb_parseNumber(c) {
+ var f = parseFloat(c);
+ return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
+ }
+ var d3_rgb_names = d3.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
+ });
+ d3_rgb_names.forEach(function(key, value) {
+ d3_rgb_names.set(key, d3_rgbNumber(value));
+ });
+ function d3_functor(v) {
+ return typeof v === "function" ? v : function() {
+ return v;
+ };
+ }
+ d3.functor = d3_functor;
+ function d3_identity(d) {
+ return d;
+ }
+ d3.xhr = d3_xhrType(d3_identity);
+ function d3_xhrType(response) {
+ return function(url, mimeType, callback) {
+ if (arguments.length === 2 && typeof mimeType === "function")
callback = mimeType,
+ mimeType = null;
+ return d3_xhr(url, mimeType, response, callback);
+ };
+ }
+ function d3_xhr(url, mimeType, response, callback) {
+ var xhr = {}, dispatch = d3.dispatch("beforesend", "progress",
"load", "error"), headers = {}, request = new XMLHttpRequest(),
responseType = null;
+ if (d3_window.XDomainRequest && !("withCredentials" in request)
&& /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest();
+ "onload" in request ? request.onload = request.onerror = respond :
request.onreadystatechange = function() {
+ request.readyState > 3 && respond();
+ };
+ function respond() {
+ var status = request.status, result;
+ if (!status && request.responseText || status >= 200 && status
< 300 || status === 304) {
+ try {
+ result = response.call(xhr, request);
+ } catch (e) {
+ dispatch.error.call(xhr, e);
+ return;
+ }
+ dispatch.load.call(xhr, result);
+ } else {
+ dispatch.error.call(xhr, request);
+ }
+ }
+ request.onprogress = function(event) {
+ var o = d3.event;
+ d3.event = event;
+ try {
+ dispatch.progress.call(xhr, request);
+ } finally {
+ d3.event = o;
+ }
+ };
+ xhr.header = function(name, value) {
+ name = (name + "").toLowerCase();
+ if (arguments.length < 2) return headers[name];
+ if (value == null) delete headers[name]; else headers[name] = value +
"";
+ return xhr;
+ };
+ xhr.mimeType = function(value) {
+ if (!arguments.length) return mimeType;
+ mimeType = value == null ? null : value + "";
+ return xhr;
+ };
+ xhr.responseType = function(value) {
+ if (!arguments.length) return responseType;
+ responseType = value;
+ return xhr;
+ };
+ xhr.response = function(value) {
+ response = value;
+ return xhr;
+ };
+ [ "get", "post" ].forEach(function(method) {
+ xhr[method] = function() {
+ return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));
+ };
+ });
+ xhr.send = function(method, data, callback) {
+ if (arguments.length === 2 && typeof data === "function")
callback = data, data = null;
+ request.open(method, url, true);
+ if (mimeType != null && !("accept" in headers))
headers["accept"] = mimeType + ",*/*";
+ if (request.setRequestHeader) for (var name in headers)
request.setRequestHeader(name, headers[name]);
+ if (mimeType != null && request.overrideMimeType)
request.overrideMimeType(mimeType);
+ if (responseType != null) request.responseType = responseType;
+ if (callback != null) xhr.on("error", callback).on("load",
function(request) {
+ callback(null, request);
+ });
+ dispatch.beforesend.call(xhr, request);
+ request.send(data == null ? null : data);
+ return xhr;
+ };
+ xhr.abort = function() {
+ request.abort();
+ return xhr;
+ };
+ d3.rebind(xhr, dispatch, "on");
+ return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
+ }
+ function d3_xhr_fixCallback(callback) {
+ return callback.length === 1 ? function(error, request) {
+ callback(error == null ? request : null);
+ } : callback;
+ }
+ d3.dsv = function(delimiter, mimeType) {
+ var reFormat = new RegExp('["' + delimiter + "\n]"),
delimiterCode = delimiter.charCodeAt(0);
+ function dsv(url, row, callback) {
+ if (arguments.length < 3) callback = row, row = null;
+ var xhr = d3_xhr(url, mimeType, row == null ? response : typedResponse(row),
callback);
+ xhr.row = function(_) {
+ return arguments.length ? xhr.response((row = _) == null ? response :
typedResponse(_)) : row;
+ };
+ return xhr;
+ }
+ function response(request) {
+ return dsv.parse(request.responseText);
+ }
+ function typedResponse(f) {
+ return function(request) {
+ return dsv.parse(request.responseText, f);
+ };
+ }
+ dsv.parse = function(text, f) {
+ var o;
+ return dsv.parseRows(text, function(row, i) {
+ if (o) return o(row, i - 1);
+ var a = new Function("d", "return {" + row.map(function(name,
i) {
+ return JSON.stringify(name) + ": d[" + i + "]";
+ }).join(",") + "}");
+ o = f ? function(row, i) {
+ return f(a(row), i);
+ } : a;
+ });
+ };
+ dsv.parseRows = function(text, f) {
+ var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
+ function token() {
+ if (I >= N) return EOF;
+ if (eol) return eol = false, EOL;
+ var j = I;
+ if (text.charCodeAt(j) === 34) {
+ var i = j;
+ while (i++ < N) {
+ if (text.charCodeAt(i) === 34) {
+ if (text.charCodeAt(i + 1) !== 34) break;
+ ++i;
+ }
+ }
+ I = i + 2;
+ var c = text.charCodeAt(i + 1);
+ if (c === 13) {
+ eol = true;
+ if (text.charCodeAt(i + 2) === 10) ++I;
+ } else if (c === 10) {
+ eol = true;
+ }
+ return text.substring(j + 1, i).replace(/""/g, '"');
+ }
+ while (I < N) {
+ var c = text.charCodeAt(I++), k = 1;
+ if (c === 10) eol = true; else if (c === 13) {
+ eol = true;
+ if (text.charCodeAt(I) === 10) ++I, ++k;
+ } else if (c !== delimiterCode) continue;
+ return text.substring(j, I - k);
+ }
+ return text.substring(j);
+ }
+ while ((t = token()) !== EOF) {
+ var a = [];
+ while (t !== EOL && t !== EOF) {
+ a.push(t);
+ t = token();
+ }
+ if (f && !(a = f(a, n++))) continue;
+ rows.push(a);
+ }
+ return rows;
+ };
+ dsv.format = function(rows) {
+ if (Array.isArray(rows[0])) return dsv.formatRows(rows);
+ var fieldSet = new d3_Set(), fields = [];
+ rows.forEach(function(row) {
+ for (var field in row) {
+ if (!fieldSet.has(field)) {
+ fields.push(fieldSet.add(field));
+ }
+ }
+ });
+ return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) {
+ return fields.map(function(field) {
+ return formatValue(row[field]);
+ }).join(delimiter);
+ })).join("\n");
+ };
+ dsv.formatRows = function(rows) {
+ return rows.map(formatRow).join("\n");
+ };
+ function formatRow(row) {
+ return row.map(formatValue).join(delimiter);
+ }
+ function formatValue(text) {
+ return reFormat.test(text) ? '"' + text.replace(/\"/g,
'""') + '"' : text;
+ }
+ return dsv;
+ };
+ d3.csv = d3.dsv(",", "text/csv");
+ d3.tsv = d3.dsv(" ", "text/tab-separated-values");
+ var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout,
d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window,
"requestAnimationFrame")] || function(callback) {
+ setTimeout(callback, 17);
+ };
+ d3.timer = function(callback, delay, then) {
+ var n = arguments.length;
+ if (n < 2) delay = 0;
+ if (n < 3) then = Date.now();
+ var time = then + delay, timer = {
+ c: callback,
+ t: time,
+ f: false,
+ n: null
+ };
+ if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead =
timer;
+ d3_timer_queueTail = timer;
+ if (!d3_timer_interval) {
+ d3_timer_timeout = clearTimeout(d3_timer_timeout);
+ d3_timer_interval = 1;
+ d3_timer_frame(d3_timer_step);
+ }
+ };
+ function d3_timer_step() {
+ var now = d3_timer_mark(), delay = d3_timer_sweep() - now;
+ if (delay > 24) {
+ if (isFinite(delay)) {
+ clearTimeout(d3_timer_timeout);
+ d3_timer_timeout = setTimeout(d3_timer_step, delay);
+ }
+ d3_timer_interval = 0;
+ } else {
+ d3_timer_interval = 1;
+ d3_timer_frame(d3_timer_step);
+ }
+ }
+ d3.timer.flush = function() {
+ d3_timer_mark();
+ d3_timer_sweep();
+ };
+ function d3_timer_mark() {
+ var now = Date.now();
+ d3_timer_active = d3_timer_queueHead;
+ while (d3_timer_active) {
+ if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now -
d3_timer_active.t);
+ d3_timer_active = d3_timer_active.n;
+ }
+ return now;
+ }
+ function d3_timer_sweep() {
+ var t0, t1 = d3_timer_queueHead, time = Infinity;
+ while (t1) {
+ if (t1.f) {
+ t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;
+ } else {
+ if (t1.t < time) time = t1.t;
+ t1 = (t0 = t1).n;
+ }
+ }
+ d3_timer_queueTail = t0;
+ return time;
+ }
+ var d3_format_decimalPoint = ".", d3_format_thousandsSeparator =
",", d3_format_grouping = [ 3, 3 ], d3_format_currencySymbol = "$";
+ var d3_formatPrefixes = [ "y", "z", "a", "f",
"p", "n", "µ", "m", "", "k",
"M", "G", "T", "P", "E", "Z",
"Y" ].map(d3_formatPrefix);
+ d3.formatPrefix = function(value, precision) {
+ var i = 0;
+ if (value) {
+ if (value < 0) value *= -1;
+ if (precision) value = d3.round(value, d3_format_precision(value, precision));
+ i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
+ i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
+ }
+ return d3_formatPrefixes[8 + i / 3];
+ };
+ function d3_formatPrefix(d, i) {
+ var k = Math.pow(10, abs(8 - i) * 3);
+ return {
+ scale: i > 8 ? function(d) {
+ return d / k;
+ } : function(d) {
+ return d * k;
+ },
+ symbol: d
+ };
+ }
+ d3.round = function(x, n) {
+ return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
+ };
+ d3.format = function(specifier) {
+ var match = d3_format_re.exec(specifier), fill = match[1] || " ", align =
match[2] || ">", sign = match[3] || "", symbol = match[4] ||
"", zfill = match[5], width = +match[6], comma = match[7], precision = match[8],
type = match[9], scale = 1, suffix = "", integer = false;
+ if (precision) precision = +precision.substring(1);
+ if (zfill || fill === "0" && align === "=") {
+ zfill = fill = "0";
+ align = "=";
+ if (comma) width -= Math.floor((width - 1) / 4);
+ }
+ switch (type) {
+ case "n":
+ comma = true;
+ type = "g";
+ break;
+
+ case "%":
+ scale = 100;
+ suffix = "%";
+ type = "f";
+ break;
+
+ case "p":
+ scale = 100;
+ suffix = "%";
+ type = "r";
+ break;
+
+ case "b":
+ case "o":
+ case "x":
+ case "X":
+ if (symbol === "#") symbol = "0" + type.toLowerCase();
+
+ case "c":
+ case "d":
+ integer = true;
+ precision = 0;
+ break;
+
+ case "s":
+ scale = -1;
+ type = "r";
+ break;
+ }
+ if (symbol === "#") symbol = ""; else if (symbol ===
"$") symbol = d3_format_currencySymbol;
+ if (type == "r" && !precision) type = "g";
+ if (precision != null) {
+ if (type == "g") precision = Math.max(1, Math.min(21, precision)); else
if (type == "e" || type == "f") precision = Math.max(0, Math.min(20,
precision));
+ }
+ type = d3_format_types.get(type) || d3_format_typeDefault;
+ var zcomma = zfill && comma;
+ return function(value) {
+ if (integer && value % 1) return "";
+ var negative = value < 0 || value === 0 && 1 / value < 0 ? (value =
-value, "-") : sign;
+ if (scale < 0) {
+ var prefix = d3.formatPrefix(value, precision);
+ value = prefix.scale(value);
+ suffix = prefix.symbol;
+ } else {
+ value *= scale;
+ }
+ value = type(value, precision);
+ var i = value.lastIndexOf("."), before = i < 0 ? value :
value.substring(0, i), after = i < 0 ? "" : d3_format_decimalPoint +
value.substring(i + 1);
+ if (!zfill && comma) before = d3_format_group(before);
+ var length = symbol.length + before.length + after.length + (zcomma ? 0 :
negative.length), padding = length < width ? new Array(length = width - length +
1).join(fill) : "";
+ if (zcomma) before = d3_format_group(padding + before);
+ negative += symbol;
+ value = before + after;
+ return (align === "<" ? negative + value + padding : align ===
">" ? padding + negative + value : align === "^" ?
padding.substring(0, length >>= 1) + negative + value + padding.substring(length) :
negative + (zcomma ? value : padding + value)) + suffix;
+ };
+ };
+ var d3_format_re = /(?:([^{])?([<>=^]))?([+\-
])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
+ var d3_format_types = d3.map({
+ b: function(x) {
+ return x.toString(2);
+ },
+ c: function(x) {
+ return String.fromCharCode(x);
+ },
+ o: function(x) {
+ return x.toString(8);
+ },
+ x: function(x) {
+ return x.toString(16);
+ },
+ X: function(x) {
+ return x.toString(16).toUpperCase();
+ },
+ g: function(x, p) {
+ return x.toPrecision(p);
+ },
+ e: function(x, p) {
+ return x.toExponential(p);
+ },
+ f: function(x, p) {
+ return x.toFixed(p);
+ },
+ r: function(x, p) {
+ return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0,
Math.min(20, d3_format_precision(x * (1 + 1e-15), p))));
+ }
+ });
+ function d3_format_precision(x, p) {
+ return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);
+ }
+ function d3_format_typeDefault(x) {
+ return x + "";
+ }
+ var d3_format_group = d3_identity;
+ if (d3_format_grouping) {
+ var d3_format_groupingLength = d3_format_grouping.length;
+ d3_format_group = function(value) {
+ var i = value.length, t = [], j = 0, g = d3_format_grouping[0];
+ while (i > 0 && g > 0) {
+ t.push(value.substring(i -= g, i + g));
+ g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength];
+ }
+ return t.reverse().join(d3_format_thousandsSeparator);
+ };
+ }
+ d3.geo = {};
+ function d3_adder() {}
+ d3_adder.prototype = {
+ s: 0,
+ t: 0,
+ add: function(y) {
+ d3_adderSum(y, this.t, d3_adderTemp);
+ d3_adderSum(d3_adderTemp.s, this.s, this);
+ if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t;
+ },
+ reset: function() {
+ this.s = this.t = 0;
+ },
+ valueOf: function() {
+ return this.s;
+ }
+ };
+ var d3_adderTemp = new d3_adder();
+ function d3_adderSum(a, b, o) {
+ var x = o.s = a + b, bv = x - a, av = x - bv;
+ o.t = a - av + (b - bv);
+ }
+ d3.geo.stream = function(object, listener) {
+ if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
+ d3_geo_streamObjectType[object.type](object, listener);
+ } else {
+ d3_geo_streamGeometry(object, listener);
+ }
+ };
+ function d3_geo_streamGeometry(geometry, listener) {
+ if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
+ d3_geo_streamGeometryType[geometry.type](geometry, listener);
+ }
+ }
+ var d3_geo_streamObjectType = {
+ Feature: function(feature, listener) {
+ d3_geo_streamGeometry(feature.geometry, listener);
+ },
+ FeatureCollection: function(object, listener) {
+ var features = object.features, i = -1, n = features.length;
+ while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
+ }
+ };
+ var d3_geo_streamGeometryType = {
+ Sphere: function(object, listener) {
+ listener.sphere();
+ },
+ Point: function(object, listener) {
+ object = object.coordinates;
+ listener.point(object[0], object[1], object[2]);
+ },
+ MultiPoint: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) object = coordinates[i], listener.point(object[0], object[1],
object[2]);
+ },
+ LineString: function(object, listener) {
+ d3_geo_streamLine(object.coordinates, listener, 0);
+ },
+ MultiLineString: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
+ },
+ Polygon: function(object, listener) {
+ d3_geo_streamPolygon(object.coordinates, listener);
+ },
+ MultiPolygon: function(object, listener) {
+ var coordinates = object.coordinates, i = -1, n = coordinates.length;
+ while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
+ },
+ GeometryCollection: function(object, listener) {
+ var geometries = object.geometries, i = -1, n = geometries.length;
+ while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
+ }
+ };
+ function d3_geo_streamLine(coordinates, listener, closed) {
+ var i = -1, n = coordinates.length - closed, coordinate;
+ listener.lineStart();
+ while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0],
coordinate[1], coordinate[2]);
+ listener.lineEnd();
+ }
+ function d3_geo_streamPolygon(coordinates, listener) {
+ var i = -1, n = coordinates.length;
+ listener.polygonStart();
+ while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
+ listener.polygonEnd();
+ }
+ d3.geo.area = function(object) {
+ d3_geo_areaSum = 0;
+ d3.geo.stream(object, d3_geo_area);
+ return d3_geo_areaSum;
+ };
+ var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder();
+ var d3_geo_area = {
+ sphere: function() {
+ d3_geo_areaSum += 4 * Ï;
+ },
+ point: d3_noop,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ d3_geo_areaRingSum.reset();
+ d3_geo_area.lineStart = d3_geo_areaRingStart;
+ },
+ polygonEnd: function() {
+ var area = 2 * d3_geo_areaRingSum;
+ d3_geo_areaSum += area < 0 ? 4 * Ï + area : area;
+ d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
+ }
+ };
+ function d3_geo_areaRingStart() {
+ var λ00, Ï00, λ0, cosÏ0, sinÏ0;
+ d3_geo_area.point = function(λ, Ï) {
+ d3_geo_area.point = nextPoint;
+ λ0 = (λ00 = λ) * d3_radians, cosÏ0 = Math.cos(Ï = (Ï00 = Ï) * d3_radians / 2
+ Ï / 4),
+ sinÏ0 = Math.sin(Ï);
+ };
+ function nextPoint(λ, Ï) {
+ λ *= d3_radians;
+ Ï = Ï * d3_radians / 2 + Ï / 4;
+ var dλ = λ - λ0, cosÏ = Math.cos(Ï), sinÏ = Math.sin(Ï), k = sinÏ0 * sinÏ,
u = cosÏ0 * cosÏ + k * Math.cos(dλ), v = k * Math.sin(dλ);
+ d3_geo_areaRingSum.add(Math.atan2(v, u));
+ λ0 = λ, cosÏ0 = cosÏ, sinÏ0 = sinÏ;
+ }
+ d3_geo_area.lineEnd = function() {
+ nextPoint(λ00, Ï00);
+ };
+ }
+ function d3_geo_cartesian(spherical) {
+ var λ = spherical[0], Ï = spherical[1], cosÏ = Math.cos(Ï);
+ return [ cosÏ * Math.cos(λ), cosÏ * Math.sin(λ), Math.sin(Ï) ];
+ }
+ function d3_geo_cartesianDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+ }
+ function d3_geo_cartesianCross(a, b) {
+ return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] *
b[0] ];
+ }
+ function d3_geo_cartesianAdd(a, b) {
+ a[0] += b[0];
+ a[1] += b[1];
+ a[2] += b[2];
+ }
+ function d3_geo_cartesianScale(vector, k) {
+ return [ vector[0] * k, vector[1] * k, vector[2] * k ];
+ }
+ function d3_geo_cartesianNormalize(d) {
+ var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+ d[0] /= l;
+ d[1] /= l;
+ d[2] /= l;
+ }
+ function d3_geo_spherical(cartesian) {
+ return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ];
+ }
+ function d3_geo_sphericalEqual(a, b) {
+ return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;
+ }
+ d3.geo.bounds = function() {
+ var λ0, Ï0, λ1, Ï1, λ_, λ__, Ï__, p0, dλSum, ranges, range;
+ var bound = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ bound.point = ringPoint;
+ bound.lineStart = ringStart;
+ bound.lineEnd = ringEnd;
+ dλSum = 0;
+ d3_geo_area.polygonStart();
+ },
+ polygonEnd: function() {
+ d3_geo_area.polygonEnd();
+ bound.point = point;
+ bound.lineStart = lineStart;
+ bound.lineEnd = lineEnd;
+ if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), Ï0 = -(Ï1 = 90); else if
(dλSum > ε) Ï1 = 90; else if (dλSum < -ε) Ï0 = -90;
+ range[0] = λ0, range[1] = λ1;
+ }
+ };
+ function point(λ, Ï) {
+ ranges.push(range = [ λ0 = λ, λ1 = λ ]);
+ if (Ï < Ï0) Ï0 = Ï;
+ if (Ï > Ï1) Ï1 = Ï;
+ }
+ function linePoint(λ, Ï) {
+ var p = d3_geo_cartesian([ λ * d3_radians, Ï * d3_radians ]);
+ if (p0) {
+ var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0],
0 ], inflection = d3_geo_cartesianCross(equatorial, normal);
+ d3_geo_cartesianNormalize(inflection);
+ inflection = d3_geo_spherical(inflection);
+ var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees *
s, antimeridian = abs(dλ) > 180;
+ if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
+ var Ïi = inflection[1] * d3_degrees;
+ if (Ïi > Ï1) Ï1 = Ïi;
+ } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi
&& λi < s * λ)) {
+ var Ïi = -inflection[1] * d3_degrees;
+ if (Ïi < Ï0) Ï0 = Ïi;
+ } else {
+ if (Ï < Ï0) Ï0 = Ï;
+ if (Ï > Ï1) Ï1 = Ï;
+ }
+ if (antimeridian) {
+ if (λ < λ_) {
+ if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
+ } else {
+ if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
+ }
+ } else {
+ if (λ1 >= λ0) {
+ if (λ < λ0) λ0 = λ;
+ if (λ > λ1) λ1 = λ;
+ } else {
+ if (λ > λ_) {
+ if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
+ } else {
+ if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
+ }
+ }
+ }
+ } else {
+ point(λ, Ï);
+ }
+ p0 = p, λ_ = λ;
+ }
+ function lineStart() {
+ bound.point = linePoint;
+ }
+ function lineEnd() {
+ range[0] = λ0, range[1] = λ1;
+ bound.point = point;
+ p0 = null;
+ }
+ function ringPoint(λ, Ï) {
+ if (p0) {
+ var dλ = λ - λ_;
+ dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
+ } else λ__ = λ, Ï__ = Ï;
+ d3_geo_area.point(λ, Ï);
+ linePoint(λ, Ï);
+ }
+ function ringStart() {
+ d3_geo_area.lineStart();
+ }
+ function ringEnd() {
+ ringPoint(λ__, Ï__);
+ d3_geo_area.lineEnd();
+ if (abs(dλSum) > ε) λ0 = -(λ1 = 180);
+ range[0] = λ0, range[1] = λ1;
+ p0 = null;
+ }
+ function angle(λ0, λ1) {
+ return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1;
+ }
+ function compareRanges(a, b) {
+ return a[0] - b[0];
+ }
+ function withinRange(x, range) {
+ return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x
< range[0] || range[1] < x;
+ }
+ return function(feature) {
+ Ï1 = λ1 = -(λ0 = Ï0 = Infinity);
+ ranges = [];
+ d3.geo.stream(feature, bound);
+ var n = ranges.length;
+ if (n) {
+ ranges.sort(compareRanges);
+ for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) {
+ b = ranges[i];
+ if (withinRange(b[0], a) || withinRange(b[1], a)) {
+ if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
+ if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
+ } else {
+ merged.push(a = b);
+ }
+ }
+ var best = -Infinity, dλ;
+ for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i)
{
+ b = merged[i];
+ if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
+ }
+ }
+ ranges = range = null;
+ return λ0 === Infinity || Ï0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [
λ0, Ï0 ], [ λ1, Ï1 ] ];
+ };
+ }();
+ d3.geo.centroid = function(object) {
+ d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 =
d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 =
d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
+ d3.geo.stream(object, d3_geo_centroid);
+ var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x +
y * y + z * z;
+ if (m < ε2) {
+ x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
+ if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z =
d3_geo_centroidZ0;
+ m = x * x + y * y + z * z;
+ if (m < ε2) return [ NaN, NaN ];
+ }
+ return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ];
+ };
+ var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0,
d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1,
d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2;
+ var d3_geo_centroid = {
+ sphere: d3_noop,
+ point: d3_geo_centroidPoint,
+ lineStart: d3_geo_centroidLineStart,
+ lineEnd: d3_geo_centroidLineEnd,
+ polygonStart: function() {
+ d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
+ }
+ };
+ function d3_geo_centroidPoint(λ, Ï) {
+ λ *= d3_radians;
+ var cosÏ = Math.cos(Ï *= d3_radians);
+ d3_geo_centroidPointXYZ(cosÏ * Math.cos(λ), cosÏ * Math.sin(λ), Math.sin(Ï));
+ }
+ function d3_geo_centroidPointXYZ(x, y, z) {
+ ++d3_geo_centroidW0;
+ d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
+ d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
+ d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
+ }
+ function d3_geo_centroidLineStart() {
+ var x0, y0, z0;
+ d3_geo_centroid.point = function(λ, Ï) {
+ λ *= d3_radians;
+ var cosÏ = Math.cos(Ï *= d3_radians);
+ x0 = cosÏ * Math.cos(λ);
+ y0 = cosÏ * Math.sin(λ);
+ z0 = Math.sin(Ï);
+ d3_geo_centroid.point = nextPoint;
+ d3_geo_centroidPointXYZ(x0, y0, z0);
+ };
+ function nextPoint(λ, Ï) {
+ λ *= d3_radians;
+ var cosÏ = Math.cos(Ï *= d3_radians), x = cosÏ * Math.cos(λ), y = cosÏ *
Math.sin(λ), z = Math.sin(Ï), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w =
z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
+ d3_geo_centroidW1 += w;
+ d3_geo_centroidX1 += w * (x0 + (x0 = x));
+ d3_geo_centroidY1 += w * (y0 + (y0 = y));
+ d3_geo_centroidZ1 += w * (z0 + (z0 = z));
+ d3_geo_centroidPointXYZ(x0, y0, z0);
+ }
+ }
+ function d3_geo_centroidLineEnd() {
+ d3_geo_centroid.point = d3_geo_centroidPoint;
+ }
+ function d3_geo_centroidRingStart() {
+ var λ00, Ï00, x0, y0, z0;
+ d3_geo_centroid.point = function(λ, Ï) {
+ λ00 = λ, Ï00 = Ï;
+ d3_geo_centroid.point = nextPoint;
+ λ *= d3_radians;
+ var cosÏ = Math.cos(Ï *= d3_radians);
+ x0 = cosÏ * Math.cos(λ);
+ y0 = cosÏ * Math.sin(λ);
+ z0 = Math.sin(Ï);
+ d3_geo_centroidPointXYZ(x0, y0, z0);
+ };
+ d3_geo_centroid.lineEnd = function() {
+ nextPoint(λ00, Ï00);
+ d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
+ d3_geo_centroid.point = d3_geo_centroidPoint;
+ };
+ function nextPoint(λ, Ï) {
+ λ *= d3_radians;
+ var cosÏ = Math.cos(Ï *= d3_radians), x = cosÏ * Math.cos(λ), y = cosÏ *
Math.sin(λ), z = Math.sin(Ï), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y -
y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m
&& -d3_acos(u) / m, w = Math.atan2(m, u);
+ d3_geo_centroidX2 += v * cx;
+ d3_geo_centroidY2 += v * cy;
+ d3_geo_centroidZ2 += v * cz;
+ d3_geo_centroidW1 += w;
+ d3_geo_centroidX1 += w * (x0 + (x0 = x));
+ d3_geo_centroidY1 += w * (y0 + (y0 = y));
+ d3_geo_centroidZ1 += w * (z0 + (z0 = z));
+ d3_geo_centroidPointXYZ(x0, y0, z0);
+ }
+ }
+ function d3_true() {
+ return true;
+ }
+ function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener)
{
+ var subject = [], clip = [];
+ segments.forEach(function(segment) {
+ if ((n = segment.length - 1) <= 0) return;
+ var n, p0 = segment[0], p1 = segment[n];
+ if (d3_geo_sphericalEqual(p0, p1)) {
+ listener.lineStart();
+ for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
+ listener.lineEnd();
+ return;
+ }
+ var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new
d3_geo_clipPolygonIntersection(p0, null, a, false);
+ a.o = b;
+ subject.push(a);
+ clip.push(b);
+ a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);
+ b = new d3_geo_clipPolygonIntersection(p1, null, a, true);
+ a.o = b;
+ subject.push(a);
+ clip.push(b);
+ });
+ clip.sort(compare);
+ d3_geo_clipPolygonLinkCircular(subject);
+ d3_geo_clipPolygonLinkCircular(clip);
+ if (!subject.length) return;
+ for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {
+ clip[i].e = entry = !entry;
+ }
+ var start = subject[0], points, point;
+ while (1) {
+ var current = start, isSubject = true;
+ while (current.v) if ((current = current.n) === start) return;
+ points = current.z;
+ listener.lineStart();
+ do {
+ current.v = current.o.v = true;
+ if (current.e) {
+ if (isSubject) {
+ for (var i = 0, n = points.length; i < n; ++i) listener.point((point =
points[i])[0], point[1]);
+ } else {
+ interpolate(current.x, current.n.x, 1, listener);
+ }
+ current = current.n;
+ } else {
+ if (isSubject) {
+ points = current.p.z;
+ for (var i = points.length - 1; i >= 0; --i) listener.point((point =
points[i])[0], point[1]);
+ } else {
+ interpolate(current.x, current.p.x, -1, listener);
+ }
+ current = current.p;
+ }
+ current = current.o;
+ points = current.z;
+ isSubject = !isSubject;
+ } while (!current.v);
+ listener.lineEnd();
+ }
+ }
+ function d3_geo_clipPolygonLinkCircular(array) {
+ if (!(n = array.length)) return;
+ var n, i = 0, a = array[0], b;
+ while (++i < n) {
+ a.n = b = array[i];
+ b.p = a;
+ a = b;
+ }
+ a.n = b = array[0];
+ b.p = a;
+ }
+ function d3_geo_clipPolygonIntersection(point, points, other, entry) {
+ this.x = point;
+ this.z = points;
+ this.o = other;
+ this.e = entry;
+ this.v = false;
+ this.n = this.p = null;
+ }
+ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
+ return function(rotate, listener) {
+ var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0],
clipStart[1]);
+ var clip = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ clip.point = pointRing;
+ clip.lineStart = ringStart;
+ clip.lineEnd = ringEnd;
+ segments = [];
+ polygon = [];
+ listener.polygonStart();
+ },
+ polygonEnd: function() {
+ clip.point = point;
+ clip.lineStart = lineStart;
+ clip.lineEnd = lineEnd;
+ segments = d3.merge(segments);
+ var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
+ if (segments.length) {
+ d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate,
listener);
+ } else if (clipStartInside) {
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ }
+ listener.polygonEnd();
+ segments = polygon = null;
+ },
+ sphere: function() {
+ listener.polygonStart();
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ listener.polygonEnd();
+ }
+ };
+ function point(λ, Ï) {
+ var point = rotate(λ, Ï);
+ if (pointVisible(λ = point[0], Ï = point[1])) listener.point(λ, Ï);
+ }
+ function pointLine(λ, Ï) {
+ var point = rotate(λ, Ï);
+ line.point(point[0], point[1]);
+ }
+ function lineStart() {
+ clip.point = pointLine;
+ line.lineStart();
+ }
+ function lineEnd() {
+ clip.point = point;
+ line.lineEnd();
+ }
+ var segments;
+ var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon,
ring;
+ function pointRing(λ, Ï) {
+ ring.push([ λ, Ï ]);
+ var point = rotate(λ, Ï);
+ ringListener.point(point[0], point[1]);
+ }
+ function ringStart() {
+ ringListener.lineStart();
+ ring = [];
+ }
+ function ringEnd() {
+ pointRing(ring[0][0], ring[0][1]);
+ ringListener.lineEnd();
+ var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n =
ringSegments.length;
+ ring.pop();
+ polygon.push(ring);
+ ring = null;
+ if (!n) return;
+ if (clean & 1) {
+ segment = ringSegments[0];
+ var n = segment.length - 1, i = -1, point;
+ listener.lineStart();
+ while (++i < n) listener.point((point = segment[i])[0], point[1]);
+ listener.lineEnd();
+ return;
+ }
+ if (n > 1 && clean & 2)
ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
+ segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
+ }
+ return clip;
+ };
+ }
+ function d3_geo_clipSegmentLength1(segment) {
+ return segment.length > 1;
+ }
+ function d3_geo_clipBufferListener() {
+ var lines = [], line;
+ return {
+ lineStart: function() {
+ lines.push(line = []);
+ },
+ point: function(λ, Ï) {
+ line.push([ λ, Ï ]);
+ },
+ lineEnd: d3_noop,
+ buffer: function() {
+ var buffer = lines;
+ lines = [];
+ line = null;
+ return buffer;
+ },
+ rejoin: function() {
+ if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
+ }
+ };
+ }
+ function d3_geo_clipSort(a, b) {
+ return ((a = a.x)[0] < 0 ? a[1] - halfÏ - ε : halfÏ - a[1]) - ((b = b.x)[0]
< 0 ? b[1] - halfÏ - ε : halfÏ - b[1]);
+ }
+ function d3_geo_pointInPolygon(point, polygon) {
+ var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian),
-Math.cos(meridian), 0 ], polarAngle = 0, winding = 0;
+ d3_geo_areaRingSum.reset();
+ for (var i = 0, n = polygon.length; i < n; ++i) {
+ var ring = polygon[i], m = ring.length;
+ if (!m) continue;
+ var point0 = ring[0], λ0 = point0[0], Ï0 = point0[1] / 2 + Ï / 4, sinÏ0 =
Math.sin(Ï0), cosÏ0 = Math.cos(Ï0), j = 1;
+ while (true) {
+ if (j === m) j = 0;
+ point = ring[j];
+ var λ = point[0], Ï = point[1] / 2 + Ï / 4, sinÏ = Math.sin(Ï), cosÏ =
Math.cos(Ï), dλ = λ - λ0, antimeridian = abs(dλ) > Ï, k = sinÏ0 * sinÏ;
+ d3_geo_areaRingSum.add(Math.atan2(k * Math.sin(dλ), cosÏ0 * cosÏ + k *
Math.cos(dλ)));
+ polarAngle += antimeridian ? dλ + (dλ >= 0 ? Ï : -Ï) : dλ;
+ if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
+ var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0),
d3_geo_cartesian(point));
+ d3_geo_cartesianNormalize(arc);
+ var intersection = d3_geo_cartesianCross(meridianNormal, arc);
+ d3_geo_cartesianNormalize(intersection);
+ var Ïarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
+ if (parallel > Ïarc || parallel === Ïarc && (arc[0] || arc[1])) {
+ winding += antimeridian ^ dλ >= 0 ? 1 : -1;
+ }
+ }
+ if (!j++) break;
+ λ0 = λ, sinÏ0 = sinÏ, cosÏ0 = cosÏ, point0 = point;
+ }
+ }
+ return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum <
0) ^ winding & 1;
+ }
+ var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine,
d3_geo_clipAntimeridianInterpolate, [ -Ï, -Ï / 2 ]);
+ function d3_geo_clipAntimeridianLine(listener) {
+ var λ0 = NaN, Ï0 = NaN, sλ0 = NaN, clean;
+ return {
+ lineStart: function() {
+ listener.lineStart();
+ clean = 1;
+ },
+ point: function(λ1, Ï1) {
+ var sλ1 = λ1 > 0 ? Ï : -Ï, dλ = abs(λ1 - λ0);
+ if (abs(dλ - Ï) < ε) {
+ listener.point(λ0, Ï0 = (Ï0 + Ï1) / 2 > 0 ? halfÏ : -halfÏ);
+ listener.point(sλ0, Ï0);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(sλ1, Ï0);
+ listener.point(λ1, Ï0);
+ clean = 0;
+ } else if (sλ0 !== sλ1 && dλ >= Ï) {
+ if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
+ if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
+ Ï0 = d3_geo_clipAntimeridianIntersect(λ0, Ï0, λ1, Ï1);
+ listener.point(sλ0, Ï0);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(sλ1, Ï0);
+ clean = 0;
+ }
+ listener.point(λ0 = λ1, Ï0 = Ï1);
+ sλ0 = sλ1;
+ },
+ lineEnd: function() {
+ listener.lineEnd();
+ λ0 = Ï0 = NaN;
+ },
+ clean: function() {
+ return 2 - clean;
+ }
+ };
+ }
+ function d3_geo_clipAntimeridianIntersect(λ0, Ï0, λ1, Ï1) {
+ var cosÏ0, cosÏ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
+ return abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(Ï0) * (cosÏ1 = Math.cos(Ï1))
* Math.sin(λ1) - Math.sin(Ï1) * (cosÏ0 = Math.cos(Ï0)) * Math.sin(λ0)) / (cosÏ0 *
cosÏ1 * sinλ0_λ1)) : (Ï0 + Ï1) / 2;
+ }
+ function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
+ var Ï;
+ if (from == null) {
+ Ï = direction * halfÏ;
+ listener.point(-Ï, Ï);
+ listener.point(0, Ï);
+ listener.point(Ï, Ï);
+ listener.point(Ï, 0);
+ listener.point(Ï, -Ï);
+ listener.point(0, -Ï);
+ listener.point(-Ï, -Ï);
+ listener.point(-Ï, 0);
+ listener.point(-Ï, Ï);
+ } else if (abs(from[0] - to[0]) > ε) {
+ var s = from[0] < to[0] ? Ï : -Ï;
+ Ï = direction * s / 2;
+ listener.point(-s, Ï);
+ listener.point(0, Ï);
+ listener.point(s, Ï);
+ } else {
+ listener.point(to[0], to[1]);
+ }
+ }
+ function d3_geo_clipCircle(radius) {
+ var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε,
interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);
+ return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [
-Ï, radius - Ï ]);
+ function visible(λ, Ï) {
+ return Math.cos(λ) * Math.cos(Ï) > cr;
+ }
+ function clipLine(listener) {
+ var point0, c0, v0, v00, clean;
+ return {
+ lineStart: function() {
+ v00 = v0 = false;
+ clean = 1;
+ },
+ point: function(λ, Ï) {
+ var point1 = [ λ, Ï ], point2, v = visible(λ, Ï), c = smallRadius ? v ? 0 :
code(λ, Ï) : v ? code(λ + (λ < 0 ? Ï : -Ï), Ï) : 0;
+ if (!point0 && (v00 = v0 = v)) listener.lineStart();
+ if (v !== v0) {
+ point2 = intersect(point0, point1);
+ if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1,
point2)) {
+ point1[0] += ε;
+ point1[1] += ε;
+ v = visible(point1[0], point1[1]);
+ }
+ }
+ if (v !== v0) {
+ clean = 0;
+ if (v) {
+ listener.lineStart();
+ point2 = intersect(point1, point0);
+ listener.point(point2[0], point2[1]);
+ } else {
+ point2 = intersect(point0, point1);
+ listener.point(point2[0], point2[1]);
+ listener.lineEnd();
+ }
+ point0 = point2;
+ } else if (notHemisphere && point0 && smallRadius ^ v) {
+ var t;
+ if (!(c & c0) && (t = intersect(point1, point0, true))) {
+ clean = 0;
+ if (smallRadius) {
+ listener.lineStart();
+ listener.point(t[0][0], t[0][1]);
+ listener.point(t[1][0], t[1][1]);
+ listener.lineEnd();
+ } else {
+ listener.point(t[1][0], t[1][1]);
+ listener.lineEnd();
+ listener.lineStart();
+ listener.point(t[0][0], t[0][1]);
+ }
+ }
+ }
+ if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
+ listener.point(point1[0], point1[1]);
+ }
+ point0 = point1, v0 = v, c0 = c;
+ },
+ lineEnd: function() {
+ if (v0) listener.lineEnd();
+ point0 = null;
+ },
+ clean: function() {
+ return clean | (v00 && v0) << 1;
+ }
+ };
+ }
+ function intersect(a, b, two) {
+ var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b);
+ var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 =
d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
+ if (!determinant) return !two && a;
+ var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 =
d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B =
d3_geo_cartesianScale(n2, c2);
+ d3_geo_cartesianAdd(A, B);
+ var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 =
w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
+ if (t2 < 0) return;
+ var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu);
+ d3_geo_cartesianAdd(q, A);
+ q = d3_geo_spherical(q);
+ if (!two) return q;
+ var λ0 = a[0], λ1 = b[0], Ï0 = a[1], Ï1 = b[1], z;
+ if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
+ var Ύλ = λ1 - λ0, polar = abs(Ύλ - Ï) < ε, meridian = polar || Ύλ <
ε;
+ if (!polar && Ï1 < Ï0) z = Ï0, Ï0 = Ï1, Ï1 = z;
+ if (meridian ? polar ? Ï0 + Ï1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? Ï0
: Ï1) : Ï0 <= q[1] && q[1] <= Ï1 : Ύλ > Ï ^ (λ0 <= q[0]
&& q[0] <= λ1)) {
+ var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
+ d3_geo_cartesianAdd(q1, A);
+ return [ q, d3_geo_spherical(q1) ];
+ }
+ }
+ function code(λ, Ï) {
+ var r = smallRadius ? radius : Ï - radius, code = 0;
+ if (λ < -r) code |= 1; else if (λ > r) code |= 2;
+ if (Ï < -r) code |= 4; else if (Ï > r) code |= 8;
+ return code;
+ }
+ }
+ function d3_geom_clipLine(x0, y0, x1, y1) {
+ return function(line) {
+ var a = line.a, b = line.b, ax = a.x, ay = a.y, bx = b.x, by = b.y, t0 = 0, t1 = 1,
dx = bx - ax, dy = by - ay, r;
+ r = x0 - ax;
+ if (!dx && r > 0) return;
+ r /= dx;
+ if (dx < 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ } else if (dx > 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ }
+ r = x1 - ax;
+ if (!dx && r < 0) return;
+ r /= dx;
+ if (dx < 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ } else if (dx > 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ }
+ r = y0 - ay;
+ if (!dy && r > 0) return;
+ r /= dy;
+ if (dy < 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ } else if (dy > 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ }
+ r = y1 - ay;
+ if (!dy && r < 0) return;
+ r /= dy;
+ if (dy < 0) {
+ if (r > t1) return;
+ if (r > t0) t0 = r;
+ } else if (dy > 0) {
+ if (r < t0) return;
+ if (r < t1) t1 = r;
+ }
+ if (t0 > 0) line.a = {
+ x: ax + t0 * dx,
+ y: ay + t0 * dy
+ };
+ if (t1 < 1) line.b = {
+ x: ax + t1 * dx,
+ y: ay + t1 * dy
+ };
+ return line;
+ };
+ }
+ var d3_geo_clipExtentMAX = 1e9;
+ d3.geo.clipExtent = function() {
+ var x0, y0, x1, y1, stream, clip, clipExtent = {
+ stream: function(output) {
+ if (stream) stream.valid = false;
+ stream = clip(output);
+ stream.valid = true;
+ return stream;
+ },
+ extent: function(_) {
+ if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
+ clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 =
+_[1][1]);
+ if (stream) stream.valid = false, stream = null;
+ return clipExtent;
+ }
+ };
+ return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]);
+ };
+ function d3_geo_clipExtent(x0, y0, x1, y1) {
+ return function(listener) {
+ var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine =
d3_geom_clipLine(x0, y0, x1, y1), segments, polygon, ring;
+ var clip = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ listener = bufferListener;
+ segments = [];
+ polygon = [];
+ clean = true;
+ },
+ polygonEnd: function() {
+ listener = listener_;
+ segments = d3.merge(segments);
+ var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean &&
clipStartInside, visible = segments.length;
+ if (inside || visible) {
+ listener.polygonStart();
+ if (inside) {
+ listener.lineStart();
+ interpolate(null, null, 1, listener);
+ listener.lineEnd();
+ }
+ if (visible) {
+ d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate,
listener);
+ }
+ listener.polygonEnd();
+ }
+ segments = polygon = ring = null;
+ }
+ };
+ function insidePolygon(p) {
+ var wn = 0, n = polygon.length, y = p[1];
+ for (var i = 0; i < n; ++i) {
+ for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
+ b = v[j];
+ if (a[1] <= y) {
+ if (b[1] > y && isLeft(a, b, p) > 0) ++wn;
+ } else {
+ if (b[1] <= y && isLeft(a, b, p) < 0) --wn;
+ }
+ a = b;
+ }
+ }
+ return wn !== 0;
+ }
+ function isLeft(a, b, c) {
+ return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
+ }
+ function interpolate(from, to, direction, listener) {
+ var a = 0, a1 = 0;
+ if (from == null || (a = corner(from, direction)) !== (a1 = corner(to,
direction)) || comparePoints(from, to) < 0 ^ direction > 0) {
+ do {
+ listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
+ } while ((a = (a + direction + 4) % 4) !== a1);
+ } else {
+ listener.point(to[0], to[1]);
+ }
+ }
+ function pointVisible(x, y) {
+ return x0 <= x && x <= x1 && y0 <= y && y <=
y1;
+ }
+ function point(x, y) {
+ if (pointVisible(x, y)) listener.point(x, y);
+ }
+ var x__, y__, v__, x_, y_, v_, first, clean;
+ function lineStart() {
+ clip.point = linePoint;
+ if (polygon) polygon.push(ring = []);
+ first = true;
+ v_ = false;
+ x_ = y_ = NaN;
+ }
+ function lineEnd() {
+ if (segments) {
+ linePoint(x__, y__);
+ if (v__ && v_) bufferListener.rejoin();
+ segments.push(bufferListener.buffer());
+ }
+ clip.point = point;
+ if (v_) listener.lineEnd();
+ }
+ function linePoint(x, y) {
+ x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
+ y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
+ var v = pointVisible(x, y);
+ if (polygon) ring.push([ x, y ]);
+ if (first) {
+ x__ = x, y__ = y, v__ = v;
+ first = false;
+ if (v) {
+ listener.lineStart();
+ listener.point(x, y);
+ }
+ } else {
+ if (v && v_) listener.point(x, y); else {
+ var l = {
+ a: {
+ x: x_,
+ y: y_
+ },
+ b: {
+ x: x,
+ y: y
+ }
+ };
+ if (clipLine(l)) {
+ if (!v_) {
+ listener.lineStart();
+ listener.point(l.a.x, l.a.y);
+ }
+ listener.point(l.b.x, l.b.y);
+ if (!v) listener.lineEnd();
+ clean = false;
+ } else if (v) {
+ listener.lineStart();
+ listener.point(x, y);
+ clean = false;
+ }
+ }
+ }
+ x_ = x, y_ = y, v_ = v;
+ }
+ return clip;
+ };
+ function corner(p, direction) {
+ return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : abs(p[0] - x1) < ε ?
direction > 0 ? 2 : 1 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction
> 0 ? 3 : 2;
+ }
+ function compare(a, b) {
+ return comparePoints(a.x, b.x);
+ }
+ function comparePoints(a, b) {
+ var ca = corner(a, 1), cb = corner(b, 1);
+ return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca
=== 2 ? a[1] - b[1] : b[0] - a[0];
+ }
+ }
+ function d3_geo_compose(a, b) {
+ function compose(x, y) {
+ return x = a(x, y), b(x[0], x[1]);
+ }
+ if (a.invert && b.invert) compose.invert = function(x, y) {
+ return x = b.invert(x, y), x && a.invert(x[0], x[1]);
+ };
+ return compose;
+ }
+ function d3_geo_conic(projectAt) {
+ var Ï0 = 0, Ï1 = Ï / 3, m = d3_geo_projectionMutator(projectAt), p = m(Ï0, Ï1);
+ p.parallels = function(_) {
+ if (!arguments.length) return [ Ï0 / Ï * 180, Ï1 / Ï * 180 ];
+ return m(Ï0 = _[0] * Ï / 180, Ï1 = _[1] * Ï / 180);
+ };
+ return p;
+ }
+ function d3_geo_conicEqualArea(Ï0, Ï1) {
+ var sinÏ0 = Math.sin(Ï0), n = (sinÏ0 + Math.sin(Ï1)) / 2, C = 1 + sinÏ0 * (2 * n
- sinÏ0), Ï0 = Math.sqrt(C) / n;
+ function forward(λ, Ï) {
+ var Ï = Math.sqrt(C - 2 * n * Math.sin(Ï)) / n;
+ return [ Ï * Math.sin(λ *= n), Ï0 - Ï * Math.cos(λ) ];
+ }
+ forward.invert = function(x, y) {
+ var Ï0_y = Ï0 - y;
+ return [ Math.atan2(x, Ï0_y) / n, d3_asin((C - (x * x + Ï0_y * Ï0_y) * n * n) /
(2 * n)) ];
+ };
+ return forward;
+ }
+ (d3.geo.conicEqualArea = function() {
+ return d3_geo_conic(d3_geo_conicEqualArea);
+ }).raw = d3_geo_conicEqualArea;
+ d3.geo.albers = function() {
+ return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([
29.5, 45.5 ]).scale(1070);
+ };
+ d3.geo.albersUsa = function() {
+ var lower48 = d3.geo.albers();
+ var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5
]).parallels([ 55, 65 ]);
+ var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9
]).parallels([ 8, 18 ]);
+ var point, pointStream = {
+ point: function(x, y) {
+ point = [ x, y ];
+ }
+ }, lower48Point, alaskaPoint, hawaiiPoint;
+ function albersUsa(coordinates) {
+ var x = coordinates[0], y = coordinates[1];
+ point = null;
+ (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y);
+ return point;
+ }
+ albersUsa.invert = function(coordinates) {
+ var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k,
y = (coordinates[1] - t[1]) / k;
+ return (y >= .12 && y < .234 && x >= -.425 && x
< -.214 ? alaska : y >= .166 && y < .234 && x >= -.214
&& x < -.115 ? hawaii : lower48).invert(coordinates);
+ };
+ albersUsa.stream = function(stream) {
+ var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream),
hawaiiStream = hawaii.stream(stream);
+ return {
+ point: function(x, y) {
+ lower48Stream.point(x, y);
+ alaskaStream.point(x, y);
+ hawaiiStream.point(x, y);
+ },
+ sphere: function() {
+ lower48Stream.sphere();
+ alaskaStream.sphere();
+ hawaiiStream.sphere();
+ },
+ lineStart: function() {
+ lower48Stream.lineStart();
+ alaskaStream.lineStart();
+ hawaiiStream.lineStart();
+ },
+ lineEnd: function() {
+ lower48Stream.lineEnd();
+ alaskaStream.lineEnd();
+ hawaiiStream.lineEnd();
+ },
+ polygonStart: function() {
+ lower48Stream.polygonStart();
+ alaskaStream.polygonStart();
+ hawaiiStream.polygonStart();
+ },
+ polygonEnd: function() {
+ lower48Stream.polygonEnd();
+ alaskaStream.polygonEnd();
+ hawaiiStream.polygonEnd();
+ }
+ };
+ };
+ albersUsa.precision = function(_) {
+ if (!arguments.length) return lower48.precision();
+ lower48.precision(_);
+ alaska.precision(_);
+ hawaii.precision(_);
+ return albersUsa;
+ };
+ albersUsa.scale = function(_) {
+ if (!arguments.length) return lower48.scale();
+ lower48.scale(_);
+ alaska.scale(_ * .35);
+ hawaii.scale(_);
+ return albersUsa.translate(lower48.translate());
+ };
+ albersUsa.translate = function(_) {
+ if (!arguments.length) return lower48.translate();
+ var k = lower48.scale(), x = +_[0], y = +_[1];
+ lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [
x + .455 * k, y + .238 * k ] ]).stream(pointStream).point;
+ alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x -
.425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ]
]).stream(pointStream).point;
+ hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x -
.214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ]
]).stream(pointStream).point;
+ return albersUsa;
+ };
+ return albersUsa.scale(1070);
+ };
+ var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
+ point: d3_noop,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: function() {
+ d3_geo_pathAreaPolygon = 0;
+ d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point =
d3_noop;
+ d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2);
+ }
+ };
+ function d3_geo_pathAreaRingStart() {
+ var x00, y00, x0, y0;
+ d3_geo_pathArea.point = function(x, y) {
+ d3_geo_pathArea.point = nextPoint;
+ x00 = x0 = x, y00 = y0 = y;
+ };
+ function nextPoint(x, y) {
+ d3_geo_pathAreaPolygon += y0 * x - x0 * y;
+ x0 = x, y0 = y;
+ }
+ d3_geo_pathArea.lineEnd = function() {
+ nextPoint(x00, y00);
+ };
+ }
+ var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1,
d3_geo_pathBoundsY1;
+ var d3_geo_pathBounds = {
+ point: d3_geo_pathBoundsPoint,
+ lineStart: d3_noop,
+ lineEnd: d3_noop,
+ polygonStart: d3_noop,
+ polygonEnd: d3_noop
+ };
+ function d3_geo_pathBoundsPoint(x, y) {
+ if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
+ if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
+ if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
+ if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
+ }
+ function d3_geo_pathBuffer() {
+ var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = [];
+ var stream = {
+ point: point,
+ lineStart: function() {
+ stream.point = pointLineStart;
+ },
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.lineEnd = lineEndPolygon;
+ },
+ polygonEnd: function() {
+ stream.lineEnd = lineEnd;
+ stream.point = point;
+ },
+ pointRadius: function(_) {
+ pointCircle = d3_geo_pathBufferCircle(_);
+ return stream;
+ },
+ result: function() {
+ if (buffer.length) {
+ var result = buffer.join("");
+ buffer = [];
+ return result;
+ }
+ }
+ };
+ function point(x, y) {
+ buffer.push("M", x, ",", y, pointCircle);
+ }
+ function pointLineStart(x, y) {
+ buffer.push("M", x, ",", y);
+ stream.point = pointLine;
+ }
+ function pointLine(x, y) {
+ buffer.push("L", x, ",", y);
+ }
+ function lineEnd() {
+ stream.point = point;
+ }
+ function lineEndPolygon() {
+ buffer.push("Z");
+ }
+ return stream;
+ }
+ function d3_geo_pathBufferCircle(radius) {
+ return "m0," + radius + "a" + radius + "," + radius +
" 0 1,1 0," + -2 * radius + "a" + radius + "," + radius +
" 0 1,1 0," + 2 * radius + "z";
+ }
+ var d3_geo_pathCentroid = {
+ point: d3_geo_pathCentroidPoint,
+ lineStart: d3_geo_pathCentroidLineStart,
+ lineEnd: d3_geo_pathCentroidLineEnd,
+ polygonStart: function() {
+ d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
+ },
+ polygonEnd: function() {
+ d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+ d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
+ d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
+ }
+ };
+ function d3_geo_pathCentroidPoint(x, y) {
+ d3_geo_centroidX0 += x;
+ d3_geo_centroidY0 += y;
+ ++d3_geo_centroidZ0;
+ }
+ function d3_geo_pathCentroidLineStart() {
+ var x0, y0;
+ d3_geo_pathCentroid.point = function(x, y) {
+ d3_geo_pathCentroid.point = nextPoint;
+ d3_geo_pathCentroidPoint(x0 = x, y0 = y);
+ };
+ function nextPoint(x, y) {
+ var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
+ d3_geo_centroidX1 += z * (x0 + x) / 2;
+ d3_geo_centroidY1 += z * (y0 + y) / 2;
+ d3_geo_centroidZ1 += z;
+ d3_geo_pathCentroidPoint(x0 = x, y0 = y);
+ }
+ }
+ function d3_geo_pathCentroidLineEnd() {
+ d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
+ }
+ function d3_geo_pathCentroidRingStart() {
+ var x00, y00, x0, y0;
+ d3_geo_pathCentroid.point = function(x, y) {
+ d3_geo_pathCentroid.point = nextPoint;
+ d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
+ };
+ function nextPoint(x, y) {
+ var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
+ d3_geo_centroidX1 += z * (x0 + x) / 2;
+ d3_geo_centroidY1 += z * (y0 + y) / 2;
+ d3_geo_centroidZ1 += z;
+ z = y0 * x - x0 * y;
+ d3_geo_centroidX2 += z * (x0 + x);
+ d3_geo_centroidY2 += z * (y0 + y);
+ d3_geo_centroidZ2 += z * 3;
+ d3_geo_pathCentroidPoint(x0 = x, y0 = y);
+ }
+ d3_geo_pathCentroid.lineEnd = function() {
+ nextPoint(x00, y00);
+ };
+ }
+ function d3_geo_pathContext(context) {
+ var pointRadius = 4.5;
+ var stream = {
+ point: point,
+ lineStart: function() {
+ stream.point = pointLineStart;
+ },
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.lineEnd = lineEndPolygon;
+ },
+ polygonEnd: function() {
+ stream.lineEnd = lineEnd;
+ stream.point = point;
+ },
+ pointRadius: function(_) {
+ pointRadius = _;
+ return stream;
+ },
+ result: d3_noop
+ };
+ function point(x, y) {
+ context.moveTo(x, y);
+ context.arc(x, y, pointRadius, 0, Ï);
+ }
+ function pointLineStart(x, y) {
+ context.moveTo(x, y);
+ stream.point = pointLine;
+ }
+ function pointLine(x, y) {
+ context.lineTo(x, y);
+ }
+ function lineEnd() {
+ stream.point = point;
+ }
+ function lineEndPolygon() {
+ context.closePath();
+ }
+ return stream;
+ }
+ function d3_geo_resample(project) {
+ var ÎŽ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16;
+ function resample(stream) {
+ return (maxDepth ? resampleRecursive : resampleNone)(stream);
+ }
+ function resampleNone(stream) {
+ return d3_geo_transformPoint(stream, function(x, y) {
+ x = project(x, y);
+ stream.point(x[0], x[1]);
+ });
+ }
+ function resampleRecursive(stream) {
+ var λ00, Ï00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0;
+ var resample = {
+ point: point,
+ lineStart: lineStart,
+ lineEnd: lineEnd,
+ polygonStart: function() {
+ stream.polygonStart();
+ resample.lineStart = ringStart;
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ resample.lineStart = lineStart;
+ }
+ };
+ function point(x, y) {
+ x = project(x, y);
+ stream.point(x[0], x[1]);
+ }
+ function lineStart() {
+ x0 = NaN;
+ resample.point = linePoint;
+ stream.lineStart();
+ }
+ function linePoint(λ, Ï) {
+ var c = d3_geo_cartesian([ λ, Ï ]), p = project(λ, Ï);
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 =
c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
+ stream.point(x0, y0);
+ }
+ function lineEnd() {
+ resample.point = point;
+ stream.lineEnd();
+ }
+ function ringStart() {
+ lineStart();
+ resample.point = ringPoint;
+ resample.lineEnd = ringEnd;
+ }
+ function ringPoint(λ, Ï) {
+ linePoint(λ00 = λ, Ï00 = Ï), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 =
c0;
+ resample.point = linePoint;
+ }
+ function ringEnd() {
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth,
stream);
+ resample.lineEnd = lineEnd;
+ lineEnd();
+ }
+ return resample;
+ }
+ function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth,
stream) {
+ var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
+ if (d2 > 4 * ÎŽ2 && depth--) {
+ var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c),
Ï2 = Math.asin(c /= m), λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 +
λ1) / 2 : Math.atan2(b, a), p = project(λ2, Ï2), x2 = p[0], y2 = p[1], dx2 = x2 - x0,
dy2 = y2 - y0, dz = dy * dx2 - dx * dy2;
+ if (dz * dz / d2 > ÎŽ2 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 *
a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
+ resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth,
stream);
+ stream.point(x2, y2);
+ resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
+ }
+ }
+ }
+ resample.precision = function(_) {
+ if (!arguments.length) return Math.sqrt(ÎŽ2);
+ maxDepth = (ÎŽ2 = _ * _) > 0 && 16;
+ return resample;
+ };
+ return resample;
+ }
+ d3.geo.path = function() {
+ var pointRadius = 4.5, projection, context, projectStream, contextStream,
cacheStream;
+ function path(object) {
+ if (object) {
+ if (typeof pointRadius === "function")
contextStream.pointRadius(+pointRadius.apply(this, arguments));
+ if (!cacheStream || !cacheStream.valid) cacheStream =
projectStream(contextStream);
+ d3.geo.stream(object, cacheStream);
+ }
+ return contextStream.result();
+ }
+ path.area = function(object) {
+ d3_geo_pathAreaSum = 0;
+ d3.geo.stream(object, projectStream(d3_geo_pathArea));
+ return d3_geo_pathAreaSum;
+ };
+ path.centroid = function(object) {
+ d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 =
d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 =
d3_geo_centroidZ2 = 0;
+ d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
+ return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2,
d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 /
d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [
d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN,
NaN ];
+ };
+ path.bounds = function(object) {
+ d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 =
d3_geo_pathBoundsY0 = Infinity);
+ d3.geo.stream(object, projectStream(d3_geo_pathBounds));
+ return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1,
d3_geo_pathBoundsY1 ] ];
+ };
+ path.projection = function(_) {
+ if (!arguments.length) return projection;
+ projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) :
d3_identity;
+ return reset();
+ };
+ path.context = function(_) {
+ if (!arguments.length) return context;
+ contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new
d3_geo_pathContext(_);
+ if (typeof pointRadius !== "function")
contextStream.pointRadius(pointRadius);
+ return reset();
+ };
+ path.pointRadius = function(_) {
+ if (!arguments.length) return pointRadius;
+ pointRadius = typeof _ === "function" ? _ :
(contextStream.pointRadius(+_), +_);
+ return path;
+ };
+ function reset() {
+ cacheStream = null;
+ return path;
+ }
+ return path.projection(d3.geo.albersUsa()).context(null);
+ };
+ function d3_geo_pathProjectStream(project) {
+ var resample = d3_geo_resample(function(x, y) {
+ return project([ x * d3_degrees, y * d3_degrees ]);
+ });
+ return function(stream) {
+ return d3_geo_projectionRadians(resample(stream));
+ };
+ }
+ d3.geo.transform = function(methods) {
+ return {
+ stream: function(stream) {
+ var transform = new d3_geo_transform(stream);
+ for (var k in methods) transform[k] = methods[k];
+ return transform;
+ }
+ };
+ };
+ function d3_geo_transform(stream) {
+ this.stream = stream;
+ }
+ d3_geo_transform.prototype = {
+ point: function(x, y) {
+ this.stream.point(x, y);
+ },
+ 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();
+ }
+ };
+ function d3_geo_transformPoint(stream, point) {
+ return {
+ point: point,
+ sphere: function() {
+ stream.sphere();
+ },
+ lineStart: function() {
+ stream.lineStart();
+ },
+ lineEnd: function() {
+ stream.lineEnd();
+ },
+ polygonStart: function() {
+ stream.polygonStart();
+ },
+ polygonEnd: function() {
+ stream.polygonEnd();
+ }
+ };
+ }
+ d3.geo.projection = d3_geo_projection;
+ d3.geo.projectionMutator = d3_geo_projectionMutator;
+ function d3_geo_projection(project) {
+ return d3_geo_projectionMutator(function() {
+ return project;
+ })();
+ }
+ function d3_geo_projectionMutator(projectAt) {
+ var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y)
{
+ x = project(x, y);
+ return [ x[0] * k + ÎŽx, ÎŽy - x[1] * k ];
+ }), k = 150, x = 480, y = 250, λ = 0, Ï = 0, Ύλ = 0, ÎŽÏ = 0, Ύγ = 0, ÎŽx,
ÎŽy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null,
clipExtent = null, stream;
+ function projection(point) {
+ point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
+ return [ point[0] * k + ÎŽx, ÎŽy - point[1] * k ];
+ }
+ function invert(point) {
+ point = projectRotate.invert((point[0] - ÎŽx) / k, (ÎŽy - point[1]) / k);
+ return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];
+ }
+ projection.stream = function(output) {
+ if (stream) stream.valid = false;
+ stream = d3_geo_projectionRadians(preclip(rotate,
projectResample(postclip(output))));
+ stream.valid = true;
+ return stream;
+ };
+ projection.clipAngle = function(_) {
+ if (!arguments.length) return clipAngle;
+ preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) :
d3_geo_clipCircle((clipAngle = +_) * d3_radians);
+ return invalidate();
+ };
+ projection.clipExtent = function(_) {
+ if (!arguments.length) return clipExtent;
+ clipExtent = _;
+ postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) :
d3_identity;
+ return invalidate();
+ };
+ projection.scale = function(_) {
+ if (!arguments.length) return k;
+ k = +_;
+ return reset();
+ };
+ projection.translate = function(_) {
+ if (!arguments.length) return [ x, y ];
+ x = +_[0];
+ y = +_[1];
+ return reset();
+ };
+ projection.center = function(_) {
+ if (!arguments.length) return [ λ * d3_degrees, Ï * d3_degrees ];
+ λ = _[0] % 360 * d3_radians;
+ Ï = _[1] % 360 * d3_radians;
+ return reset();
+ };
+ projection.rotate = function(_) {
+ if (!arguments.length) return [ Ύλ * d3_degrees, ÎŽÏ * d3_degrees, Ύγ *
d3_degrees ];
+ Ύλ = _[0] % 360 * d3_radians;
+ ÎŽÏ = _[1] % 360 * d3_radians;
+ Ύγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
+ return reset();
+ };
+ d3.rebind(projection, projectResample, "precision");
+ function reset() {
+ projectRotate = d3_geo_compose(rotate = d3_geo_rotation(Ύλ, ÎŽÏ, Ύγ),
project);
+ var center = project(λ, Ï);
+ ÎŽx = x - center[0] * k;
+ ÎŽy = y + center[1] * k;
+ return invalidate();
+ }
+ function invalidate() {
+ if (stream) stream.valid = false, stream = null;
+ return projection;
+ }
+ return function() {
+ project = projectAt.apply(this, arguments);
+ projection.invert = project.invert && invert;
+ return reset();
+ };
+ }
+ function d3_geo_projectionRadians(stream) {
+ return d3_geo_transformPoint(stream, function(x, y) {
+ stream.point(x * d3_radians, y * d3_radians);
+ });
+ }
+ function d3_geo_equirectangular(λ, Ï) {
+ return [ λ, Ï ];
+ }
+ (d3.geo.equirectangular = function() {
+ return d3_geo_projection(d3_geo_equirectangular);
+ }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
+ d3.geo.rotation = function(rotate) {
+ rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians,
rotate.length > 2 ? rotate[2] * d3_radians : 0);
+ function forward(coordinates) {
+ coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
+ return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
+ }
+ forward.invert = function(coordinates) {
+ coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] *
d3_radians);
+ return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
+ };
+ return forward;
+ };
+ function d3_geo_identityRotation(λ, Ï) {
+ return [ λ > Ï ? λ - Ï : λ < -Ï ? λ + Ï : λ, Ï ];
+ }
+ d3_geo_identityRotation.invert = d3_geo_equirectangular;
+ function d3_geo_rotation(Ύλ, ÎŽÏ, Ύγ) {
+ return Ύλ ? ÎŽÏ || Ύγ ? d3_geo_compose(d3_geo_rotationλ(Ύλ),
d3_geo_rotationÏγ(ÎŽÏ, Ύγ)) : d3_geo_rotationλ(Ύλ) : ÎŽÏ || Ύγ ?
d3_geo_rotationÏγ(ÎŽÏ, Ύγ) : d3_geo_identityRotation;
+ }
+ function d3_geo_forwardRotationλ(Ύλ) {
+ return function(λ, Ï) {
+ return λ += Ύλ, [ λ > Ï ? λ - Ï : λ < -Ï ? λ + Ï : λ, Ï ];
+ };
+ }
+ function d3_geo_rotationλ(Ύλ) {
+ var rotation = d3_geo_forwardRotationλ(Ύλ);
+ rotation.invert = d3_geo_forwardRotationλ(-Ύλ);
+ return rotation;
+ }
+ function d3_geo_rotationÏγ(ÎŽÏ, Ύγ) {
+ var cosÎŽÏ = Math.cos(ÎŽÏ), sinÎŽÏ = Math.sin(ÎŽÏ), cosΎγ = Math.cos(Ύγ),
sinΎγ = Math.sin(Ύγ);
+ function rotation(λ, Ï) {
+ var cosÏ = Math.cos(Ï), x = Math.cos(λ) * cosÏ, y = Math.sin(λ) * cosÏ, z =
Math.sin(Ï), k = z * cosÎŽÏ + x * sinÎŽÏ;
+ return [ Math.atan2(y * cosΎγ - k * sinΎγ, x * cosÎŽÏ - z * sinÎŽÏ),
d3_asin(k * cosΎγ + y * sinΎγ) ];
+ }
+ rotation.invert = function(λ, Ï) {
+ var cosÏ = Math.cos(Ï), x = Math.cos(λ) * cosÏ, y = Math.sin(λ) * cosÏ, z =
Math.sin(Ï), k = z * cosΎγ - y * sinΎγ;
+ return [ Math.atan2(y * cosΎγ + z * sinΎγ, x * cosÎŽÏ + k * sinÎŽÏ),
d3_asin(k * cosÎŽÏ - x * sinÎŽÏ) ];
+ };
+ return rotation;
+ }
+ d3.geo.circle = function() {
+ var origin = [ 0, 0 ], angle, precision = 6, interpolate;
+ function circle() {
+ var center = typeof origin === "function" ? origin.apply(this, arguments)
: origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians,
0).invert, ring = [];
+ interpolate(null, null, 1, {
+ point: function(x, y) {
+ ring.push(x = rotate(x, y));
+ x[0] *= d3_degrees, x[1] *= d3_degrees;
+ }
+ });
+ return {
+ type: "Polygon",
+ coordinates: [ ring ]
+ };
+ }
+ circle.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return circle;
+ };
+ circle.angle = function(x) {
+ if (!arguments.length) return angle;
+ interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision *
d3_radians);
+ return circle;
+ };
+ circle.precision = function(_) {
+ if (!arguments.length) return precision;
+ interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) *
d3_radians);
+ return circle;
+ };
+ return circle.angle(90);
+ };
+ function d3_geo_circleInterpolate(radius, precision) {
+ var cr = Math.cos(radius), sr = Math.sin(radius);
+ return function(from, to, direction, listener) {
+ var step = direction * precision;
+ if (from != null) {
+ from = d3_geo_circleAngle(cr, from);
+ to = d3_geo_circleAngle(cr, to);
+ if (direction > 0 ? from < to : from > to) from += direction * Ï;
+ } else {
+ from = radius + direction * Ï;
+ to = radius - .5 * step;
+ }
+ for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) {
+ listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr *
Math.sin(t) ]))[0], point[1]);
+ }
+ };
+ }
+ function d3_geo_circleAngle(cr, point) {
+ var a = d3_geo_cartesian(point);
+ a[0] -= cr;
+ d3_geo_cartesianNormalize(a);
+ var angle = d3_acos(-a[1]);
+ return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
+ }
+ d3.geo.distance = function(a, b) {
+ var Îλ = (b[0] - a[0]) * d3_radians, Ï0 = a[1] * d3_radians, Ï1 = b[1] *
d3_radians, sinÎλ = Math.sin(Îλ), cosÎλ = Math.cos(Îλ), sinÏ0 = Math.sin(Ï0),
cosÏ0 = Math.cos(Ï0), sinÏ1 = Math.sin(Ï1), cosÏ1 = Math.cos(Ï1), t;
+ return Math.atan2(Math.sqrt((t = cosÏ1 * sinÎλ) * t + (t = cosÏ0 * sinÏ1 -
sinÏ0 * cosÏ1 * cosÎλ) * t), sinÏ0 * sinÏ1 + cosÏ0 * cosÏ1 * cosÎλ);
+ };
+ d3.geo.graticule = function() {
+ var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y,
precision = 2.5;
+ function graticule() {
+ return {
+ type: "MultiLineString",
+ coordinates: lines()
+ };
+ }
+ function lines() {
+ return d3.range(Math.ceil(X0 / DX) * DX, X1,
DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1,
DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) {
+ return abs(x % DX) > ε;
+ }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) {
+ return abs(y % DY) > ε;
+ }).map(y));
+ }
+ graticule.lines = function() {
+ return lines().map(function(coordinates) {
+ return {
+ type: "LineString",
+ coordinates: coordinates
+ };
+ });
+ };
+ graticule.outline = function() {
+ return {
+ type: "Polygon",
+ coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1),
Y(Y0).reverse().slice(1)) ]
+ };
+ };
+ graticule.extent = function(_) {
+ if (!arguments.length) return graticule.minorExtent();
+ return graticule.majorExtent(_).minorExtent(_);
+ };
+ graticule.majorExtent = function(_) {
+ if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ];
+ X0 = +_[0][0], X1 = +_[1][0];
+ Y0 = +_[0][1], Y1 = +_[1][1];
+ if (X0 > X1) _ = X0, X0 = X1, X1 = _;
+ if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
+ return graticule.precision(precision);
+ };
+ graticule.minorExtent = function(_) {
+ if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
+ x0 = +_[0][0], x1 = +_[1][0];
+ y0 = +_[0][1], y1 = +_[1][1];
+ if (x0 > x1) _ = x0, x0 = x1, x1 = _;
+ if (y0 > y1) _ = y0, y0 = y1, y1 = _;
+ return graticule.precision(precision);
+ };
+ graticule.step = function(_) {
+ if (!arguments.length) return graticule.minorStep();
+ return graticule.majorStep(_).minorStep(_);
+ };
+ graticule.majorStep = function(_) {
+ if (!arguments.length) return [ DX, DY ];
+ DX = +_[0], DY = +_[1];
+ return graticule;
+ };
+ graticule.minorStep = function(_) {
+ if (!arguments.length) return [ dx, dy ];
+ dx = +_[0], dy = +_[1];
+ return graticule;
+ };
+ graticule.precision = function(_) {
+ if (!arguments.length) return precision;
+ precision = +_;
+ x = d3_geo_graticuleX(y0, y1, 90);
+ y = d3_geo_graticuleY(x0, x1, precision);
+ X = d3_geo_graticuleX(Y0, Y1, 90);
+ Y = d3_geo_graticuleY(X0, X1, precision);
+ return graticule;
+ };
+ return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([
[ -180, -80 - ε ], [ 180, 80 + ε ] ]);
+ };
+ function d3_geo_graticuleX(y0, y1, dy) {
+ var y = d3.range(y0, y1 - ε, dy).concat(y1);
+ return function(x) {
+ return y.map(function(y) {
+ return [ x, y ];
+ });
+ };
+ }
+ function d3_geo_graticuleY(x0, x1, dx) {
+ var x = d3.range(x0, x1 - ε, dx).concat(x1);
+ return function(y) {
+ return x.map(function(x) {
+ return [ x, y ];
+ });
+ };
+ }
+ function d3_source(d) {
+ return d.source;
+ }
+ function d3_target(d) {
+ return d.target;
+ }
+ d3.geo.greatArc = function() {
+ var source = d3_source, source_, target = d3_target, target_;
+ function greatArc() {
+ return {
+ type: "LineString",
+ coordinates: [ source_ || source.apply(this, arguments), target_ ||
target.apply(this, arguments) ]
+ };
+ }
+ greatArc.distance = function() {
+ return d3.geo.distance(source_ || source.apply(this, arguments), target_ ||
target.apply(this, arguments));
+ };
+ greatArc.source = function(_) {
+ if (!arguments.length) return source;
+ source = _, source_ = typeof _ === "function" ? null : _;
+ return greatArc;
+ };
+ greatArc.target = function(_) {
+ if (!arguments.length) return target;
+ target = _, target_ = typeof _ === "function" ? null : _;
+ return greatArc;
+ };
+ greatArc.precision = function() {
+ return arguments.length ? greatArc : 0;
+ };
+ return greatArc;
+ };
+ d3.geo.interpolate = function(source, target) {
+ return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] *
d3_radians, target[1] * d3_radians);
+ };
+ function d3_geo_interpolate(x0, y0, x1, y1) {
+ var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1),
kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 *
Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 *
d3_haversin(x1 - x0))), k = 1 / Math.sin(d);
+ var interpolate = d ? function(t) {
+ var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A
* ky0 + B * ky1, z = A * sy0 + B * sy1;
+ return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) *
d3_degrees ];
+ } : function() {
+ return [ x0 * d3_degrees, y0 * d3_degrees ];
+ };
+ interpolate.distance = d;
+ return interpolate;
+ }
+ d3.geo.length = function(object) {
+ d3_geo_lengthSum = 0;
+ d3.geo.stream(object, d3_geo_length);
+ return d3_geo_lengthSum;
+ };
+ var d3_geo_lengthSum;
+ var d3_geo_length = {
+ sphere: d3_noop,
+ point: d3_noop,
+ lineStart: d3_geo_lengthLineStart,
+ lineEnd: d3_noop,
+ polygonStart: d3_noop,
+ polygonEnd: d3_noop
+ };
+ function d3_geo_lengthLineStart() {
+ var λ0, sinÏ0, cosÏ0;
+ d3_geo_length.point = function(λ, Ï) {
+ λ0 = λ * d3_radians, sinÏ0 = Math.sin(Ï *= d3_radians), cosÏ0 = Math.cos(Ï);
+ d3_geo_length.point = nextPoint;
+ };
+ d3_geo_length.lineEnd = function() {
+ d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
+ };
+ function nextPoint(λ, Ï) {
+ var sinÏ = Math.sin(Ï *= d3_radians), cosÏ = Math.cos(Ï), t = abs((λ *=
d3_radians) - λ0), cosÎλ = Math.cos(t);
+ d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosÏ * Math.sin(t)) * t + (t =
cosÏ0 * sinÏ - sinÏ0 * cosÏ * cosÎλ) * t), sinÏ0 * sinÏ + cosÏ0 * cosÏ *
cosÎλ);
+ λ0 = λ, sinÏ0 = sinÏ, cosÏ0 = cosÏ;
+ }
+ }
+ function d3_geo_azimuthal(scale, angle) {
+ function azimuthal(λ, Ï) {
+ var cosλ = Math.cos(λ), cosÏ = Math.cos(Ï), k = scale(cosλ * cosÏ);
+ return [ k * cosÏ * Math.sin(λ), k * Math.sin(Ï) ];
+ }
+ azimuthal.invert = function(x, y) {
+ var Ï = Math.sqrt(x * x + y * y), c = angle(Ï), sinc = Math.sin(c), cosc =
Math.cos(c);
+ return [ Math.atan2(x * sinc, Ï * cosc), Math.asin(Ï && y * sinc / Ï)
];
+ };
+ return azimuthal;
+ }
+ var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosÏ) {
+ return Math.sqrt(2 / (1 + cosλcosÏ));
+ }, function(Ï) {
+ return 2 * Math.asin(Ï / 2);
+ });
+ (d3.geo.azimuthalEqualArea = function() {
+ return d3_geo_projection(d3_geo_azimuthalEqualArea);
+ }).raw = d3_geo_azimuthalEqualArea;
+ var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosÏ) {
+ var c = Math.acos(cosλcosÏ);
+ return c && c / Math.sin(c);
+ }, d3_identity);
+ (d3.geo.azimuthalEquidistant = function() {
+ return d3_geo_projection(d3_geo_azimuthalEquidistant);
+ }).raw = d3_geo_azimuthalEquidistant;
+ function d3_geo_conicConformal(Ï0, Ï1) {
+ var cosÏ0 = Math.cos(Ï0), t = function(Ï) {
+ return Math.tan(Ï / 4 + Ï / 2);
+ }, n = Ï0 === Ï1 ? Math.sin(Ï0) : Math.log(cosÏ0 / Math.cos(Ï1)) /
Math.log(t(Ï1) / t(Ï0)), F = cosÏ0 * Math.pow(t(Ï0), n) / n;
+ if (!n) return d3_geo_mercator;
+ function forward(λ, Ï) {
+ var Ï = abs(abs(Ï) - halfÏ) < ε ? 0 : F / Math.pow(t(Ï), n);
+ return [ Ï * Math.sin(n * λ), F - Ï * Math.cos(n * λ) ];
+ }
+ forward.invert = function(x, y) {
+ var Ï0_y = F - y, Ï = d3_sgn(n) * Math.sqrt(x * x + Ï0_y * Ï0_y);
+ return [ Math.atan2(x, Ï0_y) / n, 2 * Math.atan(Math.pow(F / Ï, 1 / n)) - halfÏ
];
+ };
+ return forward;
+ }
+ (d3.geo.conicConformal = function() {
+ return d3_geo_conic(d3_geo_conicConformal);
+ }).raw = d3_geo_conicConformal;
+ function d3_geo_conicEquidistant(Ï0, Ï1) {
+ var cosÏ0 = Math.cos(Ï0), n = Ï0 === Ï1 ? Math.sin(Ï0) : (cosÏ0 -
Math.cos(Ï1)) / (Ï1 - Ï0), G = cosÏ0 / n + Ï0;
+ if (abs(n) < ε) return d3_geo_equirectangular;
+ function forward(λ, Ï) {
+ var Ï = G - Ï;
+ return [ Ï * Math.sin(n * λ), G - Ï * Math.cos(n * λ) ];
+ }
+ forward.invert = function(x, y) {
+ var Ï0_y = G - y;
+ return [ Math.atan2(x, Ï0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + Ï0_y * Ï0_y)
];
+ };
+ return forward;
+ }
+ (d3.geo.conicEquidistant = function() {
+ return d3_geo_conic(d3_geo_conicEquidistant);
+ }).raw = d3_geo_conicEquidistant;
+ var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosÏ) {
+ return 1 / cosλcosÏ;
+ }, Math.atan);
+ (d3.geo.gnomonic = function() {
+ return d3_geo_projection(d3_geo_gnomonic);
+ }).raw = d3_geo_gnomonic;
+ function d3_geo_mercator(λ, Ï) {
+ return [ λ, Math.log(Math.tan(Ï / 4 + Ï / 2)) ];
+ }
+ d3_geo_mercator.invert = function(x, y) {
+ return [ x, 2 * Math.atan(Math.exp(y)) - halfÏ ];
+ };
+ function d3_geo_mercatorProjection(project) {
+ var m = d3_geo_projection(project), scale = m.scale, translate = m.translate,
clipExtent = m.clipExtent, clipAuto;
+ m.scale = function() {
+ var v = scale.apply(m, arguments);
+ return v === m ? clipAuto ? m.clipExtent(null) : m : v;
+ };
+ m.translate = function() {
+ var v = translate.apply(m, arguments);
+ return v === m ? clipAuto ? m.clipExtent(null) : m : v;
+ };
+ m.clipExtent = function(_) {
+ var v = clipExtent.apply(m, arguments);
+ if (v === m) {
+ if (clipAuto = _ == null) {
+ var k = Ï * scale(), t = translate();
+ clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]);
+ }
+ } else if (clipAuto) {
+ v = null;
+ }
+ return v;
+ };
+ return m.clipExtent(null);
+ }
+ (d3.geo.mercator = function() {
+ return d3_geo_mercatorProjection(d3_geo_mercator);
+ }).raw = d3_geo_mercator;
+ var d3_geo_orthographic = d3_geo_azimuthal(function() {
+ return 1;
+ }, Math.asin);
+ (d3.geo.orthographic = function() {
+ return d3_geo_projection(d3_geo_orthographic);
+ }).raw = d3_geo_orthographic;
+ var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosÏ) {
+ return 1 / (1 + cosλcosÏ);
+ }, function(Ï) {
+ return 2 * Math.atan(Ï);
+ });
+ (d3.geo.stereographic = function() {
+ return d3_geo_projection(d3_geo_stereographic);
+ }).raw = d3_geo_stereographic;
+ function d3_geo_transverseMercator(λ, Ï) {
+ return [ Math.log(Math.tan(Ï / 4 + Ï / 2)), -λ ];
+ }
+ d3_geo_transverseMercator.invert = function(x, y) {
+ return [ -y, 2 * Math.atan(Math.exp(x)) - halfÏ ];
+ };
+ (d3.geo.transverseMercator = function() {
+ var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center =
projection.center, rotate = projection.rotate;
+ projection.center = function(_) {
+ return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ -_[1], _[0] ]);
+ };
+ projection.rotate = function(_) {
+ return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ =
rotate(),
+ [ _[0], _[1], _[2] - 90 ]);
+ };
+ return projection.rotate([ 0, 0 ]);
+ }).raw = d3_geo_transverseMercator;
+ d3.geom = {};
+ function d3_geom_pointX(d) {
+ return d[0];
+ }
+ function d3_geom_pointY(d) {
+ return d[1];
+ }
+ d3.geom.hull = function(vertices) {
+ var x = d3_geom_pointX, y = d3_geom_pointY;
+ if (arguments.length) return hull(vertices);
+ function hull(data) {
+ if (data.length < 3) return [];
+ var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n -
1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;
+ if (fx === d3_geom_pointX && y === d3_geom_pointY) vertices = data; else
for (i = 0,
+ vertices = []; i < n; ++i) {
+ vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]);
+ }
+ for (i = 1; i < n; ++i) {
+ if (vertices[i][1] < vertices[h][1] || vertices[i][1] == vertices[h][1]
&& vertices[i][0] < vertices[h][0]) h = i;
+ }
+ for (i = 0; i < n; ++i) {
+ if (i === h) continue;
+ y1 = vertices[i][1] - vertices[h][1];
+ x1 = vertices[i][0] - vertices[h][0];
+ points.push({
+ angle: Math.atan2(y1, x1),
+ index: i
+ });
+ }
+ points.sort(function(a, b) {
+ return a.angle - b.angle;
+ });
+ a = points[0].angle;
+ v = points[0].index;
+ u = 0;
+ for (i = 1; i < plen; ++i) {
+ j = points[i].index;
+ if (a == points[i].angle) {
+ x1 = vertices[v][0] - vertices[h][0];
+ y1 = vertices[v][1] - vertices[h][1];
+ x2 = vertices[j][0] - vertices[h][0];
+ y2 = vertices[j][1] - vertices[h][1];
+ if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) {
+ points[i].index = -1;
+ continue;
+ } else {
+ points[u].index = -1;
+ }
+ }
+ a = points[i].angle;
+ u = i;
+ v = j;
+ }
+ stack.push(h);
+ for (i = 0, j = 0; i < 2; ++j) {
+ if (points[j].index > -1) {
+ stack.push(points[j].index);
+ i++;
+ }
+ }
+ sp = stack.length;
+ for (;j < plen; ++j) {
+ if (points[j].index < 0) continue;
+ while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices))
{
+ --sp;
+ }
+ stack[sp++] = points[j].index;
+ }
+ var poly = [];
+ for (i = sp - 1; i >= 0; --i) poly.push(data[stack[i]]);
+ return poly;
+ }
+ hull.x = function(_) {
+ return arguments.length ? (x = _, hull) : x;
+ };
+ hull.y = function(_) {
+ return arguments.length ? (y = _, hull) : y;
+ };
+ return hull;
+ };
+ function d3_geom_hullCCW(i1, i2, i3, v) {
+ var t, a, b, c, d, e, f;
+ t = v[i1];
+ a = t[0];
+ b = t[1];
+ t = v[i2];
+ c = t[0];
+ d = t[1];
+ t = v[i3];
+ e = t[0];
+ f = t[1];
+ return (f - b) * (c - a) - (d - b) * (e - a) > 0;
+ }
+ d3.geom.polygon = function(coordinates) {
+ d3_subclass(coordinates, d3_geom_polygonPrototype);
+ return coordinates;
+ };
+ var d3_geom_polygonPrototype = d3.geom.polygon.prototype = [];
+ d3_geom_polygonPrototype.area = function() {
+ var i = -1, n = this.length, a, b = this[n - 1], area = 0;
+ while (++i < n) {
+ a = b;
+ b = this[i];
+ area += a[1] * b[0] - a[0] * b[1];
+ }
+ return area * .5;
+ };
+ d3_geom_polygonPrototype.centroid = function(k) {
+ var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c;
+ if (!arguments.length) k = -1 / (6 * this.area());
+ while (++i < n) {
+ a = b;
+ b = this[i];
+ c = a[0] * b[1] - b[0] * a[1];
+ x += (a[0] + b[0]) * c;
+ y += (a[1] + b[1]) * c;
+ }
+ return [ x * k, y * k ];
+ };
+ d3_geom_polygonPrototype.clip = function(subject) {
+ var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length -
d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d;
+ while (++i < n) {
+ input = subject.slice();
+ subject.length = 0;
+ b = this[i];
+ c = input[(m = input.length - closed) - 1];
+ j = -1;
+ while (++j < m) {
+ d = input[j];
+ if (d3_geom_polygonInside(d, a, b)) {
+ if (!d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ subject.push(d);
+ } else if (d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ c = d;
+ }
+ if (closed) subject.push(subject[0]);
+ a = b;
+ }
+ return subject;
+ };
+ function d3_geom_polygonInside(p, a, b) {
+ return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
+ }
+ function d3_geom_polygonIntersect(c, d, a, b) {
+ var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21
= d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43
* y21);
+ return [ x1 + ua * x21, y1 + ua * y21 ];
+ }
+ function d3_geom_polygonClosed(coordinates) {
+ var a = coordinates[0], b = coordinates[coordinates.length - 1];
+ return !(a[0] - b[0] || a[1] - b[1]);
+ }
+ var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches,
d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles,
d3_geom_voronoiCirclePool = [];
+ function d3_geom_voronoiBeach() {
+ d3_geom_voronoiRedBlackNode(this);
+ this.edge = this.site = this.circle = null;
+ }
+ function d3_geom_voronoiCreateBeach(site) {
+ var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach();
+ beach.site = site;
+ return beach;
+ }
+ function d3_geom_voronoiDetachBeach(beach) {
+ d3_geom_voronoiDetachCircle(beach);
+ d3_geom_voronoiBeaches.remove(beach);
+ d3_geom_voronoiBeachPool.push(beach);
+ d3_geom_voronoiRedBlackNode(beach);
+ }
+ function d3_geom_voronoiRemoveBeach(beach) {
+ var circle = beach.circle, x = circle.x, y = circle.cy, vertex = {
+ x: x,
+ y: y
+ }, previous = beach.P, next = beach.N, disappearing = [ beach ];
+ d3_geom_voronoiDetachBeach(beach);
+ var lArc = previous;
+ while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y -
lArc.circle.cy) < ε) {
+ previous = lArc.P;
+ disappearing.unshift(lArc);
+ d3_geom_voronoiDetachBeach(lArc);
+ lArc = previous;
+ }
+ disappearing.unshift(lArc);
+ d3_geom_voronoiDetachCircle(lArc);
+ var rArc = next;
+ while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y -
rArc.circle.cy) < ε) {
+ next = rArc.N;
+ disappearing.push(rArc);
+ d3_geom_voronoiDetachBeach(rArc);
+ rArc = next;
+ }
+ disappearing.push(rArc);
+ d3_geom_voronoiDetachCircle(rArc);
+ var nArcs = disappearing.length, iArc;
+ for (iArc = 1; iArc < nArcs; ++iArc) {
+ rArc = disappearing[iArc];
+ lArc = disappearing[iArc - 1];
+ d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
+ }
+ lArc = disappearing[0];
+ rArc = disappearing[nArcs - 1];
+ rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex);
+ d3_geom_voronoiAttachCircle(lArc);
+ d3_geom_voronoiAttachCircle(rArc);
+ }
+ function d3_geom_voronoiAddBeach(site) {
+ var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node =
d3_geom_voronoiBeaches._;
+ while (node) {
+ dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x;
+ if (dxl > ε) node = node.L; else {
+ dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix);
+ if (dxr > ε) {
+ if (!node.R) {
+ lArc = node;
+ break;
+ }
+ node = node.R;
+ } else {
+ if (dxl > -ε) {
+ lArc = node.P;
+ rArc = node;
+ } else if (dxr > -ε) {
+ lArc = node;
+ rArc = node.N;
+ } else {
+ lArc = rArc = node;
+ }
+ break;
+ }
+ }
+ }
+ var newArc = d3_geom_voronoiCreateBeach(site);
+ d3_geom_voronoiBeaches.insert(lArc, newArc);
+ if (!lArc && !rArc) return;
+ if (lArc === rArc) {
+ d3_geom_voronoiDetachCircle(lArc);
+ rArc = d3_geom_voronoiCreateBeach(lArc.site);
+ d3_geom_voronoiBeaches.insert(newArc, rArc);
+ newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
+ d3_geom_voronoiAttachCircle(lArc);
+ d3_geom_voronoiAttachCircle(rArc);
+ return;
+ }
+ if (!rArc) {
+ newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
+ return;
+ }
+ d3_geom_voronoiDetachCircle(lArc);
+ d3_geom_voronoiDetachCircle(rArc);
+ var lSite = lArc.site, ax = lSite.x, ay = lSite.y, bx = site.x - ax, by = site.y -
ay, rSite = rArc.site, cx = rSite.x - ax, cy = rSite.y - ay, d = 2 * (bx * cy - by * cx),
hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = {
+ x: (cy * hb - by * hc) / d + ax,
+ y: (bx * hc - cx * hb) / d + ay
+ };
+ d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex);
+ newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex);
+ rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex);
+ d3_geom_voronoiAttachCircle(lArc);
+ d3_geom_voronoiAttachCircle(rArc);
+ }
+ function d3_geom_voronoiLeftBreakPoint(arc, directrix) {
+ var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix;
+ if (!pby2) return rfocx;
+ var lArc = arc.P;
+ if (!lArc) return -Infinity;
+ site = lArc.site;
+ var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix;
+ if (!plby2) return lfocx;
+ var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2;
+ if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy +
plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
+ return (rfocx + lfocx) / 2;
+ }
+ function d3_geom_voronoiRightBreakPoint(arc, directrix) {
+ var rArc = arc.N;
+ if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix);
+ var site = arc.site;
+ return site.y === directrix ? site.x : Infinity;
+ }
+ function d3_geom_voronoiCell(site) {
+ this.site = site;
+ this.edges = [];
+ }
+ d3_geom_voronoiCell.prototype.prepare = function() {
+ var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge;
+ while (iHalfEdge--) {
+ edge = halfEdges[iHalfEdge].edge;
+ if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1);
+ }
+ halfEdges.sort(d3_geom_voronoiHalfEdgeOrder);
+ return halfEdges.length;
+ };
+ function d3_geom_voronoiCloseCells(extent) {
+ var x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], x2,
y2, x3, y3, cells = d3_geom_voronoiCells, iCell = cells.length, cell, iHalfEdge,
halfEdges, nHalfEdges, start, end;
+ while (iCell--) {
+ cell = cells[iCell];
+ if (!cell || !cell.prepare()) continue;
+ halfEdges = cell.edges;
+ nHalfEdges = halfEdges.length;
+ iHalfEdge = 0;
+ while (iHalfEdge < nHalfEdges) {
+ end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y;
+ start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y;
+ if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) {
+ halfEdges.splice(iHalfEdge, 0, new
d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) <
ε && y1 - y3 > ε ? {
+ x: x0,
+ y: abs(x2 - x0) < ε ? y2 : y1
+ } : abs(y3 - y1) < ε && x1 - x3 > ε ? {
+ x: abs(y2 - y1) < ε ? x2 : x1,
+ y: y1
+ } : abs(x3 - x1) < ε && y3 - y0 > ε ? {
+ x: x1,
+ y: abs(x2 - x1) < ε ? y2 : y0
+ } : abs(y3 - y0) < ε && x3 - x0 > ε ? {
+ x: abs(y2 - y0) < ε ? x2 : x0,
+ y: y0
+ } : null), cell.site, null));
+ ++nHalfEdges;
+ }
+ }
+ }
+ }
+ function d3_geom_voronoiHalfEdgeOrder(a, b) {
+ return b.angle - a.angle;
+ }
+ function d3_geom_voronoiCircle() {
+ d3_geom_voronoiRedBlackNode(this);
+ this.x = this.y = this.arc = this.site = this.cy = null;
+ }
+ function d3_geom_voronoiAttachCircle(arc) {
+ var lArc = arc.P, rArc = arc.N;
+ if (!lArc || !rArc) return;
+ var lSite = lArc.site, cSite = arc.site, rSite = rArc.site;
+ if (lSite === rSite) return;
+ var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x -
bx, cy = rSite.y - by;
+ var d = 2 * (ax * cy - ay * cx);
+ if (d >= -ε2) return;
+ var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y =
(ax * hc - cx * ha) / d, cy = y + by;
+ var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle();
+ circle.arc = arc;
+ circle.site = cSite;
+ circle.x = x + bx;
+ circle.y = cy + Math.sqrt(x * x + y * y);
+ circle.cy = cy;
+ arc.circle = circle;
+ var before = null, node = d3_geom_voronoiCircles._;
+ while (node) {
+ if (circle.y < node.y || circle.y === node.y && circle.x <= node.x)
{
+ if (node.L) node = node.L; else {
+ before = node.P;
+ break;
+ }
+ } else {
+ if (node.R) node = node.R; else {
+ before = node;
+ break;
+ }
+ }
+ }
+ d3_geom_voronoiCircles.insert(before, circle);
+ if (!before) d3_geom_voronoiFirstCircle = circle;
+ }
+ function d3_geom_voronoiDetachCircle(arc) {
+ var circle = arc.circle;
+ if (circle) {
+ if (!circle.P) d3_geom_voronoiFirstCircle = circle.N;
+ d3_geom_voronoiCircles.remove(circle);
+ d3_geom_voronoiCirclePool.push(circle);
+ d3_geom_voronoiRedBlackNode(circle);
+ arc.circle = null;
+ }
+ }
+ function d3_geom_voronoiClipEdges(extent) {
+ var edges = d3_geom_voronoiEdges, clip = d3_geom_clipLine(extent[0][0], extent[0][1],
extent[1][0], extent[1][1]), i = edges.length, e;
+ while (i--) {
+ e = edges[i];
+ if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) <
ε && abs(e.a.y - e.b.y) < ε) {
+ e.a = e.b = null;
+ edges.splice(i, 1);
+ }
+ }
+ }
+ function d3_geom_voronoiConnectEdge(edge, extent) {
+ var vb = edge.b;
+ if (vb) return true;
+ var va = edge.a, x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 =
extent[1][1], lSite = edge.l, rSite = edge.r, lx = lSite.x, ly = lSite.y, rx = rSite.x, ry
= rSite.y, fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb;
+ if (ry === ly) {
+ if (fx < x0 || fx >= x1) return;
+ if (lx > rx) {
+ if (!va) va = {
+ x: fx,
+ y: y0
+ }; else if (va.y >= y1) return;
+ vb = {
+ x: fx,
+ y: y1
+ };
+ } else {
+ if (!va) va = {
+ x: fx,
+ y: y1
+ }; else if (va.y < y0) return;
+ vb = {
+ x: fx,
+ y: y0
+ };
+ }
+ } else {
+ fm = (lx - rx) / (ry - ly);
+ fb = fy - fm * fx;
+ if (fm < -1 || fm > 1) {
+ if (lx > rx) {
+ if (!va) va = {
+ x: (y0 - fb) / fm,
+ y: y0
+ }; else if (va.y >= y1) return;
+ vb = {
+ x: (y1 - fb) / fm,
+ y: y1
+ };
+ } else {
+ if (!va) va = {
+ x: (y1 - fb) / fm,
+ y: y1
+ }; else if (va.y < y0) return;
+ vb = {
+ x: (y0 - fb) / fm,
+ y: y0
+ };
+ }
+ } else {
+ if (ly < ry) {
+ if (!va) va = {
+ x: x0,
+ y: fm * x0 + fb
+ }; else if (va.x >= x1) return;
+ vb = {
+ x: x1,
+ y: fm * x1 + fb
+ };
+ } else {
+ if (!va) va = {
+ x: x1,
+ y: fm * x1 + fb
+ }; else if (va.x < x0) return;
+ vb = {
+ x: x0,
+ y: fm * x0 + fb
+ };
+ }
+ }
+ }
+ edge.a = va;
+ edge.b = vb;
+ return true;
+ }
+ function d3_geom_voronoiEdge(lSite, rSite) {
+ this.l = lSite;
+ this.r = rSite;
+ this.a = this.b = null;
+ }
+ function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) {
+ var edge = new d3_geom_voronoiEdge(lSite, rSite);
+ d3_geom_voronoiEdges.push(edge);
+ if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va);
+ if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb);
+ d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite,
rSite));
+ d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite,
lSite));
+ return edge;
+ }
+ function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) {
+ var edge = new d3_geom_voronoiEdge(lSite, null);
+ edge.a = va;
+ edge.b = vb;
+ d3_geom_voronoiEdges.push(edge);
+ return edge;
+ }
+ function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) {
+ if (!edge.a && !edge.b) {
+ edge.a = vertex;
+ edge.l = lSite;
+ edge.r = rSite;
+ } else if (edge.l === rSite) {
+ edge.b = vertex;
+ } else {
+ edge.a = vertex;
+ }
+ }
+ function d3_geom_voronoiHalfEdge(edge, lSite, rSite) {
+ var va = edge.a, vb = edge.b;
+ this.edge = edge;
+ this.site = lSite;
+ this.angle = rSite ? Math.atan2(rSite.y - lSite.y, rSite.x - lSite.x) : edge.l ===
lSite ? Math.atan2(vb.x - va.x, va.y - vb.y) : Math.atan2(va.x - vb.x, vb.y - va.y);
+ }
+ d3_geom_voronoiHalfEdge.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;
+ }
+ };
+ function d3_geom_voronoiRedBlackTree() {
+ this._ = null;
+ }
+ function d3_geom_voronoiRedBlackNode(node) {
+ node.U = node.C = node.L = node.R = node.P = node.N = null;
+ }
+ d3_geom_voronoiRedBlackTree.prototype = {
+ insert: function(after, node) {
+ var parent, grandpa, uncle;
+ if (after) {
+ node.P = after;
+ node.N = after.N;
+ if (after.N) after.N.P = node;
+ after.N = node;
+ if (after.R) {
+ after = after.R;
+ while (after.L) after = after.L;
+ after.L = node;
+ } else {
+ after.R = node;
+ }
+ parent = after;
+ } else if (this._) {
+ after = d3_geom_voronoiRedBlackFirst(this._);
+ node.P = null;
+ node.N = after;
+ after.P = after.L = node;
+ parent = after;
+ } else {
+ node.P = node.N = null;
+ this._ = node;
+ parent = null;
+ }
+ node.L = node.R = null;
+ node.U = parent;
+ node.C = true;
+ after = node;
+ while (parent && parent.C) {
+ grandpa = parent.U;
+ if (parent === grandpa.L) {
+ uncle = grandpa.R;
+ if (uncle && uncle.C) {
+ parent.C = uncle.C = false;
+ grandpa.C = true;
+ after = grandpa;
+ } else {
+ if (after === parent.R) {
+ d3_geom_voronoiRedBlackRotateLeft(this, parent);
+ after = parent;
+ parent = after.U;
+ }
+ parent.C = false;
+ grandpa.C = true;
+ d3_geom_voronoiRedBlackRotateRight(this, grandpa);
+ }
+ } else {
+ uncle = grandpa.L;
+ if (uncle && uncle.C) {
+ parent.C = uncle.C = false;
+ grandpa.C = true;
+ after = grandpa;
+ } else {
+ if (after === parent.L) {
+ d3_geom_voronoiRedBlackRotateRight(this, parent);
+ after = parent;
+ parent = after.U;
+ }
+ parent.C = false;
+ grandpa.C = true;
+ d3_geom_voronoiRedBlackRotateLeft(this, grandpa);
+ }
+ }
+ parent = after.U;
+ }
+ this._.C = false;
+ },
+ remove: function(node) {
+ if (node.N) node.N.P = node.P;
+ if (node.P) node.P.N = node.N;
+ node.N = node.P = null;
+ var parent = node.U, sibling, left = node.L, right = node.R, next, red;
+ if (!left) next = right; else if (!right) next = left; else next =
d3_geom_voronoiRedBlackFirst(right);
+ if (parent) {
+ if (parent.L === node) parent.L = next; else parent.R = next;
+ } else {
+ this._ = next;
+ }
+ if (left && right) {
+ red = next.C;
+ next.C = node.C;
+ next.L = left;
+ left.U = next;
+ if (next !== right) {
+ parent = next.U;
+ next.U = node.U;
+ node = next.R;
+ parent.L = node;
+ next.R = right;
+ right.U = next;
+ } else {
+ next.U = parent;
+ parent = next;
+ node = next.R;
+ }
+ } else {
+ red = node.C;
+ node = next;
+ }
+ if (node) node.U = parent;
+ if (red) return;
+ if (node && node.C) {
+ node.C = false;
+ return;
+ }
+ do {
+ if (node === this._) break;
+ if (node === parent.L) {
+ sibling = parent.R;
+ if (sibling.C) {
+ sibling.C = false;
+ parent.C = true;
+ d3_geom_voronoiRedBlackRotateLeft(this, parent);
+ sibling = parent.R;
+ }
+ if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
+ if (!sibling.R || !sibling.R.C) {
+ sibling.L.C = false;
+ sibling.C = true;
+ d3_geom_voronoiRedBlackRotateRight(this, sibling);
+ sibling = parent.R;
+ }
+ sibling.C = parent.C;
+ parent.C = sibling.R.C = false;
+ d3_geom_voronoiRedBlackRotateLeft(this, parent);
+ node = this._;
+ break;
+ }
+ } else {
+ sibling = parent.L;
+ if (sibling.C) {
+ sibling.C = false;
+ parent.C = true;
+ d3_geom_voronoiRedBlackRotateRight(this, parent);
+ sibling = parent.L;
+ }
+ if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
+ if (!sibling.L || !sibling.L.C) {
+ sibling.R.C = false;
+ sibling.C = true;
+ d3_geom_voronoiRedBlackRotateLeft(this, sibling);
+ sibling = parent.L;
+ }
+ sibling.C = parent.C;
+ parent.C = sibling.L.C = false;
+ d3_geom_voronoiRedBlackRotateRight(this, parent);
+ node = this._;
+ break;
+ }
+ }
+ sibling.C = true;
+ node = parent;
+ parent = parent.U;
+ } while (!node.C);
+ if (node) node.C = false;
+ }
+ };
+ function d3_geom_voronoiRedBlackRotateLeft(tree, node) {
+ var p = node, q = node.R, parent = p.U;
+ if (parent) {
+ if (parent.L === p) parent.L = q; else parent.R = q;
+ } else {
+ tree._ = q;
+ }
+ q.U = parent;
+ p.U = q;
+ p.R = q.L;
+ if (p.R) p.R.U = p;
+ q.L = p;
+ }
+ function d3_geom_voronoiRedBlackRotateRight(tree, node) {
+ var p = node, q = node.L, parent = p.U;
+ if (parent) {
+ if (parent.L === p) parent.L = q; else parent.R = q;
+ } else {
+ tree._ = q;
+ }
+ q.U = parent;
+ p.U = q;
+ p.L = q.R;
+ if (p.L) p.L.U = p;
+ q.R = p;
+ }
+ function d3_geom_voronoiRedBlackFirst(node) {
+ while (node.L) node = node.L;
+ return node;
+ }
+ function d3_geom_voronoi(sites, bbox) {
+ var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle;
+ d3_geom_voronoiEdges = [];
+ d3_geom_voronoiCells = new Array(sites.length);
+ d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree();
+ d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree();
+ while (true) {
+ circle = d3_geom_voronoiFirstCircle;
+ if (site && (!circle || site.y < circle.y || site.y === circle.y
&& site.x < circle.x)) {
+ if (site.x !== x0 || site.y !== y0) {
+ d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site);
+ d3_geom_voronoiAddBeach(site);
+ x0 = site.x, y0 = site.y;
+ }
+ site = sites.pop();
+ } else if (circle) {
+ d3_geom_voronoiRemoveBeach(circle.arc);
+ } else {
+ break;
+ }
+ }
+ if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox);
+ var diagram = {
+ cells: d3_geom_voronoiCells,
+ edges: d3_geom_voronoiEdges
+ };
+ d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges =
d3_geom_voronoiCells = null;
+ return diagram;
+ }
+ function d3_geom_voronoiVertexOrder(a, b) {
+ return b.y - a.y || b.x - a.x;
+ }
+ d3.geom.voronoi = function(points) {
+ var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent =
d3_geom_voronoiClipExtent;
+ if (points) return voronoi(points);
+ function voronoi(data) {
+ var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 =
clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1];
+ d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) {
+ var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ?
edges.map(function(e) {
+ var s = e.start();
+ return [ s.x, s.y ];
+ }) : site.x >= x0 && site.x <= x1 && site.y >= y0
&& site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : [];
+ polygon.point = data[i];
+ });
+ return polygons;
+ }
+ function sites(data) {
+ return data.map(function(d, i) {
+ return {
+ x: Math.round(fx(d, i) / ε) * ε,
+ y: Math.round(fy(d, i) / ε) * ε,
+ i: i
+ };
+ });
+ }
+ voronoi.links = function(data) {
+ return d3_geom_voronoi(sites(data)).edges.filter(function(edge) {
+ return edge.l && edge.r;
+ }).map(function(edge) {
+ return {
+ source: data[edge.l.i],
+ target: data[edge.r.i]
+ };
+ });
+ };
+ voronoi.triangles = function(data) {
+ var triangles = [];
+ d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) {
+ var site = cell.site, edges = cell.edges.sort(d3_geom_voronoiHalfEdgeOrder), j =
-1, m = edges.length, e0, s0, e1 = edges[m - 1].edge, s1 = e1.l === site ? e1.r : e1.l;
+ while (++j < m) {
+ e0 = e1;
+ s0 = s1;
+ e1 = edges[j].edge;
+ s1 = e1.l === site ? e1.r : e1.l;
+ if (i < s0.i && i < s1.i &&
d3_geom_voronoiTriangleArea(site, s0, s1) < 0) {
+ triangles.push([ data[i], data[s0.i], data[s1.i] ]);
+ }
+ }
+ });
+ return triangles;
+ };
+ voronoi.x = function(_) {
+ return arguments.length ? (fx = d3_functor(x = _), voronoi) : x;
+ };
+ voronoi.y = function(_) {
+ return arguments.length ? (fy = d3_functor(y = _), voronoi) : y;
+ };
+ voronoi.clipExtent = function(_) {
+ if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null :
clipExtent;
+ clipExtent = _ == null ? d3_geom_voronoiClipExtent : _;
+ return voronoi;
+ };
+ voronoi.size = function(_) {
+ if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null :
clipExtent && clipExtent[1];
+ return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]);
+ };
+ return voronoi;
+ };
+ var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ];
+ function d3_geom_voronoiTriangleArea(a, b, c) {
+ return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y);
+ }
+ d3.geom.delaunay = function(vertices) {
+ return d3.geom.voronoi().triangles(vertices);
+ };
+ d3.geom.quadtree = function(points, x1, y1, x2, y2) {
+ var x = d3_geom_pointX, y = d3_geom_pointY, compat;
+ if (compat = arguments.length) {
+ x = d3_geom_quadtreeCompatX;
+ y = d3_geom_quadtreeCompatY;
+ if (compat === 3) {
+ y2 = y1;
+ x2 = x1;
+ y1 = x1 = 0;
+ }
+ return quadtree(points);
+ }
+ function quadtree(data) {
+ var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_;
+ if (x1 != null) {
+ x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2;
+ } else {
+ x2_ = y2_ = -(x1_ = y1_ = Infinity);
+ xs = [], ys = [];
+ n = data.length;
+ if (compat) for (i = 0; i < n; ++i) {
+ d = data[i];
+ if (d.x < x1_) x1_ = d.x;
+ if (d.y < y1_) y1_ = d.y;
+ if (d.x > x2_) x2_ = d.x;
+ if (d.y > y2_) y2_ = d.y;
+ xs.push(d.x);
+ ys.push(d.y);
+ } else for (i = 0; i < n; ++i) {
+ var x_ = +fx(d = data[i], i), y_ = +fy(d, i);
+ if (x_ < x1_) x1_ = x_;
+ if (y_ < y1_) y1_ = y_;
+ if (x_ > x2_) x2_ = x_;
+ if (y_ > y2_) y2_ = y_;
+ xs.push(x_);
+ ys.push(y_);
+ }
+ }
+ var dx = x2_ - x1_, dy = y2_ - y1_;
+ if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy;
+ function insert(n, d, x, y, x1, y1, x2, y2) {
+ if (isNaN(x) || isNaN(y)) return;
+ if (n.leaf) {
+ var nx = n.x, ny = n.y;
+ if (nx != null) {
+ if (abs(nx - x) + abs(ny - y) < .01) {
+ insertChild(n, d, x, y, x1, y1, x2, y2);
+ } else {
+ var nPoint = n.point;
+ n.x = n.y = n.point = null;
+ insertChild(n, nPoint, nx, ny, x1, y1, x2, y2);
+ insertChild(n, d, x, y, x1, y1, x2, y2);
+ }
+ } else {
+ n.x = x, n.y = y, n.point = d;
+ }
+ } else {
+ insertChild(n, d, x, y, x1, y1, x2, y2);
+ }
+ }
+ function insertChild(n, d, x, y, x1, y1, x2, y2) {
+ var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y
>= sy, i = (bottom << 1) + right;
+ n.leaf = false;
+ n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
+ if (right) x1 = sx; else x2 = sx;
+ if (bottom) y1 = sy; else y2 = sy;
+ insert(n, d, x, y, x1, y1, x2, y2);
+ }
+ var root = d3_geom_quadtreeNode();
+ root.add = function(d) {
+ insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_);
+ };
+ root.visit = function(f) {
+ d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_);
+ };
+ i = -1;
+ if (x1 == null) {
+ while (++i < n) {
+ insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_);
+ }
+ --i;
+ } else data.forEach(root.add);
+ xs = ys = data = d = null;
+ return root;
+ }
+ quadtree.x = function(_) {
+ return arguments.length ? (x = _, quadtree) : x;
+ };
+ quadtree.y = function(_) {
+ return arguments.length ? (y = _, quadtree) : y;
+ };
+ quadtree.extent = function(_) {
+ if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ];
+ if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 =
+_[1][0],
+ y2 = +_[1][1];
+ return quadtree;
+ };
+ quadtree.size = function(_) {
+ if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ];
+ if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1];
+ return quadtree;
+ };
+ return quadtree;
+ };
+ function d3_geom_quadtreeCompatX(d) {
+ return d.x;
+ }
+ function d3_geom_quadtreeCompatY(d) {
+ return d.y;
+ }
+ function d3_geom_quadtreeNode() {
+ return {
+ leaf: true,
+ nodes: [],
+ point: null,
+ x: null,
+ y: null
+ };
+ }
+ function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
+ if (!f(node, x1, y1, x2, y2)) {
+ var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;
+ if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
+ if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
+ if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
+ if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
+ }
+ }
+ d3.interpolateRgb = d3_interpolateRgb;
+ function d3_interpolateRgb(a, b) {
+ a = d3.rgb(a);
+ b = d3.rgb(b);
+ var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
+ return function(t) {
+ return "#" + d3_rgb_hex(Math.round(ar + br * t)) +
d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));
+ };
+ }
+ d3.interpolateObject = d3_interpolateObject;
+ function d3_interpolateObject(a, b) {
+ var i = {}, c = {}, k;
+ for (k in a) {
+ if (k in b) {
+ i[k] = d3_interpolate(a[k], b[k]);
+ } else {
+ c[k] = a[k];
+ }
+ }
+ for (k in b) {
+ if (!(k in a)) {
+ c[k] = b[k];
+ }
+ }
+ return function(t) {
+ for (k in i) c[k] = i[k](t);
+ return c;
+ };
+ }
+ d3.interpolateNumber = d3_interpolateNumber;
+ function d3_interpolateNumber(a, b) {
+ b -= a = +a;
+ return function(t) {
+ return a + b * t;
+ };
+ }
+ d3.interpolateString = d3_interpolateString;
+ function d3_interpolateString(a, b) {
+ var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;
+ a = a + "", b = b + "";
+ d3_interpolate_number.lastIndex = 0;
+ for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
+ if (m.index) s.push(b.substring(s0, s1 = m.index));
+ q.push({
+ i: s.length,
+ x: m[0]
+ });
+ s.push(null);
+ s0 = d3_interpolate_number.lastIndex;
+ }
+ if (s0 < b.length) s.push(b.substring(s0));
+ for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n;
++i) {
+ o = q[i];
+ if (o.x == m[0]) {
+ if (o.i) {
+ if (s[o.i + 1] == null) {
+ s[o.i - 1] += o.x;
+ s.splice(o.i, 1);
+ for (j = i + 1; j < n; ++j) q[j].i--;
+ } else {
+ s[o.i - 1] += o.x + s[o.i + 1];
+ s.splice(o.i, 2);
+ for (j = i + 1; j < n; ++j) q[j].i -= 2;
+ }
+ } else {
+ if (s[o.i + 1] == null) {
+ s[o.i] = o.x;
+ } else {
+ s[o.i] = o.x + s[o.i + 1];
+ s.splice(o.i + 1, 1);
+ for (j = i + 1; j < n; ++j) q[j].i--;
+ }
+ }
+ q.splice(i, 1);
+ n--;
+ i--;
+ } else {
+ o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
+ }
+ }
+ while (i < n) {
+ o = q.pop();
+ if (s[o.i + 1] == null) {
+ s[o.i] = o.x;
+ } else {
+ s[o.i] = o.x + s[o.i + 1];
+ s.splice(o.i + 1, 1);
+ }
+ n--;
+ }
+ if (s.length === 1) {
+ return s[0] == null ? (o = q[0].x, function(t) {
+ return o(t) + "";
+ }) : function() {
+ return b;
+ };
+ }
+ return function(t) {
+ for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ }
+ var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
+ d3.interpolate = d3_interpolate;
+ function d3_interpolate(a, b) {
+ var i = d3.interpolators.length, f;
+ while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
+ return f;
+ }
+ d3.interpolators = [ function(a, b) {
+ var t = typeof b;
+ return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b)
? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : t
=== "object" ? Array.isArray(b) ? d3_interpolateArray : d3_interpolateObject :
d3_interpolateNumber)(a, b);
+ } ];
+ d3.interpolateArray = d3_interpolateArray;
+ function d3_interpolateArray(a, b) {
+ var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length),
i;
+ for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i]));
+ for (;i < na; ++i) c[i] = a[i];
+ for (;i < nb; ++i) c[i] = b[i];
+ return function(t) {
+ for (i = 0; i < n0; ++i) c[i] = x[i](t);
+ return c;
+ };
+ }
+ var d3_ease_default = function() {
+ return d3_identity;
+ };
+ var d3_ease = d3.map({
+ linear: d3_ease_default,
+ poly: d3_ease_poly,
+ quad: function() {
+ return d3_ease_quad;
+ },
+ cubic: function() {
+ return d3_ease_cubic;
+ },
+ sin: function() {
+ return d3_ease_sin;
+ },
+ exp: function() {
+ return d3_ease_exp;
+ },
+ circle: function() {
+ return d3_ease_circle;
+ },
+ elastic: d3_ease_elastic,
+ back: d3_ease_back,
+ bounce: function() {
+ return d3_ease_bounce;
+ }
+ });
+ var d3_ease_mode = d3.map({
+ "in": d3_identity,
+ out: d3_ease_reverse,
+ "in-out": d3_ease_reflect,
+ "out-in": function(f) {
+ return d3_ease_reflect(d3_ease_reverse(f));
+ }
+ });
+ d3.ease = function(name) {
+ var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m =
i >= 0 ? name.substring(i + 1) : "in";
+ t = d3_ease.get(t) || d3_ease_default;
+ m = d3_ease_mode.get(m) || d3_identity;
+ return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1))));
+ };
+ function d3_ease_clamp(f) {
+ return function(t) {
+ return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
+ };
+ }
+ function d3_ease_reverse(f) {
+ return function(t) {
+ return 1 - f(1 - t);
+ };
+ }
+ function d3_ease_reflect(f) {
+ return function(t) {
+ return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
+ };
+ }
+ function d3_ease_quad(t) {
+ return t * t;
+ }
+ function d3_ease_cubic(t) {
+ return t * t * t;
+ }
+ function d3_ease_cubicInOut(t) {
+ if (t <= 0) return 0;
+ if (t >= 1) return 1;
+ var t2 = t * t, t3 = t2 * t;
+ return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
+ }
+ function d3_ease_poly(e) {
+ return function(t) {
+ return Math.pow(t, e);
+ };
+ }
+ function d3_ease_sin(t) {
+ return 1 - Math.cos(t * halfÏ);
+ }
+ function d3_ease_exp(t) {
+ return Math.pow(2, 10 * (t - 1));
+ }
+ function d3_ease_circle(t) {
+ return 1 - Math.sqrt(1 - t * t);
+ }
+ function d3_ease_elastic(a, p) {
+ var s;
+ if (arguments.length < 2) p = .45;
+ if (arguments.length) s = p / Ï * Math.asin(1 / a); else a = 1, s = p / 4;
+ return function(t) {
+ return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * Ï / p);
+ };
+ }
+ function d3_ease_back(s) {
+ if (!s) s = 1.70158;
+ return function(t) {
+ return t * t * ((s + 1) * t - s);
+ };
+ }
+ function d3_ease_bounce(t) {
+ return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 /
2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 *
(t -= 2.625 / 2.75) * t + .984375;
+ }
+ d3.interpolateHcl = d3_interpolateHcl;
+ function d3_interpolateHcl(a, b) {
+ a = d3.hcl(a);
+ b = d3.hcl(b);
+ var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;
+ if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac;
+ if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360;
else if (bh < -180) bh += 360;
+ return function(t) {
+ return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
+ };
+ }
+ d3.interpolateHsl = d3_interpolateHsl;
+ function d3_interpolateHsl(a, b) {
+ a = d3.hsl(a);
+ b = d3.hsl(b);
+ var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al;
+ if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as;
+ if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360;
else if (bh < -180) bh += 360;
+ return function(t) {
+ return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + "";
+ };
+ }
+ d3.interpolateLab = d3_interpolateLab;
+ function d3_interpolateLab(a, b) {
+ a = d3.lab(a);
+ b = d3.lab(b);
+ var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;
+ return function(t) {
+ return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
+ };
+ }
+ d3.interpolateRound = d3_interpolateRound;
+ function d3_interpolateRound(a, b) {
+ b -= a;
+ return function(t) {
+ return Math.round(a + b * t);
+ };
+ }
+ d3.transform = function(string) {
+ var g = d3_document.createElementNS(d3.ns.prefix.svg, "g");
+ return (d3.transform = function(string) {
+ if (string != null) {
+ g.setAttribute("transform", string);
+ var t = g.transform.baseVal.consolidate();
+ }
+ return new d3_transform(t ? t.matrix : d3_transformIdentity);
+ })(string);
+ };
+ function d3_transform(m) {
+ var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz =
d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) ||
0;
+ if (r0[0] * r1[1] < r1[0] * r0[1]) {
+ r0[0] *= -1;
+ r0[1] *= -1;
+ kx *= -1;
+ kz *= -1;
+ }
+ this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) *
d3_degrees;
+ this.translate = [ m.e, m.f ];
+ this.scale = [ kx, ky ];
+ this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
+ }
+ d3_transform.prototype.toString = function() {
+ return "translate(" + this.translate + ")rotate(" + this.rotate +
")skewX(" + this.skew + ")scale(" + this.scale + ")";
+ };
+ function d3_transformDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+ }
+ function d3_transformNormalize(a) {
+ var k = Math.sqrt(d3_transformDot(a, a));
+ if (k) {
+ a[0] /= k;
+ a[1] /= k;
+ }
+ return k;
+ }
+ function d3_transformCombine(a, b, k) {
+ a[0] += k * b[0];
+ a[1] += k * b[1];
+ return a;
+ }
+ var d3_transformIdentity = {
+ a: 1,
+ b: 0,
+ c: 0,
+ d: 1,
+ e: 0,
+ f: 0
+ };
+ d3.interpolateTransform = d3_interpolateTransform;
+ function d3_interpolateTransform(a, b) {
+ var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb
= B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb =
B.scale;
+ if (ta[0] != tb[0] || ta[1] != tb[1]) {
+ s.push("translate(", null, ",", null, ")");
+ q.push({
+ i: 1,
+ x: d3_interpolateNumber(ta[0], tb[0])
+ }, {
+ i: 3,
+ x: d3_interpolateNumber(ta[1], tb[1])
+ });
+ } else if (tb[0] || tb[1]) {
+ s.push("translate(" + tb + ")");
+ } else {
+ s.push("");
+ }
+ if (ra != rb) {
+ if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
+ q.push({
+ i: s.push(s.pop() + "rotate(", null, ")") - 2,
+ x: d3_interpolateNumber(ra, rb)
+ });
+ } else if (rb) {
+ s.push(s.pop() + "rotate(" + rb + ")");
+ }
+ if (wa != wb) {
+ q.push({
+ i: s.push(s.pop() + "skewX(", null, ")") - 2,
+ x: d3_interpolateNumber(wa, wb)
+ });
+ } else if (wb) {
+ s.push(s.pop() + "skewX(" + wb + ")");
+ }
+ if (ka[0] != kb[0] || ka[1] != kb[1]) {
+ n = s.push(s.pop() + "scale(", null, ",", null,
")");
+ q.push({
+ i: n - 4,
+ x: d3_interpolateNumber(ka[0], kb[0])
+ }, {
+ i: n - 2,
+ x: d3_interpolateNumber(ka[1], kb[1])
+ });
+ } else if (kb[0] != 1 || kb[1] != 1) {
+ s.push(s.pop() + "scale(" + kb + ")");
+ }
+ n = q.length;
+ return function(t) {
+ var i = -1, o;
+ while (++i < n) s[(o = q[i]).i] = o.x(t);
+ return s.join("");
+ };
+ }
+ function d3_uninterpolateNumber(a, b) {
+ b = b - (a = +a) ? 1 / (b - a) : 0;
+ return function(x) {
+ return (x - a) * b;
+ };
+ }
+ function d3_uninterpolateClamp(a, b) {
+ b = b - (a = +a) ? 1 / (b - a) : 0;
+ return function(x) {
+ return Math.max(0, Math.min(1, (x - a) * b));
+ };
+ }
+ d3.layout = {};
+ d3.layout.bundle = function() {
+ return function(links) {
+ var paths = [], i = -1, n = links.length;
+ while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
+ return paths;
+ };
+ };
+ function d3_layout_bundlePath(link) {
+ var start = link.source, end = link.target, lca =
d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
+ while (start !== lca) {
+ start = start.parent;
+ points.push(start);
+ }
+ var k = points.length;
+ while (end !== lca) {
+ points.splice(k, 0, end);
+ end = end.parent;
+ }
+ return points;
+ }
+ function d3_layout_bundleAncestors(node) {
+ var ancestors = [], parent = node.parent;
+ while (parent != null) {
+ ancestors.push(node);
+ node = parent;
+ parent = parent.parent;
+ }
+ ancestors.push(node);
+ return ancestors;
+ }
+ function d3_layout_bundleLeastCommonAncestor(a, b) {
+ if (a === b) return a;
+ var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b),
aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
+ while (aNode === bNode) {
+ sharedNode = aNode;
+ aNode = aNodes.pop();
+ bNode = bNodes.pop();
+ }
+ return sharedNode;
+ }
+ d3.layout.chord = function() {
+ var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups,
sortChords;
+ function relayout() {
+ var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [],
k, x, x0, i, j;
+ chords = [];
+ groups = [];
+ k = 0, i = -1;
+ while (++i < n) {
+ x = 0, j = -1;
+ while (++j < n) {
+ x += matrix[i][j];
+ }
+ groupSums.push(x);
+ subgroupIndex.push(d3.range(n));
+ k += x;
+ }
+ if (sortGroups) {
+ groupIndex.sort(function(a, b) {
+ return sortGroups(groupSums[a], groupSums[b]);
+ });
+ }
+ if (sortSubgroups) {
+ subgroupIndex.forEach(function(d, i) {
+ d.sort(function(a, b) {
+ return sortSubgroups(matrix[i][a], matrix[i][b]);
+ });
+ });
+ }
+ k = (Ï - padding * n) / k;
+ x = 0, i = -1;
+ while (++i < n) {
+ x0 = x, j = -1;
+ while (++j < n) {
+ var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x,
a1 = x += v * k;
+ subgroups[di + "-" + dj] = {
+ index: di,
+ subindex: dj,
+ startAngle: a0,
+ endAngle: a1,
+ value: v
+ };
+ }
+ groups[di] = {
+ index: di,
+ startAngle: x0,
+ endAngle: x,
+ value: (x - x0) / k
+ };
+ x += padding;
+ }
+ i = -1;
+ while (++i < n) {
+ j = i - 1;
+ while (++j < n) {
+ var source = subgroups[i + "-" + j], target = subgroups[j +
"-" + i];
+ if (source.value || target.value) {
+ chords.push(source.value < target.value ? {
+ source: target,
+ target: source
+ } : {
+ source: source,
+ target: target
+ });
+ }
+ }
+ }
+ if (sortChords) resort();
+ }
+ function resort() {
+ chords.sort(function(a, b) {
+ return sortChords((a.source.value + a.target.value) / 2, (b.source.value +
b.target.value) / 2);
+ });
+ }
+ chord.matrix = function(x) {
+ if (!arguments.length) return matrix;
+ n = (matrix = x) && matrix.length;
+ chords = groups = null;
+ return chord;
+ };
+ chord.padding = function(x) {
+ if (!arguments.length) return padding;
+ padding = x;
+ chords = groups = null;
+ return chord;
+ };
+ chord.sortGroups = function(x) {
+ if (!arguments.length) return sortGroups;
+ sortGroups = x;
+ chords = groups = null;
+ return chord;
+ };
+ chord.sortSubgroups = function(x) {
+ if (!arguments.length) return sortSubgroups;
+ sortSubgroups = x;
+ chords = null;
+ return chord;
+ };
+ chord.sortChords = function(x) {
+ if (!arguments.length) return sortChords;
+ sortChords = x;
+ if (chords) resort();
+ return chord;
+ };
+ chord.chords = function() {
+ if (!chords) relayout();
+ return chords;
+ };
+ chord.groups = function() {
+ if (!groups) relayout();
+ return groups;
+ };
+ return chord;
+ };
+ d3.layout.force = function() {
+ var force = {}, event = d3.dispatch("start", "tick",
"end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance =
d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30,
gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges;
+ function repulse(node) {
+ return function(quad, x1, _, x2) {
+ if (quad.point !== node) {
+ var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx +
dy * dy);
+ if ((x2 - x1) * dn < theta) {
+ var k = quad.charge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ return true;
+ }
+ if (quad.point && isFinite(dn)) {
+ var k = quad.pointCharge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
+ }
+ }
+ return !quad.charge;
+ };
+ }
+ force.tick = function() {
+ if ((alpha *= .99) < .005) {
+ event.end({
+ type: "end",
+ alpha: alpha = 0
+ });
+ return true;
+ }
+ var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
+ for (i = 0; i < m; ++i) {
+ o = links[i];
+ s = o.source;
+ t = o.target;
+ x = t.x - s.x;
+ y = t.y - s.y;
+ if (l = x * x + y * y) {
+ l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
+ x *= l;
+ y *= l;
+ t.x -= x * (k = s.weight / (t.weight + s.weight));
+ t.y -= y * k;
+ s.x += x * (k = 1 - k);
+ s.y += y * k;
+ }
+ }
+ if (k = alpha * gravity) {
+ x = size[0] / 2;
+ y = size[1] / 2;
+ i = -1;
+ if (k) while (++i < n) {
+ o = nodes[i];
+ o.x += (x - o.x) * k;
+ o.y += (y - o.y) * k;
+ }
+ }
+ if (charge) {
+ d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
+ i = -1;
+ while (++i < n) {
+ if (!(o = nodes[i]).fixed) {
+ q.visit(repulse(o));
+ }
+ }
+ }
+ i = -1;
+ while (++i < n) {
+ o = nodes[i];
+ if (o.fixed) {
+ o.x = o.px;
+ o.y = o.py;
+ } else {
+ o.x -= (o.px - (o.px = o.x)) * friction;
+ o.y -= (o.py - (o.py = o.y)) * friction;
+ }
+ }
+ event.tick({
+ type: "tick",
+ alpha: alpha
+ });
+ };
+ force.nodes = function(x) {
+ if (!arguments.length) return nodes;
+ nodes = x;
+ return force;
+ };
+ force.links = function(x) {
+ if (!arguments.length) return links;
+ links = x;
+ return force;
+ };
+ force.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return force;
+ };
+ force.linkDistance = function(x) {
+ if (!arguments.length) return linkDistance;
+ linkDistance = typeof x === "function" ? x : +x;
+ return force;
+ };
+ force.distance = force.linkDistance;
+ force.linkStrength = function(x) {
+ if (!arguments.length) return linkStrength;
+ linkStrength = typeof x === "function" ? x : +x;
+ return force;
+ };
+ force.friction = function(x) {
+ if (!arguments.length) return friction;
+ friction = +x;
+ return force;
+ };
+ force.charge = function(x) {
+ if (!arguments.length) return charge;
+ charge = typeof x === "function" ? x : +x;
+ return force;
+ };
+ force.gravity = function(x) {
+ if (!arguments.length) return gravity;
+ gravity = +x;
+ return force;
+ };
+ force.theta = function(x) {
+ if (!arguments.length) return theta;
+ theta = +x;
+ return force;
+ };
+ force.alpha = function(x) {
+ if (!arguments.length) return alpha;
+ x = +x;
+ if (alpha) {
+ if (x > 0) alpha = x; else alpha = 0;
+ } else if (x > 0) {
+ event.start({
+ type: "start",
+ alpha: alpha = x
+ });
+ d3.timer(force.tick);
+ }
+ return force;
+ };
+ force.start = function() {
+ var i, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;
+ for (i = 0; i < n; ++i) {
+ (o = nodes[i]).index = i;
+ o.weight = 0;
+ }
+ for (i = 0; i < m; ++i) {
+ o = links[i];
+ if (typeof o.source == "number") o.source = nodes[o.source];
+ if (typeof o.target == "number") o.target = nodes[o.target];
+ ++o.source.weight;
+ ++o.target.weight;
+ }
+ for (i = 0; i < n; ++i) {
+ o = nodes[i];
+ if (isNaN(o.x)) o.x = position("x", w);
+ if (isNaN(o.y)) o.y = position("y", h);
+ if (isNaN(o.px)) o.px = o.x;
+ if (isNaN(o.py)) o.py = o.y;
+ }
+ distances = [];
+ if (typeof linkDistance === "function") for (i = 0; i < m; ++i)
distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i)
distances[i] = linkDistance;
+ strengths = [];
+ if (typeof linkStrength === "function") for (i = 0; i < m; ++i)
strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i)
strengths[i] = linkStrength;
+ charges = [];
+ if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] =
+charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge;
+ function position(dimension, size) {
+ if (!neighbors) {
+ neighbors = new Array(n);
+ for (j = 0; j < n; ++j) {
+ neighbors[j] = [];
+ }
+ for (j = 0; j < m; ++j) {
+ var o = links[j];
+ neighbors[o.source.index].push(o.target);
+ neighbors[o.target.index].push(o.source);
+ }
+ }
+ var candidates = neighbors[i], j = -1, m = candidates.length, x;
+ while (++j < m) if (!isNaN(x = candidates[j][dimension])) return x;
+ return Math.random() * size;
+ }
+ return force.resume();
+ };
+ force.resume = function() {
+ return force.alpha(.1);
+ };
+ force.stop = function() {
+ return force.alpha(0);
+ };
+ force.drag = function() {
+ if (!drag) drag =
d3.behavior.drag().origin(d3_identity).on("dragstart.force",
d3_layout_forceDragstart).on("drag.force",
dragmove).on("dragend.force", d3_layout_forceDragend);
+ if (!arguments.length) return drag;
+ this.on("mouseover.force",
d3_layout_forceMouseover).on("mouseout.force",
d3_layout_forceMouseout).call(drag);
+ };
+ function dragmove(d) {
+ d.px = d3.event.x, d.py = d3.event.y;
+ force.resume();
+ }
+ return d3.rebind(force, event, "on");
+ };
+ function d3_layout_forceDragstart(d) {
+ d.fixed |= 2;
+ }
+ function d3_layout_forceDragend(d) {
+ d.fixed &= ~6;
+ }
+ function d3_layout_forceMouseover(d) {
+ d.fixed |= 4;
+ d.px = d.x, d.py = d.y;
+ }
+ function d3_layout_forceMouseout(d) {
+ d.fixed &= ~4;
+ }
+ function d3_layout_forceAccumulate(quad, alpha, charges) {
+ var cx = 0, cy = 0;
+ quad.charge = 0;
+ if (!quad.leaf) {
+ var nodes = quad.nodes, n = nodes.length, i = -1, c;
+ while (++i < n) {
+ c = nodes[i];
+ if (c == null) continue;
+ d3_layout_forceAccumulate(c, alpha, charges);
+ quad.charge += c.charge;
+ cx += c.charge * c.cx;
+ cy += c.charge * c.cy;
+ }
+ }
+ if (quad.point) {
+ if (!quad.leaf) {
+ quad.point.x += Math.random() - .5;
+ quad.point.y += Math.random() - .5;
+ }
+ var k = alpha * charges[quad.point.index];
+ quad.charge += quad.pointCharge = k;
+ cx += k * quad.point.x;
+ cy += k * quad.point.y;
+ }
+ quad.cx = cx / quad.charge;
+ quad.cy = cy / quad.charge;
+ }
+ var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1;
+ d3.layout.hierarchy = function() {
+ var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value =
d3_layout_hierarchyValue;
+ function recurse(node, depth, nodes) {
+ var childs = children.call(hierarchy, node, depth);
+ node.depth = depth;
+ nodes.push(node);
+ if (childs && (n = childs.length)) {
+ var i = -1, n, c = node.children = new Array(n), v = 0, j = depth + 1, d;
+ while (++i < n) {
+ d = c[i] = recurse(childs[i], j, nodes);
+ d.parent = node;
+ v += d.value;
+ }
+ if (sort) c.sort(sort);
+ if (value) node.value = v;
+ } else {
+ delete node.children;
+ if (value) {
+ node.value = +value.call(hierarchy, node, depth) || 0;
+ }
+ }
+ return node;
+ }
+ function revalue(node, depth) {
+ var children = node.children, v = 0;
+ if (children && (n = children.length)) {
+ var i = -1, n, j = depth + 1;
+ while (++i < n) v += revalue(children[i], j);
+ } else if (value) {
+ v = +value.call(hierarchy, node, depth) || 0;
+ }
+ if (value) node.value = v;
+ return v;
+ }
+ function hierarchy(d) {
+ var nodes = [];
+ recurse(d, 0, nodes);
+ return nodes;
+ }
+ hierarchy.sort = function(x) {
+ if (!arguments.length) return sort;
+ sort = x;
+ return hierarchy;
+ };
+ hierarchy.children = function(x) {
+ if (!arguments.length) return children;
+ children = x;
+ return hierarchy;
+ };
+ hierarchy.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return hierarchy;
+ };
+ hierarchy.revalue = function(root) {
+ revalue(root, 0);
+ return root;
+ };
+ return hierarchy;
+ };
+ function d3_layout_hierarchyRebind(object, hierarchy) {
+ d3.rebind(object, hierarchy, "sort", "children",
"value");
+ object.nodes = object;
+ object.links = d3_layout_hierarchyLinks;
+ return object;
+ }
+ function d3_layout_hierarchyChildren(d) {
+ return d.children;
+ }
+ function d3_layout_hierarchyValue(d) {
+ return d.value;
+ }
+ function d3_layout_hierarchySort(a, b) {
+ return b.value - a.value;
+ }
+ function d3_layout_hierarchyLinks(nodes) {
+ return d3.merge(nodes.map(function(parent) {
+ return (parent.children || []).map(function(child) {
+ return {
+ source: parent,
+ target: child
+ };
+ });
+ }));
+ }
+ d3.layout.partition = function() {
+ var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
+ function position(node, x, dx, dy) {
+ var children = node.children;
+ node.x = x;
+ node.y = node.depth * dy;
+ node.dx = dx;
+ node.dy = dy;
+ if (children && (n = children.length)) {
+ var i = -1, n, c, d;
+ dx = node.value ? dx / node.value : 0;
+ while (++i < n) {
+ position(c = children[i], x, d = c.value * dx, dy);
+ x += d;
+ }
+ }
+ }
+ function depth(node) {
+ var children = node.children, d = 0;
+ if (children && (n = children.length)) {
+ var i = -1, n;
+ while (++i < n) d = Math.max(d, depth(children[i]));
+ }
+ return 1 + d;
+ }
+ function partition(d, i) {
+ var nodes = hierarchy.call(this, d, i);
+ position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
+ return nodes;
+ }
+ partition.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return partition;
+ };
+ return d3_layout_hierarchyRebind(partition, hierarchy);
+ };
+ d3.layout.pie = function() {
+ var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = Ï;
+ function pie(data) {
+ var values = data.map(function(d, i) {
+ return +value.call(pie, d, i);
+ });
+ var a = +(typeof startAngle === "function" ? startAngle.apply(this,
arguments) : startAngle);
+ var k = ((typeof endAngle === "function" ? endAngle.apply(this,
arguments) : endAngle) - a) / d3.sum(values);
+ var index = d3.range(data.length);
+ if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
+ return values[j] - values[i];
+ } : function(i, j) {
+ return sort(data[i], data[j]);
+ });
+ var arcs = [];
+ index.forEach(function(i) {
+ var d;
+ arcs[i] = {
+ data: data[i],
+ value: d = values[i],
+ startAngle: a,
+ endAngle: a += d * k
+ };
+ });
+ return arcs;
+ }
+ pie.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return pie;
+ };
+ pie.sort = function(x) {
+ if (!arguments.length) return sort;
+ sort = x;
+ return pie;
+ };
+ pie.startAngle = function(x) {
+ if (!arguments.length) return startAngle;
+ startAngle = x;
+ return pie;
+ };
+ pie.endAngle = function(x) {
+ if (!arguments.length) return endAngle;
+ endAngle = x;
+ return pie;
+ };
+ return pie;
+ };
+ var d3_layout_pieSortByValue = {};
+ d3.layout.stack = function() {
+ var values = d3_identity, order = d3_layout_stackOrderDefault, offset =
d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y =
d3_layout_stackY;
+ function stack(data, index) {
+ var series = data.map(function(d, i) {
+ return values.call(stack, d, i);
+ });
+ var points = series.map(function(d) {
+ return d.map(function(v, i) {
+ return [ x.call(stack, v, i), y.call(stack, v, i) ];
+ });
+ });
+ var orders = order.call(stack, points, index);
+ series = d3.permute(series, orders);
+ points = d3.permute(points, orders);
+ var offsets = offset.call(stack, points, index);
+ var n = series.length, m = series[0].length, i, j, o;
+ for (j = 0; j < m; ++j) {
+ out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
+ for (i = 1; i < n; ++i) {
+ out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
+ }
+ }
+ return data;
+ }
+ stack.values = function(x) {
+ if (!arguments.length) return values;
+ values = x;
+ return stack;
+ };
+ stack.order = function(x) {
+ if (!arguments.length) return order;
+ order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) ||
d3_layout_stackOrderDefault;
+ return stack;
+ };
+ stack.offset = function(x) {
+ if (!arguments.length) return offset;
+ offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) ||
d3_layout_stackOffsetZero;
+ return stack;
+ };
+ stack.x = function(z) {
+ if (!arguments.length) return x;
+ x = z;
+ return stack;
+ };
+ stack.y = function(z) {
+ if (!arguments.length) return y;
+ y = z;
+ return stack;
+ };
+ stack.out = function(z) {
+ if (!arguments.length) return out;
+ out = z;
+ return stack;
+ };
+ return stack;
+ };
+ function d3_layout_stackX(d) {
+ return d.x;
+ }
+ function d3_layout_stackY(d) {
+ return d.y;
+ }
+ function d3_layout_stackOut(d, y0, y) {
+ d.y0 = y0;
+ d.y = y;
+ }
+ var d3_layout_stackOrders = d3.map({
+ "inside-out": function(data) {
+ var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums =
data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {
+ return max[a] - max[b];
+ }), top = 0, bottom = 0, tops = [], bottoms = [];
+ for (i = 0; i < n; ++i) {
+ j = index[i];
+ if (top < bottom) {
+ top += sums[j];
+ tops.push(j);
+ } else {
+ bottom += sums[j];
+ bottoms.push(j);
+ }
+ }
+ return bottoms.reverse().concat(tops);
+ },
+ reverse: function(data) {
+ return d3.range(data.length).reverse();
+ },
+ "default": d3_layout_stackOrderDefault
+ });
+ var d3_layout_stackOffsets = d3.map({
+ silhouette: function(data) {
+ var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
+ for (j = 0; j < m; ++j) {
+ for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+ if (o > max) max = o;
+ sums.push(o);
+ }
+ for (j = 0; j < m; ++j) {
+ y0[j] = (max - sums[j]) / 2;
+ }
+ return y0;
+ },
+ wiggle: function(data) {
+ var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0
= [];
+ y0[0] = o = o0 = 0;
+ for (j = 1; j < m; ++j) {
+ for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
+ for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
+ for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k)
{
+ s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
+ }
+ s2 += s3 * data[i][j][1];
+ }
+ y0[j] = o -= s1 ? s2 / s1 * dx : 0;
+ if (o < o0) o0 = o;
+ }
+ for (j = 0; j < m; ++j) y0[j] -= o0;
+ return y0;
+ },
+ expand: function(data) {
+ var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
+ for (j = 0; j < m; ++j) {
+ for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
+ if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n;
i++) data[i][j][1] = k;
+ }
+ for (j = 0; j < m; ++j) y0[j] = 0;
+ return y0;
+ },
+ zero: d3_layout_stackOffsetZero
+ });
+ function d3_layout_stackOrderDefault(data) {
+ return d3.range(data.length);
+ }
+ function d3_layout_stackOffsetZero(data) {
+ var j = -1, m = data[0].length, y0 = [];
+ while (++j < m) y0[j] = 0;
+ return y0;
+ }
+ function d3_layout_stackMaxIndex(array) {
+ var i = 1, j = 0, v = array[0][1], k, n = array.length;
+ for (;i < n; ++i) {
+ if ((k = array[i][1]) > v) {
+ j = i;
+ v = k;
+ }
+ }
+ return j;
+ }
+ function d3_layout_stackReduceSum(d) {
+ return d.reduce(d3_layout_stackSum, 0);
+ }
+ function d3_layout_stackSum(p, d) {
+ return p + d[1];
+ }
+ d3.layout.histogram = function() {
+ var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner =
d3_layout_histogramBinSturges;
+ function histogram(data, i) {
+ var bins = [], values = data.map(valuer, this), range = ranger.call(this, values,
i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m =
thresholds.length - 1, k = frequency ? 1 : 1 / n, x;
+ while (++i < m) {
+ bin = bins[i] = [];
+ bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
+ bin.y = 0;
+ }
+ if (m > 0) {
+ i = -1;
+ while (++i < n) {
+ x = values[i];
+ if (x >= range[0] && x <= range[1]) {
+ bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
+ bin.y += k;
+ bin.push(data[i]);
+ }
+ }
+ }
+ return bins;
+ }
+ histogram.value = function(x) {
+ if (!arguments.length) return valuer;
+ valuer = x;
+ return histogram;
+ };
+ histogram.range = function(x) {
+ if (!arguments.length) return ranger;
+ ranger = d3_functor(x);
+ return histogram;
+ };
+ histogram.bins = function(x) {
+ if (!arguments.length) return binner;
+ binner = typeof x === "number" ? function(range) {
+ return d3_layout_histogramBinFixed(range, x);
+ } : d3_functor(x);
+ return histogram;
+ };
+ histogram.frequency = function(x) {
+ if (!arguments.length) return frequency;
+ frequency = !!x;
+ return histogram;
+ };
+ return histogram;
+ };
+ function d3_layout_histogramBinSturges(range, values) {
+ return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) /
Math.LN2 + 1));
+ }
+ function d3_layout_histogramBinFixed(range, n) {
+ var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
+ while (++x <= n) f[x] = m * x + b;
+ return f;
+ }
+ function d3_layout_histogramRange(values) {
+ return [ d3.min(values), d3.max(values) ];
+ }
+ d3.layout.tree = function() {
+ var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation =
d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
+ function tree(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0];
+ function firstWalk(node, previousSibling) {
+ var children = node.children, layout = node._tree;
+ if (children && (n = children.length)) {
+ var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i
= -1;
+ while (++i < n) {
+ child = children[i];
+ firstWalk(child, previousChild);
+ ancestor = apportion(child, previousChild, ancestor);
+ previousChild = child;
+ }
+ d3_layout_treeShift(node);
+ var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node,
previousSibling);
+ layout.mod = layout.prelim - midpoint;
+ } else {
+ layout.prelim = midpoint;
+ }
+ } else {
+ if (previousSibling) {
+ layout.prelim = previousSibling._tree.prelim + separation(node,
previousSibling);
+ }
+ }
+ }
+ function secondWalk(node, x) {
+ node.x = node._tree.prelim + x;
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var i = -1, n;
+ x += node._tree.mod;
+ while (++i < n) {
+ secondWalk(children[i], x);
+ }
+ }
+ }
+ function apportion(node, previousSibling, ancestor) {
+ if (previousSibling) {
+ var vip = node, vop = node, vim = previousSibling, vom =
node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod,
som = vom._tree.mod, shift;
+ while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim
&& vip) {
+ vom = d3_layout_treeLeft(vom);
+ vop = d3_layout_treeRight(vop);
+ vop._tree.ancestor = node;
+ shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim,
vip);
+ if (shift > 0) {
+ d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node,
shift);
+ sip += shift;
+ sop += shift;
+ }
+ sim += vim._tree.mod;
+ sip += vip._tree.mod;
+ som += vom._tree.mod;
+ sop += vop._tree.mod;
+ }
+ if (vim && !d3_layout_treeRight(vop)) {
+ vop._tree.thread = vim;
+ vop._tree.mod += sim - sop;
+ }
+ if (vip && !d3_layout_treeLeft(vom)) {
+ vom._tree.thread = vip;
+ vom._tree.mod += sip - som;
+ ancestor = node;
+ }
+ }
+ return ancestor;
+ }
+ d3_layout_treeVisitAfter(root, function(node, previousSibling) {
+ node._tree = {
+ ancestor: node,
+ prelim: 0,
+ mod: 0,
+ change: 0,
+ shift: 0,
+ number: previousSibling ? previousSibling._tree.number + 1 : 0
+ };
+ });
+ firstWalk(root);
+ secondWalk(root, -root._tree.prelim);
+ var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right =
d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root,
d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x +
separation(right, left) / 2, y1 = deep.depth || 1;
+ d3_layout_treeVisitAfter(root, nodeSize ? function(node) {
+ node.x *= size[0];
+ node.y = node.depth * size[1];
+ delete node._tree;
+ } : function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * size[0];
+ node.y = node.depth / y1 * size[1];
+ delete node._tree;
+ });
+ return nodes;
+ }
+ tree.separation = function(x) {
+ if (!arguments.length) return separation;
+ separation = x;
+ return tree;
+ };
+ tree.size = function(x) {
+ if (!arguments.length) return nodeSize ? null : size;
+ nodeSize = (size = x) == null;
+ return tree;
+ };
+ tree.nodeSize = function(x) {
+ if (!arguments.length) return nodeSize ? size : null;
+ nodeSize = (size = x) != null;
+ return tree;
+ };
+ return d3_layout_hierarchyRebind(tree, hierarchy);
+ };
+ function d3_layout_treeSeparation(a, b) {
+ return a.parent == b.parent ? 1 : 2;
+ }
+ function d3_layout_treeLeft(node) {
+ var children = node.children;
+ return children && children.length ? children[0] : node._tree.thread;
+ }
+ function d3_layout_treeRight(node) {
+ var children = node.children, n;
+ return children && (n = children.length) ? children[n - 1] :
node._tree.thread;
+ }
+ function d3_layout_treeSearch(node, compare) {
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var child, n, i = -1;
+ while (++i < n) {
+ if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
+ node = child;
+ }
+ }
+ }
+ return node;
+ }
+ function d3_layout_treeRightmost(a, b) {
+ return a.x - b.x;
+ }
+ function d3_layout_treeLeftmost(a, b) {
+ return b.x - a.x;
+ }
+ function d3_layout_treeDeepest(a, b) {
+ return a.depth - b.depth;
+ }
+ function d3_layout_treeVisitAfter(node, callback) {
+ function visit(node, previousSibling) {
+ var children = node.children;
+ if (children && (n = children.length)) {
+ var child, previousChild = null, i = -1, n;
+ while (++i < n) {
+ child = children[i];
+ visit(child, previousChild);
+ previousChild = child;
+ }
+ }
+ callback(node, previousSibling);
+ }
+ visit(node, null);
+ }
+ function d3_layout_treeShift(node) {
+ var shift = 0, change = 0, children = node.children, i = children.length, child;
+ while (--i >= 0) {
+ child = children[i]._tree;
+ child.prelim += shift;
+ child.mod += shift;
+ shift += child.shift + (change += child.change);
+ }
+ }
+ function d3_layout_treeMove(ancestor, node, shift) {
+ ancestor = ancestor._tree;
+ node = node._tree;
+ var change = shift / (node.number - ancestor.number);
+ ancestor.change += change;
+ node.change -= change;
+ node.shift += shift;
+ node.prelim += shift;
+ node.mod += shift;
+ }
+ function d3_layout_treeAncestor(vim, node, ancestor) {
+ return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor;
+ }
+ d3.layout.pack = function() {
+ var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [
1, 1 ], radius;
+ function pack(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1],
r = radius == null ? Math.sqrt : typeof radius === "function" ? radius :
function() {
+ return radius;
+ };
+ root.x = root.y = 0;
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r = +r(d.value);
+ });
+ d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+ if (padding) {
+ var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2;
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r += dr;
+ });
+ d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
+ d3_layout_treeVisitAfter(root, function(d) {
+ d.r -= dr;
+ });
+ }
+ d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r /
w, 2 * root.r / h));
+ return nodes;
+ }
+ pack.size = function(_) {
+ if (!arguments.length) return size;
+ size = _;
+ return pack;
+ };
+ pack.radius = function(_) {
+ if (!arguments.length) return radius;
+ radius = _ == null || typeof _ === "function" ? _ : +_;
+ return pack;
+ };
+ pack.padding = function(_) {
+ if (!arguments.length) return padding;
+ padding = +_;
+ return pack;
+ };
+ return d3_layout_hierarchyRebind(pack, hierarchy);
+ };
+ function d3_layout_packSort(a, b) {
+ return a.value - b.value;
+ }
+ function d3_layout_packInsert(a, b) {
+ var c = a._pack_next;
+ a._pack_next = b;
+ b._pack_prev = a;
+ b._pack_next = c;
+ c._pack_prev = b;
+ }
+ function d3_layout_packSplice(a, b) {
+ a._pack_next = b;
+ b._pack_prev = a;
+ }
+ function d3_layout_packIntersects(a, b) {
+ var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
+ return .999 * dr * dr > dx * dx + dy * dy;
+ }
+ function d3_layout_packSiblings(node) {
+ if (!(nodes = node.children) || !(n = nodes.length)) return;
+ var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a,
b, c, i, j, k, n;
+ function bound(node) {
+ xMin = Math.min(node.x - node.r, xMin);
+ xMax = Math.max(node.x + node.r, xMax);
+ yMin = Math.min(node.y - node.r, yMin);
+ yMax = Math.max(node.y + node.r, yMax);
+ }
+ nodes.forEach(d3_layout_packLink);
+ a = nodes[0];
+ a.x = -a.r;
+ a.y = 0;
+ bound(a);
+ if (n > 1) {
+ b = nodes[1];
+ b.x = b.r;
+ b.y = 0;
+ bound(b);
+ if (n > 2) {
+ c = nodes[2];
+ d3_layout_packPlace(a, b, c);
+ bound(c);
+ d3_layout_packInsert(a, c);
+ a._pack_prev = c;
+ d3_layout_packInsert(c, b);
+ b = a._pack_next;
+ for (i = 3; i < n; i++) {
+ d3_layout_packPlace(a, b, c = nodes[i]);
+ var isect = 0, s1 = 1, s2 = 1;
+ for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
+ if (d3_layout_packIntersects(j, c)) {
+ isect = 1;
+ break;
+ }
+ }
+ if (isect == 1) {
+ for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
+ if (d3_layout_packIntersects(k, c)) {
+ break;
+ }
+ }
+ }
+ if (isect) {
+ if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b
= j); else d3_layout_packSplice(a = k, b);
+ i--;
+ } else {
+ d3_layout_packInsert(a, c);
+ b = c;
+ bound(c);
+ }
+ }
+ }
+ }
+ var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
+ for (i = 0; i < n; i++) {
+ c = nodes[i];
+ c.x -= cx;
+ c.y -= cy;
+ cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
+ }
+ node.r = cr;
+ nodes.forEach(d3_layout_packUnlink);
+ }
+ function d3_layout_packLink(node) {
+ node._pack_next = node._pack_prev = node;
+ }
+ function d3_layout_packUnlink(node) {
+ delete node._pack_next;
+ delete node._pack_prev;
+ }
+ function d3_layout_packTransform(node, x, y, k) {
+ var children = node.children;
+ node.x = x += k * node.x;
+ node.y = y += k * node.y;
+ node.r *= k;
+ if (children) {
+ var i = -1, n = children.length;
+ while (++i < n) d3_layout_packTransform(children[i], x, y, k);
+ }
+ }
+ function d3_layout_packPlace(a, b, c) {
+ var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
+ if (db && (dx || dy)) {
+ var da = b.r + c.r, dc = dx * dx + dy * dy;
+ da *= da;
+ db *= db;
+ var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) -
(db -= dc) * db - da * da)) / (2 * dc);
+ c.x = a.x + x * dx + y * dy;
+ c.y = a.y + x * dy - y * dx;
+ } else {
+ c.x = a.x + db;
+ c.y = a.y;
+ }
+ }
+ d3.layout.cluster = function() {
+ var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation =
d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
+ function cluster(d, i) {
+ var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
+ d3_layout_treeVisitAfter(root, function(node) {
+ var children = node.children;
+ if (children && children.length) {
+ node.x = d3_layout_clusterX(children);
+ node.y = d3_layout_clusterY(children);
+ } else {
+ node.x = previousNode ? x += separation(node, previousNode) : 0;
+ node.y = 0;
+ previousNode = node;
+ }
+ });
+ var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 =
left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;
+ d3_layout_treeVisitAfter(root, nodeSize ? function(node) {
+ node.x = (node.x - root.x) * size[0];
+ node.y = (root.y - node.y) * size[1];
+ } : function(node) {
+ node.x = (node.x - x0) / (x1 - x0) * size[0];
+ node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
+ });
+ return nodes;
+ }
+ cluster.separation = function(x) {
+ if (!arguments.length) return separation;
+ separation = x;
+ return cluster;
+ };
+ cluster.size = function(x) {
+ if (!arguments.length) return nodeSize ? null : size;
+ nodeSize = (size = x) == null;
+ return cluster;
+ };
+ cluster.nodeSize = function(x) {
+ if (!arguments.length) return nodeSize ? size : null;
+ nodeSize = (size = x) != null;
+ return cluster;
+ };
+ return d3_layout_hierarchyRebind(cluster, hierarchy);
+ };
+ function d3_layout_clusterY(children) {
+ return 1 + d3.max(children, function(child) {
+ return child.y;
+ });
+ }
+ function d3_layout_clusterX(children) {
+ return children.reduce(function(x, child) {
+ return x + child.x;
+ }, 0) / children.length;
+ }
+ function d3_layout_clusterLeft(node) {
+ var children = node.children;
+ return children && children.length ? d3_layout_clusterLeft(children[0]) :
node;
+ }
+ function d3_layout_clusterRight(node) {
+ var children = node.children, n;
+ return children && (n = children.length) ? d3_layout_clusterRight(children[n
- 1]) : node;
+ }
+ d3.layout.treemap = function() {
+ var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding =
null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode =
"squarify", ratio = .5 * (1 + Math.sqrt(5));
+ function scale(children, k) {
+ var i = -1, n = children.length, child, area;
+ while (++i < n) {
+ area = (child = children[i]).value * (k < 0 ? 0 : k);
+ child.area = isNaN(area) || area <= 0 ? 0 : area;
+ }
+ }
+ function squarify(node) {
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node), row = [], remaining = children.slice(), child, best =
Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ?
rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx :
Math.min(rect.dx, rect.dy), n;
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while ((n = remaining.length) > 0) {
+ row.push(child = remaining[n - 1]);
+ row.area += child.area;
+ if (mode !== "squarify" || (score = worst(row, u)) <= best) {
+ remaining.pop();
+ best = score;
+ } else {
+ row.area -= row.pop().area;
+ position(row, u, rect, false);
+ u = Math.min(rect.dx, rect.dy);
+ row.length = row.area = 0;
+ best = Infinity;
+ }
+ }
+ if (row.length) {
+ position(row, u, rect, true);
+ row.length = row.area = 0;
+ }
+ children.forEach(squarify);
+ }
+ }
+ function stickify(node) {
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node), remaining = children.slice(), child, row = [];
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while (child = remaining.pop()) {
+ row.push(child);
+ row.area += child.area;
+ if (child.z != null) {
+ position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
+ row.length = row.area = 0;
+ }
+ }
+ children.forEach(stickify);
+ }
+ }
+ function worst(row, u) {
+ var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
+ while (++i < n) {
+ if (!(r = row[i].area)) continue;
+ if (r < rmin) rmin = r;
+ if (r > rmax) rmax = r;
+ }
+ s *= s;
+ u *= u;
+ return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
+ }
+ function position(row, u, rect, flush) {
+ var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) :
0, o;
+ if (u == rect.dx) {
+ if (flush || v > rect.dy) v = rect.dy;
+ while (++i < n) {
+ o = row[i];
+ o.x = x;
+ o.y = y;
+ o.dy = v;
+ x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
+ }
+ o.z = true;
+ o.dx += rect.x + rect.dx - x;
+ rect.y += v;
+ rect.dy -= v;
+ } else {
+ if (flush || v > rect.dx) v = rect.dx;
+ while (++i < n) {
+ o = row[i];
+ o.x = x;
+ o.y = y;
+ o.dx = v;
+ y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
+ }
+ o.z = false;
+ o.dy += rect.y + rect.dy - y;
+ rect.x += v;
+ rect.dx -= v;
+ }
+ }
+ function treemap(d) {
+ var nodes = stickies || hierarchy(d), root = nodes[0];
+ root.x = 0;
+ root.y = 0;
+ root.dx = size[0];
+ root.dy = size[1];
+ if (stickies) hierarchy.revalue(root);
+ scale([ root ], root.dx * root.dy / root.value);
+ (stickies ? stickify : squarify)(root);
+ if (sticky) stickies = nodes;
+ return nodes;
+ }
+ treemap.size = function(x) {
+ if (!arguments.length) return size;
+ size = x;
+ return treemap;
+ };
+ treemap.padding = function(x) {
+ if (!arguments.length) return padding;
+ function padFunction(node) {
+ var p = x.call(treemap, node, node.depth);
+ return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node,
typeof p === "number" ? [ p, p, p, p ] : p);
+ }
+ function padConstant(node) {
+ return d3_layout_treemapPad(node, x);
+ }
+ var type;
+ pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) ===
"function" ? padFunction : type === "number" ? (x = [ x, x, x, x ],
+ padConstant) : padConstant;
+ return treemap;
+ };
+ treemap.round = function(x) {
+ if (!arguments.length) return round != Number;
+ round = x ? Math.round : Number;
+ return treemap;
+ };
+ treemap.sticky = function(x) {
+ if (!arguments.length) return sticky;
+ sticky = x;
+ stickies = null;
+ return treemap;
+ };
+ treemap.ratio = function(x) {
+ if (!arguments.length) return ratio;
+ ratio = x;
+ return treemap;
+ };
+ treemap.mode = function(x) {
+ if (!arguments.length) return mode;
+ mode = x + "";
+ return treemap;
+ };
+ return d3_layout_hierarchyRebind(treemap, hierarchy);
+ };
+ function d3_layout_treemapPadNull(node) {
+ return {
+ x: node.x,
+ y: node.y,
+ dx: node.dx,
+ dy: node.dy
+ };
+ }
+ function d3_layout_treemapPad(node, padding) {
+ var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] -
padding[3], dy = node.dy - padding[0] - padding[2];
+ if (dx < 0) {
+ x += dx / 2;
+ dx = 0;
+ }
+ if (dy < 0) {
+ y += dy / 2;
+ dy = 0;
+ }
+ return {
+ x: x,
+ y: y,
+ dx: dx,
+ dy: dy
+ };
+ }
+ d3.random = {
+ normal: function(µ, Ï) {
+ var n = arguments.length;
+ if (n < 2) Ï = 1;
+ if (n < 1) µ = 0;
+ return function() {
+ var x, y, r;
+ do {
+ x = Math.random() * 2 - 1;
+ y = Math.random() * 2 - 1;
+ r = x * x + y * y;
+ } while (!r || r > 1);
+ return µ + Ï * x * Math.sqrt(-2 * Math.log(r) / r);
+ };
+ },
+ logNormal: function() {
+ var random = d3.random.normal.apply(d3, arguments);
+ return function() {
+ return Math.exp(random());
+ };
+ },
+ bates: function(m) {
+ var random = d3.random.irwinHall(m);
+ return function() {
+ return random() / m;
+ };
+ },
+ irwinHall: function(m) {
+ return function() {
+ for (var s = 0, j = 0; j < m; j++) s += Math.random();
+ return s;
+ };
+ }
+ };
+ d3.scale = {};
+ function d3_scaleExtent(domain) {
+ var start = domain[0], stop = domain[domain.length - 1];
+ return start < stop ? [ start, stop ] : [ stop, start ];
+ }
+ function d3_scaleRange(scale) {
+ return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
+ }
+ function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
+ var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
+ return function(x) {
+ return i(u(x));
+ };
+ }
+ function d3_scale_nice(domain, nice) {
+ var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
+ if (x1 < x0) {
+ dx = i0, i0 = i1, i1 = dx;
+ dx = x0, x0 = x1, x1 = dx;
+ }
+ domain[i0] = nice.floor(x0);
+ domain[i1] = nice.ceil(x1);
+ return domain;
+ }
+ function d3_scale_niceStep(step) {
+ return step ? {
+ floor: function(x) {
+ return Math.floor(x / step) * step;
+ },
+ ceil: function(x) {
+ return Math.ceil(x / step) * step;
+ }
+ } : d3_scale_niceIdentity;
+ }
+ var d3_scale_niceIdentity = {
+ floor: d3_identity,
+ ceil: d3_identity
+ };
+ function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
+ var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
+ if (domain[k] < domain[0]) {
+ domain = domain.slice().reverse();
+ range = range.slice().reverse();
+ }
+ while (++j <= k) {
+ u.push(uninterpolate(domain[j - 1], domain[j]));
+ i.push(interpolate(range[j - 1], range[j]));
+ }
+ return function(x) {
+ var j = d3.bisect(domain, x, 1, k) - 1;
+ return i[j](u[j](x));
+ };
+ }
+ d3.scale.linear = function() {
+ return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false);
+ };
+ function d3_scale_linear(domain, range, interpolate, clamp) {
+ var output, input;
+ function rescale() {
+ var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear :
d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp :
d3_uninterpolateNumber;
+ output = linear(domain, range, uninterpolate, interpolate);
+ input = linear(range, domain, uninterpolate, d3_interpolate);
+ return scale;
+ }
+ function scale(x) {
+ return output(x);
+ }
+ scale.invert = function(y) {
+ return input(y);
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.map(Number);
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.rangeRound = function(x) {
+ return scale.range(x).interpolate(d3_interpolateRound);
+ };
+ scale.clamp = function(x) {
+ if (!arguments.length) return clamp;
+ clamp = x;
+ return rescale();
+ };
+ scale.interpolate = function(x) {
+ if (!arguments.length) return interpolate;
+ interpolate = x;
+ return rescale();
+ };
+ scale.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ scale.tickFormat = function(m, format) {
+ return d3_scale_linearTickFormat(domain, m, format);
+ };
+ scale.nice = function(m) {
+ d3_scale_linearNice(domain, m);
+ return rescale();
+ };
+ scale.copy = function() {
+ return d3_scale_linear(domain, range, interpolate, clamp);
+ };
+ return rescale();
+ }
+ function d3_scale_linearRebind(scale, linear) {
+ return d3.rebind(scale, linear, "range", "rangeRound",
"interpolate", "clamp");
+ }
+ function d3_scale_linearNice(domain, m) {
+ return d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain,
m)[2]));
+ }
+ function d3_scale_linearTickRange(domain, m) {
+ if (m == null) m = 10;
+ var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step =
Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
+ if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <=
.75) step *= 2;
+ extent[0] = Math.ceil(extent[0] / step) * step;
+ extent[1] = Math.floor(extent[1] / step) * step + step * .5;
+ extent[2] = step;
+ return extent;
+ }
+ function d3_scale_linearTicks(domain, m) {
+ return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
+ }
+ function d3_scale_linearTickFormat(domain, m, format) {
+ var range = d3_scale_linearTickRange(domain, m);
+ return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g,
h, i, j) {
+ return [ b, c, d, e, f, g, h, i || "." +
d3_scale_linearFormatPrecision(j, range), j ].join("");
+ }) : ",." + d3_scale_linearPrecision(range[2]) + "f");
+ }
+ var d3_scale_linearFormatSignificant = {
+ s: 1,
+ g: 1,
+ p: 1,
+ r: 1,
+ e: 1
+ };
+ function d3_scale_linearPrecision(value) {
+ return -Math.floor(Math.log(value) / Math.LN10 + .01);
+ }
+ function d3_scale_linearFormatPrecision(type, range) {
+ var p = d3_scale_linearPrecision(range[2]);
+ return type in d3_scale_linearFormatSignificant ? Math.abs(p -
d3_scale_linearPrecision(Math.max(Math.abs(range[0]), Math.abs(range[1])))) + +(type !==
"e") : p - (type === "%") * 2;
+ }
+ d3.scale.log = function() {
+ return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]);
+ };
+ function d3_scale_log(linear, base, positive, domain) {
+ function log(x) {
+ return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) /
Math.log(base);
+ }
+ function pow(x) {
+ return positive ? Math.pow(base, x) : -Math.pow(base, -x);
+ }
+ function scale(x) {
+ return linear(log(x));
+ }
+ scale.invert = function(x) {
+ return pow(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ positive = x[0] >= 0;
+ linear.domain((domain = x.map(Number)).map(log));
+ return scale;
+ };
+ scale.base = function(_) {
+ if (!arguments.length) return base;
+ base = +_;
+ linear.domain(domain.map(log));
+ return scale;
+ };
+ scale.nice = function() {
+ var niced = d3_scale_nice(domain.map(log), positive ? Math :
d3_scale_logNiceNegative);
+ linear.domain(niced);
+ domain = niced.map(pow);
+ return scale;
+ };
+ scale.ticks = function() {
+ var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i =
Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base;
+ if (isFinite(j - i)) {
+ if (positive) {
+ for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k);
+ ticks.push(pow(i));
+ } else {
+ ticks.push(pow(i));
+ for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k);
+ }
+ for (i = 0; ticks[i] < u; i++) {}
+ for (j = ticks.length; ticks[j - 1] > v; j--) {}
+ ticks = ticks.slice(i, j);
+ }
+ return ticks;
+ };
+ scale.tickFormat = function(n, format) {
+ if (!arguments.length) return d3_scale_logFormat;
+ if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format
!== "function") format = d3.format(format);
+ var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12,
Math.ceil) : (e = -1e-12,
+ Math.floor), e;
+ return function(d) {
+ return d / pow(f(log(d) + e)) <= k ? format(d) : "";
+ };
+ };
+ scale.copy = function() {
+ return d3_scale_log(linear.copy(), base, positive, domain);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = {
+ floor: function(x) {
+ return -Math.ceil(-x);
+ },
+ ceil: function(x) {
+ return -Math.floor(-x);
+ }
+ };
+ d3.scale.pow = function() {
+ return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]);
+ };
+ function d3_scale_pow(linear, exponent, domain) {
+ var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
+ function scale(x) {
+ return linear(powp(x));
+ }
+ scale.invert = function(x) {
+ return powb(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ linear.domain((domain = x.map(Number)).map(powp));
+ return scale;
+ };
+ scale.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ scale.tickFormat = function(m, format) {
+ return d3_scale_linearTickFormat(domain, m, format);
+ };
+ scale.nice = function(m) {
+ return scale.domain(d3_scale_linearNice(domain, m));
+ };
+ scale.exponent = function(x) {
+ if (!arguments.length) return exponent;
+ powp = d3_scale_powPow(exponent = x);
+ powb = d3_scale_powPow(1 / exponent);
+ linear.domain(domain.map(powp));
+ return scale;
+ };
+ scale.copy = function() {
+ return d3_scale_pow(linear.copy(), exponent, domain);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ function d3_scale_powPow(e) {
+ return function(x) {
+ return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
+ };
+ }
+ d3.scale.sqrt = function() {
+ return d3.scale.pow().exponent(.5);
+ };
+ d3.scale.ordinal = function() {
+ return d3_scale_ordinal([], {
+ t: "range",
+ a: [ [] ]
+ });
+ };
+ function d3_scale_ordinal(domain, ranger) {
+ var index, range, rangeBand;
+ function scale(x) {
+ return range[((index.get(x) || ranger.t === "range" &&
index.set(x, domain.push(x))) - 1) % range.length];
+ }
+ function steps(start, step) {
+ return d3.range(domain.length).map(function(i) {
+ return start + step * i;
+ });
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = [];
+ index = new d3_Map();
+ var i = -1, n = x.length, xi;
+ while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
+ return scale[ranger.t].apply(scale, ranger.a);
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ rangeBand = 0;
+ ranger = {
+ t: "range",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangePoints = function(x, padding) {
+ if (arguments.length < 2) padding = 0;
+ var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length -
1) + padding);
+ range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding /
2, step);
+ rangeBand = 0;
+ ranger = {
+ t: "rangePoints",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeBands = function(x, padding, outerPadding) {
+ if (arguments.length < 2) padding = 0;
+ if (arguments.length < 3) outerPadding = padding;
+ var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step =
(stop - start) / (domain.length - padding + 2 * outerPadding);
+ range = steps(start + step * outerPadding, step);
+ if (reverse) range.reverse();
+ rangeBand = step * (1 - padding);
+ ranger = {
+ t: "rangeBands",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeRoundBands = function(x, padding, outerPadding) {
+ if (arguments.length < 2) padding = 0;
+ if (arguments.length < 3) outerPadding = padding;
+ var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step =
Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop -
start - (domain.length - padding) * step;
+ range = steps(start + Math.round(error / 2), step);
+ if (reverse) range.reverse();
+ rangeBand = Math.round(step * (1 - padding));
+ ranger = {
+ t: "rangeRoundBands",
+ a: arguments
+ };
+ return scale;
+ };
+ scale.rangeBand = function() {
+ return rangeBand;
+ };
+ scale.rangeExtent = function() {
+ return d3_scaleExtent(ranger.a[0]);
+ };
+ scale.copy = function() {
+ return d3_scale_ordinal(domain, ranger);
+ };
+ return scale.domain(domain);
+ }
+ d3.scale.category10 = function() {
+ return d3.scale.ordinal().range(d3_category10);
+ };
+ d3.scale.category20 = function() {
+ return d3.scale.ordinal().range(d3_category20);
+ };
+ d3.scale.category20b = function() {
+ return d3.scale.ordinal().range(d3_category20b);
+ };
+ d3.scale.category20c = function() {
+ return d3.scale.ordinal().range(d3_category20c);
+ };
+ var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330,
8355711, 12369186, 1556175 ].map(d3_rgbString);
+ var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698,
14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711,
13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString);
+ var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115,
13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372,
8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString);
+ var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764,
16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372,
14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString);
+ d3.scale.quantile = function() {
+ return d3_scale_quantile([], []);
+ };
+ function d3_scale_quantile(domain, range) {
+ var thresholds;
+ function rescale() {
+ var k = 0, q = range.length;
+ thresholds = [];
+ while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
+ return scale;
+ }
+ function scale(x) {
+ if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)];
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.filter(function(d) {
+ return !isNaN(d);
+ }).sort(d3.ascending);
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.quantiles = function() {
+ return thresholds;
+ };
+ scale.invertExtent = function(y) {
+ y = range.indexOf(y);
+ return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y <
thresholds.length ? thresholds[y] : domain[domain.length - 1] ];
+ };
+ scale.copy = function() {
+ return d3_scale_quantile(domain, range);
+ };
+ return rescale();
+ }
+ d3.scale.quantize = function() {
+ return d3_scale_quantize(0, 1, [ 0, 1 ]);
+ };
+ function d3_scale_quantize(x0, x1, range) {
+ var kx, i;
+ function scale(x) {
+ return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
+ }
+ function rescale() {
+ kx = range.length / (x1 - x0);
+ i = range.length - 1;
+ return scale;
+ }
+ scale.domain = function(x) {
+ if (!arguments.length) return [ x0, x1 ];
+ x0 = +x[0];
+ x1 = +x[x.length - 1];
+ return rescale();
+ };
+ scale.range = function(x) {
+ if (!arguments.length) return range;
+ range = x;
+ return rescale();
+ };
+ scale.invertExtent = function(y) {
+ y = range.indexOf(y);
+ y = y < 0 ? NaN : y / kx + x0;
+ return [ y, y + 1 / kx ];
+ };
+ scale.copy = function() {
+ return d3_scale_quantize(x0, x1, range);
+ };
+ return rescale();
+ }
+ d3.scale.threshold = function() {
+ return d3_scale_threshold([ .5 ], [ 0, 1 ]);
+ };
+ function d3_scale_threshold(domain, range) {
+ function scale(x) {
+ if (x <= x) return range[d3.bisect(domain, x)];
+ }
+ scale.domain = function(_) {
+ if (!arguments.length) return domain;
+ domain = _;
+ return scale;
+ };
+ scale.range = function(_) {
+ if (!arguments.length) return range;
+ range = _;
+ return scale;
+ };
+ scale.invertExtent = function(y) {
+ y = range.indexOf(y);
+ return [ domain[y - 1], domain[y] ];
+ };
+ scale.copy = function() {
+ return d3_scale_threshold(domain, range);
+ };
+ return scale;
+ }
+ d3.scale.identity = function() {
+ return d3_scale_identity([ 0, 1 ]);
+ };
+ function d3_scale_identity(domain) {
+ function identity(x) {
+ return +x;
+ }
+ identity.invert = identity;
+ identity.domain = identity.range = function(x) {
+ if (!arguments.length) return domain;
+ domain = x.map(identity);
+ return identity;
+ };
+ identity.ticks = function(m) {
+ return d3_scale_linearTicks(domain, m);
+ };
+ identity.tickFormat = function(m, format) {
+ return d3_scale_linearTickFormat(domain, m, format);
+ };
+ identity.copy = function() {
+ return d3_scale_identity(domain);
+ };
+ return identity;
+ }
+ d3.svg = {};
+ d3.svg.arc = function() {
+ var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius,
startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+ function arc() {
+ var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this,
arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 =
endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0,
+ a0 = a1, a1 = da), a1 - a0), df = da < Ï ? "0" : "1", c0 =
Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1);
+ return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 +
"," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1
+ " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," +
r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0
0," + r0 + "Z" : "M0," + r1 + "A" + r1 + ","
+ r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0
1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0
+ "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 *
c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 +
"A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0
+ "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 *
s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1
* c1 + "," + r1 * s1 + "L0,0" + "Z";
+ }
+ arc.innerRadius = function(v) {
+ if (!arguments.length) return innerRadius;
+ innerRadius = d3_functor(v);
+ return arc;
+ };
+ arc.outerRadius = function(v) {
+ if (!arguments.length) return outerRadius;
+ outerRadius = d3_functor(v);
+ return arc;
+ };
+ arc.startAngle = function(v) {
+ if (!arguments.length) return startAngle;
+ startAngle = d3_functor(v);
+ return arc;
+ };
+ arc.endAngle = function(v) {
+ if (!arguments.length) return endAngle;
+ endAngle = d3_functor(v);
+ return arc;
+ };
+ arc.centroid = function() {
+ var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) /
2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 +
d3_svg_arcOffset;
+ return [ Math.cos(a) * r, Math.sin(a) * r ];
+ };
+ return arc;
+ };
+ var d3_svg_arcOffset = -halfÏ, d3_svg_arcMax = Ï - ε;
+ function d3_svg_arcInnerRadius(d) {
+ return d.innerRadius;
+ }
+ function d3_svg_arcOuterRadius(d) {
+ return d.outerRadius;
+ }
+ function d3_svg_arcStartAngle(d) {
+ return d.startAngle;
+ }
+ function d3_svg_arcEndAngle(d) {
+ return d.endAngle;
+ }
+ function d3_svg_line(projection) {
+ var x = d3_geom_pointX, y = d3_geom_pointY, defined = d3_true, interpolate =
d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
+ function line(data) {
+ var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy
= d3_functor(y);
+ function segment() {
+ segments.push("M", interpolate(projection(points), tension));
+ }
+ while (++i < n) {
+ if (defined.call(this, d = data[i], i)) {
+ points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
+ } else if (points.length) {
+ segment();
+ points = [];
+ }
+ }
+ if (points.length) segment();
+ return segments.length ? segments.join("") : null;
+ }
+ line.x = function(_) {
+ if (!arguments.length) return x;
+ x = _;
+ return line;
+ };
+ line.y = function(_) {
+ if (!arguments.length) return y;
+ y = _;
+ return line;
+ };
+ line.defined = function(_) {
+ if (!arguments.length) return defined;
+ defined = _;
+ return line;
+ };
+ line.interpolate = function(_) {
+ if (!arguments.length) return interpolateKey;
+ if (typeof _ === "function") interpolateKey = interpolate = _; else
interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) ||
d3_svg_lineLinear).key;
+ return line;
+ };
+ line.tension = function(_) {
+ if (!arguments.length) return tension;
+ tension = _;
+ return line;
+ };
+ return line;
+ }
+ d3.svg.line = function() {
+ return d3_svg_line(d3_identity);
+ };
+ var d3_svg_lineInterpolators = d3.map({
+ linear: d3_svg_lineLinear,
+ "linear-closed": d3_svg_lineLinearClosed,
+ step: d3_svg_lineStep,
+ "step-before": d3_svg_lineStepBefore,
+ "step-after": d3_svg_lineStepAfter,
+ basis: d3_svg_lineBasis,
+ "basis-open": d3_svg_lineBasisOpen,
+ "basis-closed": d3_svg_lineBasisClosed,
+ bundle: d3_svg_lineBundle,
+ cardinal: d3_svg_lineCardinal,
+ "cardinal-open": d3_svg_lineCardinalOpen,
+ "cardinal-closed": d3_svg_lineCardinalClosed,
+ monotone: d3_svg_lineMonotone
+ });
+ d3_svg_lineInterpolators.forEach(function(key, value) {
+ value.key = key;
+ value.closed = /-closed$/.test(key);
+ });
+ function d3_svg_lineLinear(points) {
+ return points.join("L");
+ }
+ function d3_svg_lineLinearClosed(points) {
+ return d3_svg_lineLinear(points) + "Z";
+ }
+ function d3_svg_lineStep(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2,
"V", p[1]);
+ if (n > 1) path.push("H", p[0]);
+ return path.join("");
+ }
+ function d3_svg_lineStepBefore(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("V", (p = points[i])[1], "H",
p[0]);
+ return path.join("");
+ }
+ function d3_svg_lineStepAfter(points) {
+ var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
+ while (++i < n) path.push("H", (p = points[i])[0], "V",
p[1]);
+ return path.join("");
+ }
+ function d3_svg_lineCardinalOpen(points, tension) {
+ return points.length < 4 ? d3_svg_lineLinear(points) : points[1] +
d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points,
tension));
+ }
+ function d3_svg_lineCardinalClosed(points, tension) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] +
d3_svg_lineHermite((points.push(points[0]),
+ points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [
points[1] ]), tension));
+ }
+ function d3_svg_lineCardinal(points, tension) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] +
d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
+ }
+ function d3_svg_lineHermite(points, tangents) {
+ if (tangents.length < 1 || points.length != tangents.length &&
points.length != tangents.length + 2) {
+ return d3_svg_lineLinear(points);
+ }
+ var quad = points.length != tangents.length, path = "", p0 = points[0], p =
points[1], t0 = tangents[0], t = t0, pi = 1;
+ if (quad) {
+ path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2
/ 3) + "," + p[0] + "," + p[1];
+ p0 = points[1];
+ pi = 2;
+ }
+ if (tangents.length > 1) {
+ t = tangents[1];
+ p = points[pi];
+ pi++;
+ path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) +
"," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] +
"," + p[1];
+ for (var i = 2; i < tangents.length; i++, pi++) {
+ p = points[pi];
+ t = tangents[i];
+ path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) +
"," + p[0] + "," + p[1];
+ }
+ }
+ if (quad) {
+ var lp = points[pi];
+ path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 /
3) + "," + lp[0] + "," + lp[1];
+ }
+ return path;
+ }
+ function d3_svg_lineCardinalTangents(points, tension) {
+ var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1,
n = points.length;
+ while (++i < n) {
+ p0 = p1;
+ p1 = p2;
+ p2 = points[i];
+ tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
+ }
+ return tangents;
+ }
+ function d3_svg_lineBasis(points) {
+ if (points.length < 3) return d3_svg_lineLinear(points);
+ var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0,
x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0,
"L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
+ points.push(points[n - 1]);
+ while (++i <= n) {
+ pi = points[i];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ points.pop();
+ path.push("L", pi);
+ return path.join("");
+ }
+ function d3_svg_lineBasisOpen(points) {
+ if (points.length < 4) return d3_svg_lineLinear(points);
+ var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
+ while (++i < 3) {
+ pi = points[i];
+ px.push(pi[0]);
+ py.push(pi[1]);
+ }
+ path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," +
d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
+ --i;
+ while (++i < n) {
+ pi = points[i];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBasisClosed(points) {
+ var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
+ while (++i < 4) {
+ pi = points[i % n];
+ px.push(pi[0]);
+ py.push(pi[1]);
+ }
+ path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
+ --i;
+ while (++i < m) {
+ pi = points[i % n];
+ px.shift();
+ px.push(pi[0]);
+ py.shift();
+ py.push(pi[1]);
+ d3_svg_lineBasisBezier(path, px, py);
+ }
+ return path.join("");
+ }
+ function d3_svg_lineBundle(points, tension) {
+ var n = points.length - 1;
+ if (n) {
+ var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1]
- y0, i = -1, p, t;
+ while (++i <= n) {
+ p = points[i];
+ t = i / n;
+ p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
+ p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
+ }
+ }
+ return d3_svg_lineBasis(points);
+ }
+ function d3_svg_lineDot4(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+ }
+ var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1
/ 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];
+ function d3_svg_lineBasisBezier(path, x, y) {
+ path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
+ }
+ function d3_svg_lineSlope(p0, p1) {
+ return (p1[1] - p0[1]) / (p1[0] - p0[0]);
+ }
+ function d3_svg_lineFiniteDifferences(points) {
+ var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] =
d3_svg_lineSlope(p0, p1);
+ while (++i < j) {
+ m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
+ }
+ m[i] = d;
+ return m;
+ }
+ function d3_svg_lineMonotoneTangents(points) {
+ var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j =
points.length - 1;
+ while (++i < j) {
+ d = d3_svg_lineSlope(points[i], points[i + 1]);
+ if (abs(d) < ε) {
+ m[i] = m[i + 1] = 0;
+ } else {
+ a = m[i] / d;
+ b = m[i + 1] / d;
+ s = a * a + b * b;
+ if (s > 9) {
+ s = d * 3 / Math.sqrt(s);
+ m[i] = s * a;
+ m[i + 1] = s * b;
+ }
+ }
+ }
+ i = -1;
+ while (++i <= j) {
+ s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 +
m[i] * m[i]));
+ tangents.push([ s || 0, m[i] * s || 0 ]);
+ }
+ return tangents;
+ }
+ function d3_svg_lineMonotone(points) {
+ return points.length < 3 ? d3_svg_lineLinear(points) : points[0] +
d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
+ }
+ d3.svg.line.radial = function() {
+ var line = d3_svg_line(d3_svg_lineRadial);
+ line.radius = line.x, delete line.x;
+ line.angle = line.y, delete line.y;
+ return line;
+ };
+ function d3_svg_lineRadial(points) {
+ var point, i = -1, n = points.length, r, a;
+ while (++i < n) {
+ point = points[i];
+ r = point[0];
+ a = point[1] + d3_svg_arcOffset;
+ point[0] = r * Math.cos(a);
+ point[1] = r * Math.sin(a);
+ }
+ return points;
+ }
+ function d3_svg_area(projection) {
+ var x0 = d3_geom_pointX, x1 = d3_geom_pointX, y0 = 0, y1 = d3_geom_pointY, defined =
d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key,
interpolateReverse = interpolate, L = "L", tension = .7;
+ function area(data) {
+ var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 =
d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
+ return x;
+ } : d3_functor(x1), fy1 = y0 === y1 ? function() {
+ return y;
+ } : d3_functor(y1), x, y;
+ function segment() {
+ segments.push("M", interpolate(projection(points1), tension), L,
interpolateReverse(projection(points0.reverse()), tension), "Z");
+ }
+ while (++i < n) {
+ if (defined.call(this, d = data[i], i)) {
+ points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);
+ points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);
+ } else if (points0.length) {
+ segment();
+ points0 = [];
+ points1 = [];
+ }
+ }
+ if (points0.length) segment();
+ return segments.length ? segments.join("") : null;
+ }
+ area.x = function(_) {
+ if (!arguments.length) return x1;
+ x0 = x1 = _;
+ return area;
+ };
+ area.x0 = function(_) {
+ if (!arguments.length) return x0;
+ x0 = _;
+ return area;
+ };
+ area.x1 = function(_) {
+ if (!arguments.length) return x1;
+ x1 = _;
+ return area;
+ };
+ area.y = function(_) {
+ if (!arguments.length) return y1;
+ y0 = y1 = _;
+ return area;
+ };
+ area.y0 = function(_) {
+ if (!arguments.length) return y0;
+ y0 = _;
+ return area;
+ };
+ area.y1 = function(_) {
+ if (!arguments.length) return y1;
+ y1 = _;
+ return area;
+ };
+ area.defined = function(_) {
+ if (!arguments.length) return defined;
+ defined = _;
+ return area;
+ };
+ area.interpolate = function(_) {
+ if (!arguments.length) return interpolateKey;
+ if (typeof _ === "function") interpolateKey = interpolate = _; else
interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) ||
d3_svg_lineLinear).key;
+ interpolateReverse = interpolate.reverse || interpolate;
+ L = interpolate.closed ? "M" : "L";
+ return area;
+ };
+ area.tension = function(_) {
+ if (!arguments.length) return tension;
+ tension = _;
+ return area;
+ };
+ return area;
+ }
+ d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
+ d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
+ d3.svg.area = function() {
+ return d3_svg_area(d3_identity);
+ };
+ d3.svg.area.radial = function() {
+ var area = d3_svg_area(d3_svg_lineRadial);
+ area.radius = area.x, delete area.x;
+ area.innerRadius = area.x0, delete area.x0;
+ area.outerRadius = area.x1, delete area.x1;
+ area.angle = area.y, delete area.y;
+ area.startAngle = area.y0, delete area.y0;
+ area.endAngle = area.y1, delete area.y1;
+ return area;
+ };
+ d3.svg.chord = function() {
+ var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle =
d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
+ function chord(d, i) {
+ var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);
+ return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ?
curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) +
curve(t.r, t.p1, s.r, s.p0)) + "Z";
+ }
+ function subgroup(self, f, d, i) {
+ var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 =
startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup,
i) + d3_svg_arcOffset;
+ return {
+ r: r,
+ a0: a0,
+ a1: a1,
+ p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
+ p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
+ };
+ }
+ function equals(a, b) {
+ return a.a0 == b.a0 && a.a1 == b.a1;
+ }
+ function arc(r, p, a) {
+ return "A" + r + "," + r + " 0 " + +(a > Ï) +
",1 " + p;
+ }
+ function curve(r0, p0, r1, p1) {
+ return "Q 0,0 " + p1;
+ }
+ chord.radius = function(v) {
+ if (!arguments.length) return radius;
+ radius = d3_functor(v);
+ return chord;
+ };
+ chord.source = function(v) {
+ if (!arguments.length) return source;
+ source = d3_functor(v);
+ return chord;
+ };
+ chord.target = function(v) {
+ if (!arguments.length) return target;
+ target = d3_functor(v);
+ return chord;
+ };
+ chord.startAngle = function(v) {
+ if (!arguments.length) return startAngle;
+ startAngle = d3_functor(v);
+ return chord;
+ };
+ chord.endAngle = function(v) {
+ if (!arguments.length) return endAngle;
+ endAngle = d3_functor(v);
+ return chord;
+ };
+ return chord;
+ };
+ function d3_svg_chordRadius(d) {
+ return d.radius;
+ }
+ d3.svg.diagonal = function() {
+ var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;
+ function diagonal(d, i) {
+ var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) /
2, p = [ p0, {
+ x: p0.x,
+ y: m
+ }, {
+ x: p3.x,
+ y: m
+ }, p3 ];
+ p = p.map(projection);
+ return "M" + p[0] + "C" + p[1] + " " + p[2] + "
" + p[3];
+ }
+ diagonal.source = function(x) {
+ if (!arguments.length) return source;
+ source = d3_functor(x);
+ return diagonal;
+ };
+ diagonal.target = function(x) {
+ if (!arguments.length) return target;
+ target = d3_functor(x);
+ return diagonal;
+ };
+ diagonal.projection = function(x) {
+ if (!arguments.length) return projection;
+ projection = x;
+ return diagonal;
+ };
+ return diagonal;
+ };
+ function d3_svg_diagonalProjection(d) {
+ return [ d.x, d.y ];
+ }
+ d3.svg.diagonal.radial = function() {
+ var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_
= diagonal.projection;
+ diagonal.projection = function(x) {
+ return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection =
x)) : projection;
+ };
+ return diagonal;
+ };
+ function d3_svg_diagonalRadialProjection(projection) {
+ return function() {
+ var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset;
+ return [ r * Math.cos(a), r * Math.sin(a) ];
+ };
+ }
+ d3.svg.symbol = function() {
+ var type = d3_svg_symbolType, size = d3_svg_symbolSize;
+ function symbol(d, i) {
+ return (d3_svg_symbols.get(type.call(this, d, i)) ||
d3_svg_symbolCircle)(size.call(this, d, i));
+ }
+ symbol.type = function(x) {
+ if (!arguments.length) return type;
+ type = d3_functor(x);
+ return symbol;
+ };
+ symbol.size = function(x) {
+ if (!arguments.length) return size;
+ size = d3_functor(x);
+ return symbol;
+ };
+ return symbol;
+ };
+ function d3_svg_symbolSize() {
+ return 64;
+ }
+ function d3_svg_symbolType() {
+ return "circle";
+ }
+ function d3_svg_symbolCircle(size) {
+ var r = Math.sqrt(size / Ï);
+ return "M0," + r + "A" + r + "," + r + " 0 1,1
0," + -r + "A" + r + "," + r + " 0 1,1 0," + r +
"Z";
+ }
+ var d3_svg_symbols = d3.map({
+ circle: d3_svg_symbolCircle,
+ cross: function(size) {
+ var r = Math.sqrt(size / 5) / 2;
+ return "M" + -3 * r + "," + -r + "H" + -r +
"V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r +
"V" + r + "H" + r + "V" + 3 * r + "H" + -r +
"V" + r + "H" + -3 * r + "Z";
+ },
+ diamond: function(size) {
+ var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;
+ return "M0," + -ry + "L" + rx + ",0" + "
0," + ry + " " + -rx + ",0" + "Z";
+ },
+ square: function(size) {
+ var r = Math.sqrt(size) / 2;
+ return "M" + -r + "," + -r + "L" + r + ","
+ -r + " " + r + "," + r + " " + -r + "," + r +
"Z";
+ },
+ "triangle-down": function(size) {
+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+ return "M0," + ry + "L" + rx + "," + -ry + "
" + -rx + "," + -ry + "Z";
+ },
+ "triangle-up": function(size) {
+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
+ return "M0," + -ry + "L" + rx + "," + ry + "
" + -rx + "," + ry + "Z";
+ }
+ });
+ d3.svg.symbolTypes = d3_svg_symbols.keys();
+ var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);
+ function d3_transition(groups, id) {
+ d3_subclass(groups, d3_transitionPrototype);
+ groups.id = id;
+ return groups;
+ }
+ var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId,
d3_transitionInherit;
+ d3_transitionPrototype.call = d3_selectionPrototype.call;
+ d3_transitionPrototype.empty = d3_selectionPrototype.empty;
+ d3_transitionPrototype.node = d3_selectionPrototype.node;
+ d3_transitionPrototype.size = d3_selectionPrototype.size;
+ d3.transition = function(selection) {
+ return arguments.length ? d3_transitionInheritId ? selection.transition() : selection
: d3_selectionRoot.transition();
+ };
+ d3.transition.prototype = d3_transitionPrototype;
+ d3_transitionPrototype.select = function(selector) {
+ var id = this.id, subgroups = [], subgroup, subnode, node;
+ selector = d3_selection_selector(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i,
j))) {
+ if ("__data__" in node) subnode.__data__ = node.__data__;
+ d3_transitionNode(subnode, i, id, node.__transition__[id]);
+ subgroup.push(subnode);
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_transitionPrototype.selectAll = function(selector) {
+ var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition;
+ selector = d3_selection_selectorAll(selector);
+ for (var j = -1, m = this.length; ++j < m; ) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
+ if (node = group[i]) {
+ transition = node.__transition__[id];
+ subnodes = selector.call(node, node.__data__, i, j);
+ subgroups.push(subgroup = []);
+ for (var k = -1, o = subnodes.length; ++k < o; ) {
+ if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition);
+ subgroup.push(subnode);
+ }
+ }
+ }
+ }
+ return d3_transition(subgroups, id);
+ };
+ d3_transitionPrototype.filter = function(filter) {
+ var subgroups = [], subgroup, group, node;
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
+ subgroup.push(node);
+ }
+ }
+ }
+ return d3_transition(subgroups, this.id);
+ };
+ d3_transitionPrototype.tween = function(name, tween) {
+ var id = this.id;
+ if (arguments.length < 2) return this.node().__transition__[id].tween.get(name);
+ return d3_selection_each(this, tween == null ? function(node) {
+ node.__transition__[id].tween.remove(name);
+ } : function(node) {
+ node.__transition__[id].tween.set(name, tween);
+ });
+ };
+ function d3_transition_tween(groups, name, value, tween) {
+ var id = groups.id;
+ return d3_selection_each(groups, typeof value === "function" ?
function(node, i, j) {
+ node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i,
j)));
+ } : (value = tween(value), function(node) {
+ node.__transition__[id].tween.set(name, value);
+ }));
+ }
+ d3_transitionPrototype.attr = function(nameNS, value) {
+ if (arguments.length < 2) {
+ for (value in nameNS) this.attr(value, nameNS[value]);
+ return this;
+ }
+ var interpolate = nameNS == "transform" ? d3_interpolateTransform :
d3_interpolate, name = d3.ns.qualify(nameNS);
+ function attrNull() {
+ this.removeAttribute(name);
+ }
+ function attrNullNS() {
+ this.removeAttributeNS(name.space, name.local);
+ }
+ function attrTween(b) {
+ return b == null ? attrNull : (b += "", function() {
+ var a = this.getAttribute(name), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.setAttribute(name, i(t));
+ });
+ });
+ }
+ function attrTweenNS(b) {
+ return b == null ? attrNullNS : (b += "", function() {
+ var a = this.getAttributeNS(name.space, name.local), i;
+ return a !== b && (i = interpolate(a, b), function(t) {
+ this.setAttributeNS(name.space, name.local, i(t));
+ });
+ });
+ }
+ return d3_transition_tween(this, "attr." + nameNS, value, name.local ?
attrTweenNS : attrTween);
+ };
+ d3_transitionPrototype.attrTween = function(nameNS, tween) {
+ var name = d3.ns.qualify(nameNS);
+ function attrTween(d, i) {
+ var f = tween.call(this, d, i, this.getAttribute(name));
+ return f && function(t) {
+ this.setAttribute(name, f(t));
+ };
+ }
+ function attrTweenNS(d, i) {
+ var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
+ return f && function(t) {
+ this.setAttributeNS(name.space, name.local, f(t));
+ };
+ }
+ return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
+ };
+ d3_transitionPrototype.style = function(name, value, priority) {
+ var n = arguments.length;
+ if (n < 3) {
+ if (typeof name !== "string") {
+ if (n < 2) value = "";
+ for (priority in name) this.style(priority, name[priority], value);
+ return this;
+ }
+ priority = "";
+ }
+ function styleNull() {
+ this.style.removeProperty(name);
+ }
+ function styleString(b) {
+ return b == null ? styleNull : (b += "", function() {
+ var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i;
+ return a !== b && (i = d3_interpolate(a, b), function(t) {
+ this.style.setProperty(name, i(t), priority);
+ });
+ });
+ }
+ return d3_transition_tween(this, "style." + name, value, styleString);
+ };
+ d3_transitionPrototype.styleTween = function(name, tween, priority) {
+ if (arguments.length < 3) priority = "";
+ function styleTween(d, i) {
+ var f = tween.call(this, d, i, d3_window.getComputedStyle(this,
null).getPropertyValue(name));
+ return f && function(t) {
+ this.style.setProperty(name, f(t), priority);
+ };
+ }
+ return this.tween("style." + name, styleTween);
+ };
+ d3_transitionPrototype.text = function(value) {
+ return d3_transition_tween(this, "text", value, d3_transition_text);
+ };
+ function d3_transition_text(b) {
+ if (b == null) b = "";
+ return function() {
+ this.textContent = b;
+ };
+ }
+ d3_transitionPrototype.remove = function() {
+ return this.each("end.transition", function() {
+ var p;
+ if (this.__transition__.count < 2 && (p = this.parentNode))
p.removeChild(this);
+ });
+ };
+ d3_transitionPrototype.ease = function(value) {
+ var id = this.id;
+ if (arguments.length < 1) return this.node().__transition__[id].ease;
+ if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
+ return d3_selection_each(this, function(node) {
+ node.__transition__[id].ease = value;
+ });
+ };
+ d3_transitionPrototype.delay = function(value) {
+ var id = this.id;
+ return d3_selection_each(this, typeof value === "function" ? function(node,
i, j) {
+ node.__transition__[id].delay = +value.call(node, node.__data__, i, j);
+ } : (value = +value, function(node) {
+ node.__transition__[id].delay = value;
+ }));
+ };
+ d3_transitionPrototype.duration = function(value) {
+ var id = this.id;
+ return d3_selection_each(this, typeof value === "function" ? function(node,
i, j) {
+ node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i,
j));
+ } : (value = Math.max(1, value), function(node) {
+ node.__transition__[id].duration = value;
+ }));
+ };
+ d3_transitionPrototype.each = function(type, listener) {
+ var id = this.id;
+ if (arguments.length < 2) {
+ var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
+ d3_transitionInheritId = id;
+ d3_selection_each(this, function(node, i, j) {
+ d3_transitionInherit = node.__transition__[id];
+ type.call(node, node.__data__, i, j);
+ });
+ d3_transitionInherit = inherit;
+ d3_transitionInheritId = inheritId;
+ } else {
+ d3_selection_each(this, function(node) {
+ var transition = node.__transition__[id];
+ (transition.event || (transition.event = d3.dispatch("start",
"end"))).on(type, listener);
+ });
+ }
+ return this;
+ };
+ d3_transitionPrototype.transition = function() {
+ var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node,
transition;
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ if (node = group[i]) {
+ transition = Object.create(node.__transition__[id0]);
+ transition.delay += transition.duration;
+ d3_transitionNode(node, i, id1, transition);
+ }
+ subgroup.push(node);
+ }
+ }
+ return d3_transition(subgroups, id1);
+ };
+ function d3_transitionNode(node, i, id, inherit) {
+ var lock = node.__transition__ || (node.__transition__ = {
+ active: 0,
+ count: 0
+ }), transition = lock[id];
+ if (!transition) {
+ var time = inherit.time;
+ transition = lock[id] = {
+ tween: new d3_Map(),
+ time: time,
+ ease: inherit.ease,
+ delay: inherit.delay,
+ duration: inherit.duration
+ };
+ ++lock.count;
+ d3.timer(function(elapsed) {
+ var d = node.__data__, ease = transition.ease, delay = transition.delay, duration
= transition.duration, timer = d3_timer_active, tweened = [];
+ timer.t = delay + time;
+ if (delay <= elapsed) return start(elapsed - delay);
+ timer.c = start;
+ function start(elapsed) {
+ if (lock.active > id) return stop();
+ lock.active = id;
+ transition.event && transition.event.start.call(node, d, i);
+ transition.tween.forEach(function(key, value) {
+ if (value = value.call(node, d, i)) {
+ tweened.push(value);
+ }
+ });
+ d3.timer(function() {
+ timer.c = tick(elapsed || 1) ? d3_true : tick;
+ return 1;
+ }, 0, time);
+ }
+ function tick(elapsed) {
+ if (lock.active !== id) return stop();
+ var t = elapsed / duration, e = ease(t), n = tweened.length;
+ while (n > 0) {
+ tweened[--n].call(node, e);
+ }
+ if (t >= 1) {
+ transition.event && transition.event.end.call(node, d, i);
+ return stop();
+ }
+ }
+ function stop() {
+ if (--lock.count) delete lock[id]; else delete node.__transition__;
+ return 1;
+ }
+ }, 0, time);
+ }
+ }
+ d3.svg.axis = function() {
+ var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6,
outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null,
tickFormat_;
+ function axis(g) {
+ g.each(function() {
+ var g = d3.select(this);
+ var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy();
+ var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1,
tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ?
scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity :
tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter =
tick.enter().insert("g", ".domain").attr("class",
"tick").style("opacity", ε), tickExit =
d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate =
d3.transition(tick).style("opacity", 1), tickTransform;
+ var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([
0 ]), pathUpdate = (path.enter().append("path").attr("class",
"domain"),
+ d3.transition(path));
+ tickEnter.append("line");
+ tickEnter.append("text");
+ var lineEnter = tickEnter.select("line"), lineUpdate =
tickUpdate.select("line"), text =
tick.select("text").text(tickFormat), textEnter =
tickEnter.select("text"), textUpdate = tickUpdate.select("text");
+ switch (orient) {
+ case "bottom":
+ {
+ tickTransform = d3_svg_axisX;
+ lineEnter.attr("y2", innerTickSize);
+ textEnter.attr("y", Math.max(innerTickSize, 0) + tickPadding);
+ lineUpdate.attr("x2", 0).attr("y2", innerTickSize);
+ textUpdate.attr("x", 0).attr("y", Math.max(innerTickSize,
0) + tickPadding);
+ text.attr("dy", ".71em").style("text-anchor",
"middle");
+ pathUpdate.attr("d", "M" + range[0] + "," +
outerTickSize + "V0H" + range[1] + "V" + outerTickSize);
+ break;
+ }
+
+ case "top":
+ {
+ tickTransform = d3_svg_axisX;
+ lineEnter.attr("y2", -innerTickSize);
+ textEnter.attr("y", -(Math.max(innerTickSize, 0) + tickPadding));
+ lineUpdate.attr("x2", 0).attr("y2", -innerTickSize);
+ textUpdate.attr("x", 0).attr("y",
-(Math.max(innerTickSize, 0) + tickPadding));
+ text.attr("dy", "0em").style("text-anchor",
"middle");
+ pathUpdate.attr("d", "M" + range[0] + "," +
-outerTickSize + "V0H" + range[1] + "V" + -outerTickSize);
+ break;
+ }
+
+ case "left":
+ {
+ tickTransform = d3_svg_axisY;
+ lineEnter.attr("x2", -innerTickSize);
+ textEnter.attr("x", -(Math.max(innerTickSize, 0) + tickPadding));
+ lineUpdate.attr("x2", -innerTickSize).attr("y2", 0);
+ textUpdate.attr("x", -(Math.max(innerTickSize, 0) +
tickPadding)).attr("y", 0);
+ text.attr("dy", ".32em").style("text-anchor",
"end");
+ pathUpdate.attr("d", "M" + -outerTickSize + ","
+ range[0] + "H0V" + range[1] + "H" + -outerTickSize);
+ break;
+ }
+
+ case "right":
+ {
+ tickTransform = d3_svg_axisY;
+ lineEnter.attr("x2", innerTickSize);
+ textEnter.attr("x", Math.max(innerTickSize, 0) + tickPadding);
+ lineUpdate.attr("x2", innerTickSize).attr("y2", 0);
+ textUpdate.attr("x", Math.max(innerTickSize, 0) +
tickPadding).attr("y", 0);
+ text.attr("dy", ".32em").style("text-anchor",
"start");
+ pathUpdate.attr("d", "M" + outerTickSize + ","
+ range[0] + "H0V" + range[1] + "H" + outerTickSize);
+ break;
+ }
+ }
+ if (scale1.rangeBand) {
+ var x = scale1, dx = x.rangeBand() / 2;
+ scale0 = scale1 = function(d) {
+ return x(d) + dx;
+ };
+ } else if (scale0.rangeBand) {
+ scale0 = scale1;
+ } else {
+ tickExit.call(tickTransform, scale1);
+ }
+ tickEnter.call(tickTransform, scale0);
+ tickUpdate.call(tickTransform, scale1);
+ });
+ }
+ axis.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = x;
+ return axis;
+ };
+ axis.orient = function(x) {
+ if (!arguments.length) return orient;
+ orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient;
+ return axis;
+ };
+ axis.ticks = function() {
+ if (!arguments.length) return tickArguments_;
+ tickArguments_ = arguments;
+ return axis;
+ };
+ axis.tickValues = function(x) {
+ if (!arguments.length) return tickValues;
+ tickValues = x;
+ return axis;
+ };
+ axis.tickFormat = function(x) {
+ if (!arguments.length) return tickFormat_;
+ tickFormat_ = x;
+ return axis;
+ };
+ axis.tickSize = function(x) {
+ var n = arguments.length;
+ if (!n) return innerTickSize;
+ innerTickSize = +x;
+ outerTickSize = +arguments[n - 1];
+ return axis;
+ };
+ axis.innerTickSize = function(x) {
+ if (!arguments.length) return innerTickSize;
+ innerTickSize = +x;
+ return axis;
+ };
+ axis.outerTickSize = function(x) {
+ if (!arguments.length) return outerTickSize;
+ outerTickSize = +x;
+ return axis;
+ };
+ axis.tickPadding = function(x) {
+ if (!arguments.length) return tickPadding;
+ tickPadding = +x;
+ return axis;
+ };
+ axis.tickSubdivide = function() {
+ return arguments.length && axis;
+ };
+ return axis;
+ };
+ var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = {
+ top: 1,
+ right: 1,
+ bottom: 1,
+ left: 1
+ };
+ function d3_svg_axisX(selection, x) {
+ selection.attr("transform", function(d) {
+ return "translate(" + x(d) + ",0)";
+ });
+ }
+ function d3_svg_axisY(selection, y) {
+ selection.attr("transform", function(d) {
+ return "translate(0," + y(d) + ")";
+ });
+ }
+ d3.svg.brush = function() {
+ var event = d3_eventDispatch(brush, "brushstart", "brush",
"brushend"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ],
xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes =
d3_svg_brushResizes[0];
+ function brush(g) {
+ g.each(function() {
+ var g = d3.select(this).style("pointer-events",
"all").style("-webkit-tap-highlight-color",
"rgba(0,0,0,0)").on("mousedown.brush",
brushstart).on("touchstart.brush", brushstart);
+ var background = g.selectAll(".background").data([ 0 ]);
+ background.enter().append("rect").attr("class",
"background").style("visibility",
"hidden").style("cursor", "crosshair");
+ g.selectAll(".extent").data([ 0
]).enter().append("rect").attr("class",
"extent").style("cursor", "move");
+ var resize = g.selectAll(".resize").data(resizes, d3_identity);
+ resize.exit().remove();
+ resize.enter().append("g").attr("class", function(d) {
+ return "resize " + d;
+ }).style("cursor", function(d) {
+ return d3_svg_brushCursor[d];
+ }).append("rect").attr("x", function(d) {
+ return /[ew]$/.test(d) ? -3 : null;
+ }).attr("y", function(d) {
+ return /^[ns]/.test(d) ? -3 : null;
+ }).attr("width", 6).attr("height",
6).style("visibility", "hidden");
+ resize.style("display", brush.empty() ? "none" : null);
+ var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background),
range;
+ if (x) {
+ range = d3_scaleRange(x);
+ backgroundUpdate.attr("x", range[0]).attr("width", range[1]
- range[0]);
+ redrawX(gUpdate);
+ }
+ if (y) {
+ range = d3_scaleRange(y);
+ backgroundUpdate.attr("y", range[0]).attr("height",
range[1] - range[0]);
+ redrawY(gUpdate);
+ }
+ redraw(gUpdate);
+ });
+ }
+ brush.event = function(g) {
+ g.each(function() {
+ var event_ = event.of(this, arguments), extent1 = {
+ x: xExtent,
+ y: yExtent,
+ i: xExtentDomain,
+ j: yExtentDomain
+ }, extent0 = this.__chart__ || extent1;
+ this.__chart__ = extent1;
+ if (d3_transitionInheritId) {
+ d3.select(this).transition().each("start.brush", function() {
+ xExtentDomain = extent0.i;
+ yExtentDomain = extent0.j;
+ xExtent = extent0.x;
+ yExtent = extent0.y;
+ event_({
+ type: "brushstart"
+ });
+ }).tween("brush:brush", function() {
+ var xi = d3_interpolateArray(xExtent, extent1.x), yi =
d3_interpolateArray(yExtent, extent1.y);
+ xExtentDomain = yExtentDomain = null;
+ return function(t) {
+ xExtent = extent1.x = xi(t);
+ yExtent = extent1.y = yi(t);
+ event_({
+ type: "brush",
+ mode: "resize"
+ });
+ };
+ }).each("end.brush", function() {
+ xExtentDomain = extent1.i;
+ yExtentDomain = extent1.j;
+ event_({
+ type: "brush",
+ mode: "resize"
+ });
+ event_({
+ type: "brushend"
+ });
+ });
+ } else {
+ event_({
+ type: "brushstart"
+ });
+ event_({
+ type: "brush",
+ mode: "resize"
+ });
+ event_({
+ type: "brushend"
+ });
+ }
+ });
+ };
+ function redraw(g) {
+ g.selectAll(".resize").attr("transform", function(d) {
+ return "translate(" + xExtent[+/e$/.test(d)] + "," +
yExtent[+/^s/.test(d)] + ")";
+ });
+ }
+ function redrawX(g) {
+ g.select(".extent").attr("x", xExtent[0]);
+ g.selectAll(".extent,.n>rect,.s>rect").attr("width",
xExtent[1] - xExtent[0]);
+ }
+ function redrawY(g) {
+ g.select(".extent").attr("y", yExtent[0]);
+ g.selectAll(".extent,.e>rect,.w>rect").attr("height",
yExtent[1] - yExtent[0]);
+ }
+ function brushstart() {
+ var target = this, eventTarget = d3.select(d3.event.target), event_ =
event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(),
resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing)
&& y, dragging = eventTarget.classed("extent"), dragRestore =
d3_event_dragSuppress(), center, origin = d3.mouse(target), offset;
+ var w = d3.select(d3_window).on("keydown.brush",
keydown).on("keyup.brush", keyup);
+ if (d3.event.changedTouches) {
+ w.on("touchmove.brush", brushmove).on("touchend.brush",
brushend);
+ } else {
+ w.on("mousemove.brush", brushmove).on("mouseup.brush",
brushend);
+ }
+ g.interrupt().selectAll("*").interrupt();
+ if (dragging) {
+ origin[0] = xExtent[0] - origin[0];
+ origin[1] = yExtent[0] - origin[1];
+ } else if (resizing) {
+ var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
+ offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ];
+ origin[0] = xExtent[ex];
+ origin[1] = yExtent[ey];
+ } else if (d3.event.altKey) center = origin.slice();
+ g.style("pointer-events",
"none").selectAll(".resize").style("display", null);
+ d3.select("body").style("cursor",
eventTarget.style("cursor"));
+ event_({
+ type: "brushstart"
+ });
+ brushmove();
+ function keydown() {
+ if (d3.event.keyCode == 32) {
+ if (!dragging) {
+ center = null;
+ origin[0] -= xExtent[1];
+ origin[1] -= yExtent[1];
+ dragging = 2;
+ }
+ d3_eventPreventDefault();
+ }
+ }
+ function keyup() {
+ if (d3.event.keyCode == 32 && dragging == 2) {
+ origin[0] += xExtent[1];
+ origin[1] += yExtent[1];
+ dragging = 0;
+ d3_eventPreventDefault();
+ }
+ }
+ function brushmove() {
+ var point = d3.mouse(target), moved = false;
+ if (offset) {
+ point[0] += offset[0];
+ point[1] += offset[1];
+ }
+ if (!dragging) {
+ if (d3.event.altKey) {
+ if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] +
yExtent[1]) / 2 ];
+ origin[0] = xExtent[+(point[0] < center[0])];
+ origin[1] = yExtent[+(point[1] < center[1])];
+ } else center = null;
+ }
+ if (resizingX && move1(point, x, 0)) {
+ redrawX(g);
+ moved = true;
+ }
+ if (resizingY && move1(point, y, 1)) {
+ redrawY(g);
+ moved = true;
+ }
+ if (moved) {
+ redraw(g);
+ event_({
+ type: "brush",
+ mode: dragging ? "move" : "resize"
+ });
+ }
+ }
+ function move1(point, scale, i) {
+ var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position =
origin[i], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max;
+ if (dragging) {
+ r0 -= position;
+ r1 -= size + position;
+ }
+ min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i];
+ if (dragging) {
+ max = (min += position) + size;
+ } else {
+ if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
+ if (position < min) {
+ max = min;
+ min = position;
+ } else {
+ max = position;
+ }
+ }
+ if (extent[0] != min || extent[1] != max) {
+ if (i) yExtentDomain = null; else xExtentDomain = null;
+ extent[0] = min;
+ extent[1] = max;
+ return true;
+ }
+ }
+ function brushend() {
+ brushmove();
+ g.style("pointer-events",
"all").selectAll(".resize").style("display", brush.empty() ?
"none" : null);
+ d3.select("body").style("cursor", null);
+ w.on("mousemove.brush", null).on("mouseup.brush",
null).on("touchmove.brush", null).on("touchend.brush",
null).on("keydown.brush", null).on("keyup.brush", null);
+ dragRestore();
+ event_({
+ type: "brushend"
+ });
+ }
+ }
+ brush.x = function(z) {
+ if (!arguments.length) return x;
+ x = z;
+ resizes = d3_svg_brushResizes[!x << 1 | !y];
+ return brush;
+ };
+ brush.y = function(z) {
+ if (!arguments.length) return y;
+ y = z;
+ resizes = d3_svg_brushResizes[!x << 1 | !y];
+ return brush;
+ };
+ brush.clamp = function(z) {
+ if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y
? yClamp : null;
+ if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z;
else if (y) yClamp = !!z;
+ return brush;
+ };
+ brush.extent = function(z) {
+ var x0, x1, y0, y1, t;
+ if (!arguments.length) {
+ if (x) {
+ if (xExtentDomain) {
+ x0 = xExtentDomain[0], x1 = xExtentDomain[1];
+ } else {
+ x0 = xExtent[0], x1 = xExtent[1];
+ if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ }
+ }
+ if (y) {
+ if (yExtentDomain) {
+ y0 = yExtentDomain[0], y1 = yExtentDomain[1];
+ } else {
+ y0 = yExtent[0], y1 = yExtent[1];
+ if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ }
+ }
+ return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y
&& [ y0, y1 ];
+ }
+ if (x) {
+ x0 = z[0], x1 = z[1];
+ if (y) x0 = x0[0], x1 = x1[0];
+ xExtentDomain = [ x0, x1 ];
+ if (x.invert) x0 = x(x0), x1 = x(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ];
+ }
+ if (y) {
+ y0 = z[0], y1 = z[1];
+ if (x) y0 = y0[1], y1 = y1[1];
+ yExtentDomain = [ y0, y1 ];
+ if (y.invert) y0 = y(y0), y1 = y(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ];
+ }
+ return brush;
+ };
+ brush.clear = function() {
+ if (!brush.empty()) {
+ xExtent = [ 0, 0 ], yExtent = [ 0, 0 ];
+ xExtentDomain = yExtentDomain = null;
+ }
+ return brush;
+ };
+ brush.empty = function() {
+ return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] ==
yExtent[1];
+ };
+ return d3.rebind(brush, event, "on");
+ };
+ var d3_svg_brushCursor = {
+ n: "ns-resize",
+ e: "ew-resize",
+ s: "ns-resize",
+ w: "ew-resize",
+ nw: "nwse-resize",
+ ne: "nesw-resize",
+ se: "nwse-resize",
+ sw: "nesw-resize"
+ };
+ var d3_svg_brushResizes = [ [ "n", "e", "s",
"w", "nw", "ne", "se", "sw" ], [
"e", "w" ], [ "n", "s" ], [] ];
+ var d3_time = d3.time = {}, d3_date = Date, d3_time_daySymbols = [ "Sunday",
"Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday" ];
+ function d3_date_utc() {
+ this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) :
arguments[0]);
+ }
+ d3_date_utc.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() {
+ d3_time_prototype.setUTCDate.apply(this._, arguments);
+ },
+ setDay: function() {
+ d3_time_prototype.setUTCDay.apply(this._, arguments);
+ },
+ setFullYear: function() {
+ d3_time_prototype.setUTCFullYear.apply(this._, arguments);
+ },
+ setHours: function() {
+ d3_time_prototype.setUTCHours.apply(this._, arguments);
+ },
+ setMilliseconds: function() {
+ d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
+ },
+ setMinutes: function() {
+ d3_time_prototype.setUTCMinutes.apply(this._, arguments);
+ },
+ setMonth: function() {
+ d3_time_prototype.setUTCMonth.apply(this._, arguments);
+ },
+ setSeconds: function() {
+ d3_time_prototype.setUTCSeconds.apply(this._, arguments);
+ },
+ setTime: function() {
+ d3_time_prototype.setTime.apply(this._, arguments);
+ }
+ };
+ var d3_time_prototype = Date.prototype;
+ var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate =
"%m/%d/%Y", d3_time_formatTime = "%H:%M:%S";
+ var d3_time_days = [ "Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday", "Saturday" ],
d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue",
"Wed", "Thu", "Fri", "Sat" ], d3_time_months = [
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December" ],
d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar",
"Apr", "May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec" ];
+ function d3_time_interval(local, step, number) {
+ function round(date) {
+ var d0 = local(date), d1 = offset(d0, 1);
+ return date - d0 < d1 - date ? d0 : d1;
+ }
+ function ceil(date) {
+ step(date = local(new d3_date(date - 1)), 1);
+ return date;
+ }
+ function offset(date, k) {
+ step(date = new d3_date(+date), k);
+ return date;
+ }
+ function range(t0, t1, dt) {
+ var time = ceil(t0), times = [];
+ if (dt > 1) {
+ while (time < t1) {
+ if (!(number(time) % dt)) times.push(new Date(+time));
+ step(time, 1);
+ }
+ } else {
+ while (time < t1) times.push(new Date(+time)), step(time, 1);
+ }
+ return times;
+ }
+ function range_utc(t0, t1, dt) {
+ try {
+ d3_date = d3_date_utc;
+ var utc = new d3_date_utc();
+ utc._ = t0;
+ return range(utc, t1, dt);
+ } finally {
+ d3_date = Date;
+ }
+ }
+ local.floor = local;
+ local.round = round;
+ local.ceil = ceil;
+ local.offset = offset;
+ local.range = range;
+ var utc = local.utc = d3_time_interval_utc(local);
+ utc.floor = utc;
+ utc.round = d3_time_interval_utc(round);
+ utc.ceil = d3_time_interval_utc(ceil);
+ utc.offset = d3_time_interval_utc(offset);
+ utc.range = range_utc;
+ return local;
+ }
+ function d3_time_interval_utc(method) {
+ return function(date, k) {
+ try {
+ d3_date = d3_date_utc;
+ var utc = new d3_date_utc();
+ utc._ = date;
+ return method(utc, k)._;
+ } finally {
+ d3_date = Date;
+ }
+ };
+ }
+ d3_time.year = d3_time_interval(function(date) {
+ date = d3_time.day(date);
+ date.setMonth(0, 1);
+ return date;
+ }, function(date, offset) {
+ date.setFullYear(date.getFullYear() + offset);
+ }, function(date) {
+ return date.getFullYear();
+ });
+ d3_time.years = d3_time.year.range;
+ d3_time.years.utc = d3_time.year.utc.range;
+ d3_time.day = d3_time_interval(function(date) {
+ var day = new d3_date(2e3, 0);
+ day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
+ return day;
+ }, function(date, offset) {
+ date.setDate(date.getDate() + offset);
+ }, function(date) {
+ return date.getDate() - 1;
+ });
+ d3_time.days = d3_time.day.range;
+ d3_time.days.utc = d3_time.day.utc.range;
+ d3_time.dayOfYear = function(date) {
+ var year = d3_time.year(date);
+ return Math.floor((date - year - (date.getTimezoneOffset() -
year.getTimezoneOffset()) * 6e4) / 864e5);
+ };
+ d3_time_daySymbols.forEach(function(day, i) {
+ day = day.toLowerCase();
+ i = 7 - i;
+ var interval = d3_time[day] = d3_time_interval(function(date) {
+ (date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
+ return date;
+ }, function(date, offset) {
+ date.setDate(date.getDate() + Math.floor(offset) * 7);
+ }, function(date) {
+ var day = d3_time.year(date).getDay();
+ return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
+ });
+ d3_time[day + "s"] = interval.range;
+ d3_time[day + "s"].utc = interval.utc.range;
+ d3_time[day + "OfYear"] = function(date) {
+ var day = d3_time.year(date).getDay();
+ return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7);
+ };
+ });
+ d3_time.week = d3_time.sunday;
+ d3_time.weeks = d3_time.sunday.range;
+ d3_time.weeks.utc = d3_time.sunday.utc.range;
+ d3_time.weekOfYear = d3_time.sundayOfYear;
+ d3_time.format = d3_time_format;
+ function d3_time_format(template) {
+ var n = template.length;
+ function format(date) {
+ var string = [], i = -1, j = 0, c, p, f;
+ while (++i < n) {
+ if (template.charCodeAt(i) === 37) {
+ string.push(template.substring(j, i));
+ if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c =
template.charAt(++i);
+ if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ?
" " : "0" : p);
+ string.push(c);
+ j = i + 1;
+ }
+ }
+ string.push(template.substring(j, i));
+ return string.join("");
+ }
+ format.parse = function(string) {
+ var d = {
+ y: 1900,
+ m: 0,
+ d: 1,
+ H: 0,
+ M: 0,
+ S: 0,
+ L: 0,
+ Z: null
+ }, i = d3_time_parse(d, template, string, 0);
+ if (i != string.length) return null;
+ if ("p" in d) d.H = d.H % 12 + d.p * 12;
+ var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ?
d3_date_utc : d3_date)();
+ if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d
&& ("W" in d || "U" in d)) {
+ date.setFullYear(d.y, 0, 1);
+ date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 -
(date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7);
+ } else date.setFullYear(d.y, d.m, d.d);
+ date.setHours(d.H + Math.floor(d.Z / 100), d.M + d.Z % 100, d.S, d.L);
+ return localZ ? date._ : date;
+ };
+ format.toString = function() {
+ return template;
+ };
+ return format;
+ }
+ function d3_time_parse(date, template, string, j) {
+ var c, p, t, i = 0, n = template.length, m = string.length;
+ while (i < n) {
+ if (j >= m) return -1;
+ c = template.charCodeAt(i++);
+ if (c === 37) {
+ t = template.charAt(i++);
+ p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t];
+ if (!p || (j = p(date, string, j)) < 0) return -1;
+ } else if (c != string.charCodeAt(j++)) {
+ return -1;
+ }
+ }
+ return j;
+ }
+ function d3_time_formatRe(names) {
+ return new RegExp("^(?:" + names.map(d3.requote).join("|") +
")", "i");
+ }
+ function d3_time_formatLookup(names) {
+ var map = new d3_Map(), i = -1, n = names.length;
+ while (++i < n) map.set(names[i].toLowerCase(), i);
+ return map;
+ }
+ function d3_time_formatPad(value, fill, width) {
+ var sign = value < 0 ? "-" : "", string = (sign ? -value :
value) + "", length = string.length;
+ return sign + (length < width ? new Array(width - length + 1).join(fill) + string
: string);
+ }
+ var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayLookup =
d3_time_formatLookup(d3_time_days), d3_time_dayAbbrevRe =
d3_time_formatRe(d3_time_dayAbbreviations), d3_time_dayAbbrevLookup =
d3_time_formatLookup(d3_time_dayAbbreviations), d3_time_monthRe =
d3_time_formatRe(d3_time_months), d3_time_monthLookup =
d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe =
d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup =
d3_time_formatLookup(d3_time_monthAbbreviations), d3_time_percentRe = /^%/;
+ var d3_time_formatPads = {
+ "-": "",
+ _: " ",
+ "0": "0"
+ };
+ var d3_time_formats = {
+ a: function(d) {
+ return d3_time_dayAbbreviations[d.getDay()];
+ },
+ A: function(d) {
+ return d3_time_days[d.getDay()];
+ },
+ b: function(d) {
+ return d3_time_monthAbbreviations[d.getMonth()];
+ },
+ B: function(d) {
+ return d3_time_months[d.getMonth()];
+ },
+ c: d3_time_format(d3_time_formatDateTime),
+ d: function(d, p) {
+ return d3_time_formatPad(d.getDate(), p, 2);
+ },
+ e: function(d, p) {
+ return d3_time_formatPad(d.getDate(), p, 2);
+ },
+ H: function(d, p) {
+ return d3_time_formatPad(d.getHours(), p, 2);
+ },
+ I: function(d, p) {
+ return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);
+ },
+ j: function(d, p) {
+ return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3);
+ },
+ L: function(d, p) {
+ return d3_time_formatPad(d.getMilliseconds(), p, 3);
+ },
+ m: function(d, p) {
+ return d3_time_formatPad(d.getMonth() + 1, p, 2);
+ },
+ M: function(d, p) {
+ return d3_time_formatPad(d.getMinutes(), p, 2);
+ },
+ p: function(d) {
+ return d.getHours() >= 12 ? "PM" : "AM";
+ },
+ S: function(d, p) {
+ return d3_time_formatPad(d.getSeconds(), p, 2);
+ },
+ U: function(d, p) {
+ return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2);
+ },
+ w: function(d) {
+ return d.getDay();
+ },
+ W: function(d, p) {
+ return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2);
+ },
+ x: d3_time_format(d3_time_formatDate),
+ X: d3_time_format(d3_time_formatTime),
+ y: function(d, p) {
+ return d3_time_formatPad(d.getFullYear() % 100, p, 2);
+ },
+ Y: function(d, p) {
+ return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);
+ },
+ Z: d3_time_zone,
+ "%": function() {
+ return "%";
+ }
+ };
+ var d3_time_parsers = {
+ a: d3_time_parseWeekdayAbbrev,
+ A: d3_time_parseWeekday,
+ b: d3_time_parseMonthAbbrev,
+ B: d3_time_parseMonth,
+ c: d3_time_parseLocaleFull,
+ d: d3_time_parseDay,
+ e: d3_time_parseDay,
+ H: d3_time_parseHour24,
+ I: d3_time_parseHour24,
+ j: d3_time_parseDayOfYear,
+ L: d3_time_parseMilliseconds,
+ m: d3_time_parseMonthNumber,
+ M: d3_time_parseMinutes,
+ p: d3_time_parseAmPm,
+ S: d3_time_parseSeconds,
+ U: d3_time_parseWeekNumberSunday,
+ w: d3_time_parseWeekdayNumber,
+ W: d3_time_parseWeekNumberMonday,
+ x: d3_time_parseLocaleDate,
+ X: d3_time_parseLocaleTime,
+ y: d3_time_parseYear,
+ Y: d3_time_parseFullYear,
+ Z: d3_time_parseZone,
+ "%": d3_time_parseLiteralPercent
+ };
+ function d3_time_parseWeekdayAbbrev(date, string, i) {
+ d3_time_dayAbbrevRe.lastIndex = 0;
+ var n = d3_time_dayAbbrevRe.exec(string.substring(i));
+ return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i +
n[0].length) : -1;
+ }
+ function d3_time_parseWeekday(date, string, i) {
+ d3_time_dayRe.lastIndex = 0;
+ var n = d3_time_dayRe.exec(string.substring(i));
+ return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) :
-1;
+ }
+ function d3_time_parseWeekdayNumber(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 1));
+ return n ? (date.w = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseWeekNumberSunday(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i));
+ return n ? (date.U = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseWeekNumberMonday(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i));
+ return n ? (date.W = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseMonthAbbrev(date, string, i) {
+ d3_time_monthAbbrevRe.lastIndex = 0;
+ var n = d3_time_monthAbbrevRe.exec(string.substring(i));
+ return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i +
n[0].length) : -1;
+ }
+ function d3_time_parseMonth(date, string, i) {
+ d3_time_monthRe.lastIndex = 0;
+ var n = d3_time_monthRe.exec(string.substring(i));
+ return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) :
-1;
+ }
+ function d3_time_parseLocaleFull(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
+ }
+ function d3_time_parseLocaleDate(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
+ }
+ function d3_time_parseLocaleTime(date, string, i) {
+ return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
+ }
+ function d3_time_parseFullYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 4));
+ return n ? (date.y = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1;
+ }
+ function d3_time_parseZone(date, string, i) {
+ return /^[+-]\d{4}$/.test(string = string.substring(i, i + 5)) ? (date.Z = +string,
+ i + 5) : -1;
+ }
+ function d3_time_expandYear(d) {
+ return d + (d > 68 ? 1900 : 2e3);
+ }
+ function d3_time_parseMonthNumber(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.m = n[0] - 1, i + n[0].length) : -1;
+ }
+ function d3_time_parseDay(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.d = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseDayOfYear(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 3));
+ return n ? (date.j = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseHour24(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.H = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseMinutes(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.M = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseSeconds(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 2));
+ return n ? (date.S = +n[0], i + n[0].length) : -1;
+ }
+ function d3_time_parseMilliseconds(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 3));
+ return n ? (date.L = +n[0], i + n[0].length) : -1;
+ }
+ var d3_time_numberRe = /^\s*\d+/;
+ function d3_time_parseAmPm(date, string, i) {
+ var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase());
+ return n == null ? -1 : (date.p = n, i);
+ }
+ var d3_time_amPmLookup = d3.map({
+ am: 0,
+ pm: 1
+ });
+ function d3_time_zone(d) {
+ var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh =
~~(abs(z) / 60), zm = abs(z) % 60;
+ return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm,
"0", 2);
+ }
+ function d3_time_parseLiteralPercent(date, string, i) {
+ d3_time_percentRe.lastIndex = 0;
+ var n = d3_time_percentRe.exec(string.substring(i, i + 1));
+ return n ? i + n[0].length : -1;
+ }
+ d3_time_format.utc = d3_time_formatUtc;
+ function d3_time_formatUtc(template) {
+ var local = d3_time_format(template);
+ function format(date) {
+ try {
+ d3_date = d3_date_utc;
+ var utc = new d3_date();
+ utc._ = date;
+ return local(utc);
+ } finally {
+ d3_date = Date;
+ }
+ }
+ format.parse = function(string) {
+ try {
+ d3_date = d3_date_utc;
+ var date = local.parse(string);
+ return date && date._;
+ } finally {
+ d3_date = Date;
+ }
+ };
+ format.toString = local.toString;
+ return format;
+ }
+ var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ");
+ d3_time_format.iso = Date.prototype.toISOString && +new
Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso;
+ function d3_time_formatIsoNative(date) {
+ return date.toISOString();
+ }
+ d3_time_formatIsoNative.parse = function(string) {
+ var date = new Date(string);
+ return isNaN(date) ? null : date;
+ };
+ d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
+ d3_time.second = d3_time_interval(function(date) {
+ return new d3_date(Math.floor(date / 1e3) * 1e3);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 1e3);
+ }, function(date) {
+ return date.getSeconds();
+ });
+ d3_time.seconds = d3_time.second.range;
+ d3_time.seconds.utc = d3_time.second.utc.range;
+ d3_time.minute = d3_time_interval(function(date) {
+ return new d3_date(Math.floor(date / 6e4) * 6e4);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 6e4);
+ }, function(date) {
+ return date.getMinutes();
+ });
+ d3_time.minutes = d3_time.minute.range;
+ d3_time.minutes.utc = d3_time.minute.utc.range;
+ d3_time.hour = d3_time_interval(function(date) {
+ var timezone = date.getTimezoneOffset() / 60;
+ return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
+ }, function(date, offset) {
+ date.setTime(date.getTime() + Math.floor(offset) * 36e5);
+ }, function(date) {
+ return date.getHours();
+ });
+ d3_time.hours = d3_time.hour.range;
+ d3_time.hours.utc = d3_time.hour.utc.range;
+ d3_time.month = d3_time_interval(function(date) {
+ date = d3_time.day(date);
+ date.setDate(1);
+ return date;
+ }, function(date, offset) {
+ date.setMonth(date.getMonth() + offset);
+ }, function(date) {
+ return date.getMonth();
+ });
+ d3_time.months = d3_time.month.range;
+ d3_time.months.utc = d3_time.month.utc.range;
+ function d3_time_scale(linear, methods, format) {
+ function scale(x) {
+ return linear(x);
+ }
+ scale.invert = function(x) {
+ return d3_time_scaleDate(linear.invert(x));
+ };
+ scale.domain = function(x) {
+ if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
+ linear.domain(x);
+ return scale;
+ };
+ function tickMethod(extent, count) {
+ var span = extent[1] - extent[0], target = span / count, i =
d3.bisect(d3_time_scaleSteps, target);
+ return i == d3_time_scaleSteps.length ? [ methods.year,
d3_scale_linearTickRange(extent.map(function(d) {
+ return d / 31536e6;
+ }), count)[2] ] : !i ? [ d3_time_scaleMilliseconds,
d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1]
< d3_time_scaleSteps[i] / target ? i - 1 : i];
+ }
+ scale.nice = function(interval, skip) {
+ var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval ==
null ? tickMethod(extent, 10) : typeof interval === "number" &&
tickMethod(extent, interval);
+ if (method) interval = method[0], skip = method[1];
+ function skipped(date) {
+ return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date +
1), skip).length;
+ }
+ return scale.domain(d3_scale_nice(domain, skip > 1 ? {
+ floor: function(date) {
+ while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date -
1);
+ return date;
+ },
+ ceil: function(date) {
+ while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date +
1);
+ return date;
+ }
+ } : interval));
+ };
+ scale.ticks = function(interval, skip) {
+ var extent = d3_scaleExtent(scale.domain()), method = interval == null ?
tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent,
interval) : !interval.range && [ {
+ range: interval
+ }, skip ];
+ if (method) interval = method[0], skip = method[1];
+ return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1
: skip);
+ };
+ scale.tickFormat = function() {
+ return format;
+ };
+ scale.copy = function() {
+ return d3_time_scale(linear.copy(), methods, format);
+ };
+ return d3_scale_linearRebind(scale, linear);
+ }
+ function d3_time_scaleDate(t) {
+ return new Date(t);
+ }
+ function d3_time_scaleFormat(formats) {
+ return function(date) {
+ var i = formats.length - 1, f = formats[i];
+ while (!f[1](date)) f = formats[--i];
+ return f[0](date);
+ };
+ }
+ var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5,
216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];
+ var d3_time_scaleLocalMethods = [ [ d3_time.second, 1 ], [ d3_time.second, 5 ], [
d3_time.second, 15 ], [ d3_time.second, 30 ], [ d3_time.minute, 1 ], [ d3_time.minute, 5
], [ d3_time.minute, 15 ], [ d3_time.minute, 30 ], [ d3_time.hour, 1 ], [ d3_time.hour, 3
], [ d3_time.hour, 6 ], [ d3_time.hour, 12 ], [ d3_time.day, 1 ], [ d3_time.day, 2 ], [
d3_time.week, 1 ], [ d3_time.month, 1 ], [ d3_time.month, 3 ], [ d3_time.year, 1 ] ];
+ var d3_time_scaleLocalFormats = [ [ d3_time_format("%Y"), d3_true ], [
d3_time_format("%B"), function(d) {
+ return d.getMonth();
+ } ], [ d3_time_format("%b %d"), function(d) {
+ return d.getDate() != 1;
+ } ], [ d3_time_format("%a %d"), function(d) {
+ return d.getDay() && d.getDate() != 1;
+ } ], [ d3_time_format("%I %p"), function(d) {
+ return d.getHours();
+ } ], [ d3_time_format("%I:%M"), function(d) {
+ return d.getMinutes();
+ } ], [ d3_time_format(":%S"), function(d) {
+ return d.getSeconds();
+ } ], [ d3_time_format(".%L"), function(d) {
+ return d.getMilliseconds();
+ } ] ];
+ var d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);
+ d3_time_scaleLocalMethods.year = d3_time.year;
+ d3_time.scale = function() {
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods,
d3_time_scaleLocalFormat);
+ };
+ var d3_time_scaleMilliseconds = {
+ range: function(start, stop, step) {
+ return d3.range(+start, +stop, step).map(d3_time_scaleDate);
+ },
+ floor: d3_identity,
+ ceil: d3_identity
+ };
+ var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) {
+ return [ m[0].utc, m[1] ];
+ });
+ var d3_time_scaleUTCFormats = [ [ d3_time_formatUtc("%Y"), d3_true ], [
d3_time_formatUtc("%B"), function(d) {
+ return d.getUTCMonth();
+ } ], [ d3_time_formatUtc("%b %d"), function(d) {
+ return d.getUTCDate() != 1;
+ } ], [ d3_time_formatUtc("%a %d"), function(d) {
+ return d.getUTCDay() && d.getUTCDate() != 1;
+ } ], [ d3_time_formatUtc("%I %p"), function(d) {
+ return d.getUTCHours();
+ } ], [ d3_time_formatUtc("%I:%M"), function(d) {
+ return d.getUTCMinutes();
+ } ], [ d3_time_formatUtc(":%S"), function(d) {
+ return d.getUTCSeconds();
+ } ], [ d3_time_formatUtc(".%L"), function(d) {
+ return d.getUTCMilliseconds();
+ } ] ];
+ var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
+ d3_time_scaleUTCMethods.year = d3_time.year.utc;
+ d3_time.scale.utc = function() {
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods,
d3_time_scaleUTCFormat);
+ };
+ d3.text = d3_xhrType(function(request) {
+ return request.responseText;
+ });
+ d3.json = function(url, callback) {
+ return d3_xhr(url, "application/json", d3_json, callback);
+ };
+ function d3_json(request) {
+ return JSON.parse(request.responseText);
+ }
+ d3.html = function(url, callback) {
+ return d3_xhr(url, "text/html", d3_html, callback);
+ };
+ function d3_html(request) {
+ var range = d3_document.createRange();
+ range.selectNode(d3_document.body);
+ return range.createContextualFragment(request.responseText);
+ }
+ d3.xml = d3_xhrType(function(request) {
+ return request.responseXML;
+ });
+ return d3;
+}();
\ No newline at end of file
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.3.13.min.js
b/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.3.13.min.js
new file mode 100755
index 0000000..dba5993
--- /dev/null
+++ b/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.3.13.min.js
@@ -0,0 +1,5 @@
+d3=function(){function n(n){return null!=n&&!isNaN(n)}function t(n){return
n.length}function e(n){for(var t=1;n*t%1;)t*=10;return t}function r(n,t){try{for(var e in
t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function
u(){}function i(){}function o(n,t,e){return function(){var r=e.apply(t,arguments);return
r===t?n:r}}function a(n,t){if(t in n)return
t;t=t.charAt(0).toUpperCase()+t.substring(1);for(var e=0,r=fa.length;r>e;++e){var
u=fa[e]+t;if(u in n)return u}}function c(){}function s(){}function l(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 u;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
f(){Bo.event.preventDefault()}function h(){for(var
n,t=Bo.event;n=t.sourceEvent;)t=n;return t}function g(n){for(var t=new s,e=0,r
=arguments.length;++e<r;)t[arguments[e]]=l(t);return t.of=function(e,r){return
function(u){try{var
i=u.sourceEvent=Bo.event;u.target=n,Bo.event=u,t[u.type].apply(e,r)}finally{Bo.event=i}}},t}function
p(n){return ga(n,ya),n}function v(n){return"function"==typeof
n?n:function(){return pa(n,this)}}function d(n){return"function"==typeof
n?n:function(){return va(n,this)}}function m(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=Bo.ns.qualify(n),null==t?n.local?r:e:"function"==typeof
t?n.local?a:o:n.local?i:u}function y(n){return n.trim().replace(/\s+/g,"
")}function x(n){return new RegExp("(?:^|\\s+)"+Bo.requote(n
)+"(?:\\s+|$)","g")}function M(n){return
n.trim().split(/^|\s+/)}function _(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=M(n).map(b);var
u=n.length;return"function"==typeof t?r:e}function b(n){var t=x(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",y(u+"
"+n))):e.setAttribute("class",y(u.replace(t," ")))}}function
w(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 S(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
k(n){return"function"==typeof n?n:(n=Bo.ns.qu
alify(n)).local?function(){return
this.ownerDocument.createElementNS(n.space,n.local)}:function(){return
this.ownerDocument.createElementNS(this.namespaceURI,n)}}function
E(n){return{__data__:n}}function A(n){return function(){return ma(this,n)}}function
C(n){return arguments.length||(n=Bo.ascending),function(t,e){return
t&&e?n(t.__data__,e.__data__):!t-!e}}function N(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
L(n){return ga(n,Ma),n}function T(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 q(){var n=this.__transition__;n&&++n.active}function z(n,t,e){function
r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function
u(){var
u=s(t,Jo(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function
i(){var t,e=new RegExp("^__on([^.]+)"+Bo.requote(n)+"$");for(var r in
this)if(t=r.ma
tch(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var
o="__on"+n,a=n.indexOf("."),s=R;a>0&&(n=n.substring(0,a));var
l=ba.get(n);return l&&(n=l,s=D),a?t?u:r:t?c:i}function R(n,t){return
function(e){var
r=Bo.event;Bo.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{Bo.event=r}}}function
D(n,t){var e=R(n,t);return function(n){var
t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function
P(){var n=".dragsuppress-"+
++Sa,t="click"+n,e=Bo.select(Qo).on("touchmove"+n,f).on("dragstart"+n,f).on("selectstart"+n,f);if(wa){var
r=Ko.style,u=r[wa];r[wa]="none"}return function(i){function
o(){e.on(t,null)}e.on(n,null),wa&&(r[wa]=u),i&&(e.on(t,function(){f(),o()},!0),setTimeout(o,0))}}function
U(n,t){t.changedTouches&&(t=t.changedTouches[0]);var
e=n.ownerSVGElement||n;if(e.createSVGPoint){var
r=e.createSVGPoint();if(0>ka&&(Qo.scrollX||Qo.scrollY)){e=Bo.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:
0,padding:0,border:"none"},"important");var
u=e[0][0].getScreenCTM();ka=!(u.f||u.e),e.remove()}return
ka?(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
j(n){return n>0?1:0>n?-1:0}function H(n){return
n>1?0:-1>n?Ea:Math.acos(n)}function F(n){return
n>1?Ca:-1>n?-Ca:Math.asin(n)}function O(n){return((n=Math.exp(n))-1/n)/2}function
Y(n){return((n=Math.exp(n))+1/n)/2}function
I(n){return((n=Math.exp(2*n))-1)/(n+1)}function Z(n){return(n=Math.sin(n/2))*n}function
V(){}function X(n,t,e){return new $(n,t,e)}function
$(n,t,e){this.h=n,this.s=t,this.l=e}function B(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,at(u(n+120),u(n),u(n-120))}function W(n,t,e){return new
J(n,t,e)}function J(n,t,e){this.h=n,this.c=t,this.l=e}function G(n,t,e){return
isNaN(n)&&(n=0),isNaN(t)&&(t=0),K(e,Math.cos(n*=Ta)*t,Math.sin(n)*t)}function
K(n,t,e){return new Q(n,t,e)}function Q(n,t,e){this.l=n,this.a=t,this.b=e}function
nt(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return
u=et(u)*Ya,r=et(r)*Ia,i=et(i)*Za,at(ut(3.2404542*u-1.5371385*r-.4985314*i),ut(-.969266*u+1.8760108*r+.041556*i),ut(.0556434*u-.2040259*r+1.0572252*i))}function
tt(n,t,e){return n>0?W(Math.atan2(e,t)*qa,Math.sqrt(t*t+e*e),n):W(0/0,0/0,n)}function
et(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function rt(n){return
n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function ut(n){return
Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function it(n){return
at(n>>16,255&n>>8,255&n)}function ot(n){return
it(n)+""}function at(n,t,e){return new ct(n,t,e)}function
ct(n,t,e){this.r=n,this.g=t,this.b=e}function s
t(n){return
16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function
lt(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(pt(u[0]),pt(u[1]),pt(u[2]))}return(i=$a.get(n))?t(i.r,i.g,i.b):(null!=n&&"#"===n.charAt(0)&&(4===n.length?(o=n.charAt(1),o+=o,a=n.charAt(2),a+=a,c=n.charAt(3),c+=c):7===n.length&&(o=n.substring(1,3),a=n.substring(3,5),c=n.substring(5,7)),o=parseInt(o,16),a=parseInt(a,16),c=parseInt(c,16)),t(o,a,c))}function
ft(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),X(r,u,c)}function
ht(n,t,e){n=gt(n),t=gt(t),e=gt(e);var
r=rt((.4124564*n+.3575761*t+.1804375*e)/Ya),u=rt((.2126729*n+.7151522*t+.072175*e)/Ia),i=rt((.0193339*n+.119192*t+.9503041*e)/Za);return
K(116*u
-16,500*(r-u),200*(u-i))}function
gt(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function pt(n){var
t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function
vt(n){return"function"==typeof n?n:function(){return n}}function dt(n){return
n}function mt(n){return function(t,e,r){return
2===arguments.length&&"function"==typeof
e&&(r=e,e=null),yt(t,e,n,r)}}function yt(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=Bo.dispatch("beforesend","progress","load","error"),a={},c=new
XMLHttpRequest,s=null;return!Qo.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=Bo.event;Bo.event=n;try{o.progress.call(i,c)}finally{Bo.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(Jo(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},Bo.rebind(i,o,"on"),null==r?i:i.get(xt(r))}function xt(n){return
1===n.length?function(t,e){n(null==t?e:null)}:n}function Mt(){var
n=_t(),t=bt()-n;t>24?(isFinite(t)&&(clearTimeout(Ga)
,Ga=setTimeout(Mt,t)),Ja=0):(Ja=1,Qa(Mt))}function _t(){var
n=Date.now();for(Ka=Ba;Ka;)n>=Ka.t&&(Ka.f=Ka.c(n-Ka.t)),Ka=Ka.n;return
n}function bt(){for(var
n,t=Ba,e=1/0;t;)t.f?t=n?n.n=t.n:Ba=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return
Wa=n,e}function wt(n,t){var
e=Math.pow(10,3*ca(8-t));return{scale:t>8?function(n){return n/e}:function(n){return
n*e},symbol:n}}function St(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function
kt(n){return n+""}function Et(){}function At(n,t,e){var
r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function
Ct(n,t){n&&fc.hasOwnProperty(n.type)&&fc[n.type](n,t)}function
Nt(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
Lt(n,t){var
e=-1,r=n.length;for(t.polygonStart();++e<r;)Nt(n[e],t,1);t.polygonEnd()}function
Tt(){function n(n,t){n*=Ta,t=t*Ta/2+Ea/4;var
e=n-r,o=Math.cos(t),a=Math.sin(t),c=i*a,s=u*o+c*Math.cos(e),l=c*Math.sin(e);gc.add(Math.atan2(l,s)),r=n,u=o,i=a}var
t,e,r,u,i;pc.point=function(o,
a){pc.point=n,r=(t=o)*Ta,u=Math.cos(a=(e=a)*Ta/2+Ea/4),i=Math.sin(a)},pc.lineEnd=function(){n(t,e)}}function
qt(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
zt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function
Rt(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
Dt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function
Pt(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Ut(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
jt(n){return[Math.atan2(n[1],n[0]),F(n[2])]}function Ht(n,t){return
ca(n[0]-t[0])<Na&&ca(n[1]-t[1])<Na}function Ft(n,t){n*=Ta;var
e=Math.cos(t*=Ta);Ot(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function
Ot(n,t,e){++vc,mc+=(n-mc)/vc,yc+=(t-yc)/vc,xc+=(e-xc)/vc}function Yt(){function
n(n,u){n*=Ta;var
i=Math.cos(u*=Ta),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);dc+=s,Mc+=s*(t+(t=o)),_
c+=s*(e+(e=a)),bc+=s*(r+(r=c)),Ot(t,e,r)}var t,e,r;Ec.point=function(u,i){u*=Ta;var
o=Math.cos(i*=Ta);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),Ec.point=n,Ot(t,e,r)}}function
It(){Ec.point=Ft}function Zt(){function n(n,t){n*=Ta;var
e=Math.cos(t*=Ta),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&&-H(g)/h,v=Math.atan2(h,g);wc+=p*s,Sc+=p*l,kc+=p*f,dc+=v,Mc+=v*(r+(r=o)),_c+=v*(u+(u=a)),bc+=v*(i+(i=c)),Ot(r,u,i)}var
t,e,r,u,i;Ec.point=function(o,a){t=o,e=a,Ec.point=n,o*=Ta;var
c=Math.cos(a*=Ta);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),Ot(r,u,i)},Ec.lineEnd=function(){n(t,e),Ec.lineEnd=It,Ec.point=Ft}}function
Vt(){return!0}function Xt(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(Ht(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
Bt(e,n,null,!0),s=new Bt(e,null,c,!1);c.o=s,i.push(c),o.push(s),c=
new Bt(r,n,null,!1),s=new
Bt(r,null,c,!0),c.o=s,i.push(c),o.push(s)}}),o.sort(t),$t(i),$t(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
$t(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
Bt(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
Wt(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.lineStar
t(),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;for(i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);return
i.lineEnd(),void
0}r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Jt))}}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=[],i.polygonStart()},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=s,g=Bo.merge(g);var
n=Qt(m,p);g.length?Xt(g,Kt,n,e,i):n&&(i.lineStart(),e(null,null,1,i),i.lineEnd()),i.polygonEnd(),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},x=Gt(),M=t(x);return
y}}function Jt(n){return n.length>1}function Gt(){var
n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:c,buffer:function(){var
e=t;return t=[],n=null,e},rejoin:function(){t.length
1&&t.push(t.pop().concat(t.shift()))}}}function
Kt(n,t){return((n=n.x)[0]<0?n[1]-Ca-Na:Ca-n[1])-((t=t.x)[0]<0?t[1]-Ca-Na:Ca-t[1])}function
Qt(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;gc.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+Ea/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+Ea/4,x=Math.sin(y),M=Math.cos(y),_=m-h,b=ca(_)>Ea,w=p*x;if(gc.add(Math.atan2(w*Math.sin(_),v*M+w*Math.cos(_))),i+=b?_+(_>=0?Aa:-Aa):_,b^h>=e^m>=e){var
S=Rt(qt(f),qt(n));Ut(S);var k=Rt(u,S);Ut(k);var
E=(b^_>=0?-1:1)*F(k[2]);(r>E||r===E&&(S[0]||S[1]))&&(o+=b^_>=0?1:-1)}if(!d++)break;h=m,p=x,v=M,f=n}}return(-Na>i||Na>i&&0>gc)^1&o}function
ne(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?Ea:-Ea,c=ca(i-e);ca(c-Ea)<Na?(n.point(e,r=(r+o)/2>0?Ca:-Ca),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=Ea&&(ca(e-u)<Na&&(
e-=u*Na),ca(i-a)<Na&&(i-=a*Na),r=te(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 te(n,t,e,r){var u,i,o=Math.sin(n-e);return
ca(o)>Na?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
ee(n,t,e,r){var
u;if(null==n)u=e*Ca,r.point(-Ea,u),r.point(0,u),r.point(Ea,u),r.point(Ea,0),r.point(Ea,-u),r.point(0,-u),r.point(-Ea,-u),r.point(-Ea,0),r.point(-Ea,u);else
if(ca(n[0]-t[0])>Na){var
i=n[0]<t[0]?Ea:-Ea;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else
r.point(t[0],t[1])}function re(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?Ea:-Ea),h):0;if(!e&&(s=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(Ht(e,g)||Ht(p,g))&&(p[0]+=Na,p[1]+=Na,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&&Ht(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=qt(n),u=qt(t),o=[1,0,0],a=Rt(r,u),c=zt(a,a),s=a[0],l=c-s*s;if(!l)return!e&&n;var
f=i*c/l,h=-i*s/l,g=Rt(o,a),p=Pt(o,f),v=Pt(a,h);Dt(p,v);var
d=g,m=zt(p,d),y=zt(d,d),x=m*m-y*(zt(p,p)-1);if(!(0>x)){var
M=Math.sqrt(x),_=Pt(d,(-m-M)/y);if(Dt(_,p),_=jt(_),!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=ca(A-Ea)<Na,N=C||Na>A;if(!C&&k>E&&(b=k,k=E,E=b),N?C?k+E>0^_[1]<(ca(_[0]-w)<Na?k:E):k<=_[1]&&_[1]<=E:A>Ea^(w<=_[0]&&_[0]<=S)){var
L=Pt(d,(-m+M)/y);return Dt(L,p),[_,jt(L)]}}}function u(t,e){var r=o?n:Ea-n,u=0;r
eturn-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=ca(i)>Na,c=Te(n,6*Ta);return
Wt(t,e,c,o?[0,-n]:[-Ea,n-Ea])}function ue(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
ie(n,t,e,r){function u(r,u){return
ca(r[0]-n)<Na?u>0?0:3:ca(r[0]-e)<Na?u>0?2:1:ca(r[1]-t)<Na?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=m.length,r=n[1],u=0;e>u;++u)for(var
i,o=1,a=m[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&s(l,i,n)>0&&++t:i[1]<=r&&s(l,i,n)<0&&--t,l=i;return
0!==t}function s(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(e[0]-n[0])*(t[1]-n[1])}function
l(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 f(u,i){return
u>=n&&e>=u&&i>=t&&r>=i}function
h(n,t){f(n,t)&&a.point(n,t)}function
g(){L.point=v,m&&m.push(y=[]),k=!0,S=!1,b=w=0/0}function
p(){d&&(v(x,M),_&&S&&C.rejoin(),d.push(C.buffer())),L.point=h,S&&a.lineEnd()}function
v(n,t){n=Math.max(-Cc,Math.min(Cc,n)),t=Math.max(-Cc,Math.min(Cc,t));var
e=f(n,t);if(m&&y.push([n,t]),k)x=n,M=t,_=e,k=!1,e&&(a.lineStart(),a.point(n,t));else
if(e&&S)a.point(n,t);else{var
r={a:{x:b,y:w},b:{x:n,y:t}};N(r)?(S||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),E=!1):e&&(a.lineStart(),a.point(n,t),E=!1)
}b=n,w=t,S=e}var
d,m,y,x,M,_,b,w,S,k,E,A=a,C=Gt(),N=ue(n,t,e,r),L={point:h,lineStart:g,lineEnd:p,polygonStart:function(){a=C,d=[],m=[],E=!0},polygonEnd:function(){a=A,d=Bo.merge(d);var
t=c([n,r]),e=E&&t,u=d.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),u&&Xt(d,i,t,l,a),a.polygonEnd()),d=m=y=null}};return
L}}function oe(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 ae(n){var
t=0,e=Ea/3,r=we(n),u=r(t,e);return u.parallels=function(n){return
arguments.length?r(t=n[0]*Ea/180,e=n[1]*Ea/180):[180*(t/Ea),180*(e/Ea)]},u}function
ce(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,F((i-(n*n+e*e)*u*u)/(2*u))]},e}function se(){function
n(n,t){Lc+=u*n-r*t,r=n,
u=t}var
t,e,r,u;Dc.point=function(i,o){Dc.point=n,t=r=i,e=u=o},Dc.lineEnd=function(){n(t,e)}}function
le(n,t){Tc>n&&(Tc=n),n>zc&&(zc=n),qc>t&&(qc=t),t>Rc&&(Rc=t)}function
fe(){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=he(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=he(n),a},result:function(){if(o.length){var n=o.join("");return
o=[],n}}};return a}function
he(n){return"m0,"+n+"a"+n+","+n+" 0 1,1
0,"+-2*n+"a"+n+","+n+" 0 1,1
0,"+2*n+"z"}function ge(n,t){mc+=n,yc+=t,++xc}function pe(){function
n(n,r){var
u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);Mc+=o*(t+n)/2,_c+=o*(e+r)/2,bc+=o,ge(t=n,e=r)}var
t,e;Uc.point=function(r,u){Uc.point=n,ge(t=r,e=u)}}function ve(){Uc.point=ge}function
de(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt
(e*e+i*i);Mc+=o*(r+n)/2,_c+=o*(u+t)/2,bc+=o,o=u*n-r*t,wc+=o*(r+n),Sc+=o*(u+t),kc+=3*o,ge(r=n,u=t)}var
t,e,r,u;Uc.point=function(i,o){Uc.point=n,ge(t=r=i,e=u=o)},Uc.lineEnd=function(){n(t,e)}}function
me(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,Aa)}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:c};return a}function ye(n){function t(n){return(a?r:e)(n)}function
e(t){return _e(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=qt([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=ca(ca(w)-1)<Na||ca(r-h)<Na?(r+h)/2:Math.atan2(b,_),A=n(E,k),C=A[0],N=A[1],L=C-t,T=N-e,q=x*L-y*T;(q*q/M>i||ca((y*L+x*T)/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*Ta),a=16;return t.precision=function(n){return
arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function xe(n){var
t=ye(function(t,e){return n([t*qa,e*qa])});return function(n){return Se(t(n))}}function
Me(n){this.stream=n}function
_e(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:fu
nction(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function
be(n){return we(function(){return n})()}function we(n){function t(n){return
n=a(n[0]*Ta,n[1]*Ta),[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]*qa,n[1]*qa]}function
r(){a=oe(o=Ae(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=ye(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=Ac,_=dt,b=null,w=null;return
t.stream=function(n){return
l&&(l.valid=!1),l=Se(M(o,f(_(n)))),l.valid=!0,l},t.clipAngle=function(n){return
arguments.length?(M=null==n?(b=n,Ac):re((b=+n)*Ta),u()):b},t.clipExtent=function(n){return
arguments.length?(w=n,_=n?ie(n[0][0],n[0][1],n[1][0],n[1][1]):dt,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*Ta,d=n[1]%360*Ta,r()):[v*qa,d*qa]},t.rotate=function(n){return
arguments.length?(m=n[0]%360*Ta,y=n[1]%360*Ta,x=n.length>2?n[2]%360*Ta:0,r()):[m*qa,y*qa,x*qa]},Bo.rebind(t,f,"precision"),function(){return
i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function Se(n){return
_e(n,function(t,e){n.point(t*Ta,e*Ta)})}function ke(n,t){return[n,t]}function
Ee(n,t){return[n>Ea?n-Aa:-Ea>n?n+Aa:n,t]}function Ae(n,t,e){return
n?t||e?oe(Ne(n),Le(t,e)):Ne(n):t||e?Le(t,e):Ee}function Ce(n){return function(t,e){return
t+=n,[t>Ea?t-Aa:-Ea>t?t+Aa:t,e]}}function Ne(n){var t=Ce(n);return
t.invert=Ce(-n),t}function Le(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),F(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),F(l*r-a*u)]},e}function Te(n,t){var
e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var
c=o*t;null!=u?(u=qe(e,u),i=qe(e,i),(o>0?i>u:u>i)&&(u+=o*Aa)):(u=n+o*Aa,i=n-.5*c);for(var
s,l=u;o>0?l>i:i>l;l-=c)a.point((s=jt([e,-r*Math.cos(l),-r*Math.sin(l)]))[0],s[1])}}function
qe(n,t){var e=qt(t);e[0]-=n,Ut(e);var
r=H(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Na)%(2*Math.PI)}function ze(n,t,e){var
r=Bo.range(n,t-Na,e).concat(t);return function(n){return
r.map(function(t){return[n,t]})}}function Re(n,t,e){var
r=Bo.range(n,t-Na,e).concat(t);return function(n){return
r.map(function(t){return[t,n]})}}function De(n){return n.source}function Pe(n){return
n.target}function Ue(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(Z(r-t)+u*o*Z(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)*qa,Math.atan2(o,Math.sqrt(r*r+u*u))*qa]}:function(){return[n*qa,t*qa]};return
p.distance=h,p}function je(){function n(n,u){var
i=Math.sin(u*=Ta),o=Math.cos(u),a=ca((n*=Ta)-t),c=Math.cos(a);jc+=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;Hc.point=function(u,i){t=u*Ta,e=Math.sin(i*=Ta),r=Math.cos(i),Hc.point=n},Hc.lineEnd=function(){Hc.point=Hc.lineEnd=c}}function
He(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
Fe(n,t){function e(n,t){var
e=ca(ca(t)-Ca)<Na?0: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(Ea/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=j(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Ca]},e):Ye}function
Oe(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
ca(u)<Na?ke:(e.invert=function(n,t){var
e=i-t;return[Math.atan2(n,e)/u,i-j(u)*Math.sqrt(n*n+e*e)]},e)}function
Ye(n,t){return[n,Math.log(Math.tan(Ea/4+t/2))]}function Ie(n){var
t,e=be(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=Ea*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 Ze(n,t){return[Math.log(Math.tan(Ea/4+t/2)),-n]}function
Ve(n){return n[0]}function Xe(n){return n[1]}function $e(n,t,e,r){var u,i,o,a,c,s,l
;return
u=r[n],i=u[0],o=u[1],u=r[t],a=u[0],c=u[1],u=r[e],s=u[0],l=u[1],(l-o)*(a-i)-(c-o)*(s-i)>0}function
Be(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function
We(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
Je(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function
Ge(){yr(this),this.edge=this.site=this.circle=null}function Ke(n){var t=Gc.pop()||new
Ge;return t.site=n,t}function Qe(n){sr(n),Bc.remove(n),Gc.push(n),yr(n)}function nr(n){var
t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Qe(n);for(var
c=i;c.circle&&ca(e-c.circle.x)<Na&&ca(r-c.circle.cy)<Na;)i=c.P,a.unshift(c),Qe(c),c=i;a.unshift(c),sr(c);for(var
s=o;s.circle&&ca(e-s.circle.x)<Na&&ca(r-s.circle.cy)<Na;)o=s.N,a.push(s),Qe(s),s=o;a.push(s),sr(s);var
l,f=a.length;for(l=1;f>l;++l)s=a[l],c=a[l-1],vr(s.edge,c.site,s.site,u);c=a[0],s=a[f-1],s.edge=gr(c.site,s.site,null,u),cr(c),cr(s)}functi
on tr(n){for(var
t,e,r,u,i=n.x,o=n.y,a=Bc._;a;)if(r=er(a,o)-i,r>Na)a=a.L;else{if(u=i-rr(a,o),!(u>Na)){r>-Na?(t=a.P,e=a):u>-Na?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var
c=Ke(n);if(Bc.insert(t,c),t||e){if(t===e)return
sr(t),e=Ke(t.site),Bc.insert(c,e),c.edge=e.edge=gr(t.site,c.site),cr(t),cr(e),void
0;if(!e)return c.edge=gr(t.site,c.site),void 0;sr(t),sr(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};vr(e.edge,s,p,M),c.edge=gr(s,n,null,M),e.edge=gr(n,p,null,M),cr(t),cr(e)}}function
er(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 rr(n,t){var
e=n.N;if(e)return er(e,t);var r=n.site;return r.y===t?r.x:1/0}function
ur(n){this.site=n,this.edges=[]}function ir(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=$c,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,(ca(r-t)>Na||ca(u-e)>Na)&&(a.splice(o,0,new
dr(pr(i.site,l,ca(r-f)<Na&&p-u>Na?{x:f,y:ca(t-f)<Na?e:p}:ca(u-p)<Na&&h-r>Na?{x:ca(e-p)<Na?t:h,y:p}:ca(r-h)<Na&&u-g>Na?{x:h,y:ca(t-h)<Na?e:g}:ca(u-g)<Na&&r-f>Na?{x:ca(e-g)<Na?t:f,y:g}:null),i.site,null)),++c)}function
or(n,t){return t.angle-n.angle}function
ar(){yr(this),this.x=this.y=this.arc=this.site=this.cy=null}function cr(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>=-La)){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=Kc.pop()||new
ar;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=Jc._;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}Jc.insert(y,m),y||(Wc=m)}}}}function
sr(n){var
t=n.circle;t&&(t.P||(Wc=t.N),Jc.remove(t),Kc.push(t),yr(t),n.circle=null)}function
lr(n){for(var
t,e=Xc,r=ue(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!fr(t,n)||!r(t)||ca(t.a.x-t.b.x)<Na&&ca(t.a.y-t.b.y)<Na)&&(t.a=t.b=null,e.splice(u,1))}function
fr(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
hr(n,t){this.l=n,this.r=t,this.a=this.b=null}function gr(n,t,e,r){var u=new hr(n,t);return
Xc.push(u),e&&vr(u,n,t,e),r&&vr(u,t,n,r),$c[n.i].edges.push(new
dr(u,n,t)),$c[t.i].edges.push(new dr(u,t,n)),u}function pr(n,t,e){var r=new
hr(n,null);return r.a=t,r.b=e,Xc.push(r),r}function
vr(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 dr(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 mr(){this._=null}function
yr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function xr(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
Mr(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
_r(n){for(;n.L;)n=n.L;return n}function br(n,t){var
e,r,u,i=n.sort(wr).pop();for(Xc=[],$c=new Array(n.length),Bc=new mr,Jc=new
mr;;)if(u=Wc,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&($c[i.i]=new
ur(i),tr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;nr(u.arc)}t&&(lr(t),ir(t));var
o={cells:$c,edges:Xc};return Bc=Jc=Xc=$c=null,o}function wr(n,t){return
t.y-n.y||t.x-n.x}function Sr(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function
kr(n){return n.x}function Er(n){return n.y}function
Ar(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function
Cr(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]&&Cr(n,c[0],e,r,o,a),c[1]&&Cr(n,c[1],o
,r,u,a),c[2]&&Cr(n,c[2],e,a,o,i),c[3]&&Cr(n,c[3],o,a,u,i)}}function
Nr(n,t){n=Bo.rgb(n),t=Bo.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"#"+st(Math.round(e+i*n))+st(Math.round(r+o*n))+st(Math.round(u+a*n))}}function
Lr(n,t){var e,r={},u={};for(e in n)e in t?r[e]=zr(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
Tr(n,t){return t-=n=+n,function(e){return n+t*e}}function qr(n,t){var
e,r,u,i,o,a=0,c=0,s=[],l=[];for(n+="",t+="",ns.lastIndex=0,r=0;e=ns.exec(t);++r)e.index&&s.push(t.substring(a,c=e.index)),l.push({i:s.length,x:e[0]}),s.push(null),a=ns.lastIndex;for(a<t.length&&s.push(t.substring(a)),r=0,i=l.length;(e=ns.exec(n))&&i>r;++r)if(o=l[r],o.x==e[0]){if(o.i)if(null==s[o.i+1])for(s[o.i-1]+=o.x,s.splice(o.i,1),u=r+1;i>u;++u)l[u].i--;else
for(s[o.i-1]+=o.x+s[o.i+1],s.splice(o.i,2),u=r+1;i>u;++u)l[u].i-=2;else
if(null==s[o.i+1])s[o.i]=o.x;else for(s[o.i]=o.x+s[o.i+1],s.splice(o
.i+1,1),u=r+1;i>u;++u)l[u].i--;l.splice(r,1),i--,r--}else
o.x=Tr(parseFloat(e[0]),parseFloat(o.x));for(;i>r;)o=l.pop(),null==s[o.i+1]?s[o.i]=o.x:(s[o.i]=o.x+s[o.i+1],s.splice(o.i+1,1)),i--;return
1===s.length?null==s[0]?(o=l[0].x,function(n){return o(n)+""}):function(){return
t}:function(n){for(r=0;i>r;++r)s[(o=l[r]).i]=o.x(n);return
s.join("")}}function zr(n,t){for(var
e,r=Bo.interpolators.length;--r>=0&&!(e=Bo.interpolators[r](n,t)););return
e}function Rr(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(zr(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 Dr(n){return
function(t){return 0>=t?0:t>=1?1:n(t)}}function Pr(n){return function(t){return
1-n(1-t)}}function Ur(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function
jr(n){return n*n}function Hr(n){return n*n*n}function Fr(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 Or(n){return function(t){return
Math.pow(t,n)}}function Yr(n){return 1-Math.cos(n*Ca)}function Ir(n){return
Math.pow(2,10*(n-1))}function Zr(n){return 1-Math.sqrt(1-n*n)}function Vr(n,t){var
e;return
arguments.length<2&&(t=.45),arguments.length?e=t/Aa*Math.asin(1/n):(n=1,e=t/4),function(r){return
1+n*Math.pow(2,-10*r)*Math.sin((r-e)*Aa/t)}}function Xr(n){return
n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function $r(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
Br(n,t){n=Bo.hcl(n),t=Bo.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
G(e+i*n,r+o*n,u+a*n)+""}}function Wr(n,t){n=Bo.hsl(n),t=Bo.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
B(e+i*n,r+o*n,u+a*n)+""}}function Jr(n,t){n=Bo.lab(n),t=Bo.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
nt(e+i*n,r+o*n,u+a*n)+""}}function Gr(n,t){return t-=n,function(e){return
Math.round(n+t*e)}}function Kr(n){var
t=[n.a,n.b],e=[n.c,n.d],r=nu(t),u=Qr(t,e),i=nu(tu(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]))*qa,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*qa:0}function
Qr(n,t){return n[0]*t[0]+n[1]*t[1]}function nu(n){var t=Math.sqrt(Qr(n,n));return
t&&(n[0]/=t,n[1]/=t),t}function tu(n,t,e){return
n[0]+=e*t[0],n[1]+=e*t[1],n}function eu(n,t){var
e,r=[],u=[],i=Bo.transform(n),o=Bo.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:Tr(a[0],c[0])},{i:3,x:Tr(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:Tr(s,l)})):l&&r.push(r.pop()+"rotate("+l+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:Tr(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:Tr(g[0],p[0])},{i:e-2,x:Tr(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 ru(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
iu(n){for(var t=n.source,e=n.target,r=au(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 ou(n){for(var
t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function
au(n,t){if(n===
t)return n;for(var
e=ou(n),r=ou(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return
o}function cu(n){n.fixed|=2}function su(n){n.fixed&=-7}function
lu(n){n.fixed|=4,n.px=n.x,n.py=n.y}function fu(n){n.fixed&=-5}function hu(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&&(hu(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
gu(n,t){return
Bo.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=mu,n}function
pu(n){return n.children}function vu(n){return n.value}function du(n,t){return
t.value-n.value}function mu(n){return
Bo.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function
yu(n){return n.x}function xu(n){return n.y}function Mu(n,t,e){n.y0=t,n.y=e}f
unction _u(n){return Bo.range(n.length)}function bu(n){for(var
t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function wu(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 Su(n){return n.reduce(ku,0)}function ku(n,t){return n+t[1]}function
Eu(n,t){return Au(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function Au(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
Cu(n){return[Bo.min(n),Bo.max(n)]}function Nu(n,t){return n.parent==t.parent?1:2}function
Lu(n){var t=n.children;return t&&t.length?t[0]:n._tree.thread}function Tu(n){var
t,e=n.children;return e&&(t=e.length)?e[t-1]:n._tree.thread}function qu(n,t){var
e=n.children;if(e&&(u=e.length))for(var
r,u,i=-1;++i<u;)t(r=qu(e[i],t),n)>0&&(n=r);return n}function zu(n,t){return
n.x-t.x}function Ru(n,t){return t.x-n.x}function Du(n,t){return n.depth-t.depth}function
Pu(n,t){function e(n,r){var u=n.children;if(u&&(o=u.length))for(var
i,o,a=null,c=-1;++c<o;)i=u
[c],e(i,a),a=i;t(n,r)}e(n,null)}function Uu(n){for(var
t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i]._tree,t.prelim+=e,t.mod+=e,e+=t.shift+(r+=t.change)}function
ju(n,t,e){n=n._tree,t=t._tree;var
r=e/(t.number-n.number);n.change+=r,t.change-=r,t.shift+=e,t.prelim+=e,t.mod+=e}function
Hu(n,t,e){return n._tree.ancestor.parent==t.parent?n._tree.ancestor:e}function
Fu(n,t){return n.value-t.value}function Ou(n,t){var
e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function
Yu(n,t){n._pack_next=t,t._pack_prev=n}function Iu(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 Zu(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(Vu),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],Bu(r,u,i),t(i),Ou(r,i),r._pack_prev=i,Ou(i,u),u=r._pack_next,o=3;s>o;o++){Bu(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(Iu(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!Iu(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?Yu(r,u=a):Yu(r=c,u),o--):(Ou(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(Xu)}}function
Vu(n){n._pack_next=n._pack_prev=n}function Xu(n){delete n._pack_next,delete
n._pack_prev}function $u(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;)$u(u[i],t,e,r)}function Bu(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 Wu(n){return 1+Bo.max(n,function(n){return n.y})}function
Ju(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Gu(n){var
t=n.children;return t&&t.length?Gu
(t[0]):n}function Ku(n){var t,e=n.children;return
e&&(t=e.length)?Ku(e[t-1]):n}function
Qu(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function ni(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
ti(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function ei(n){return
n.rangeExtent?n.rangeExtent():ti(n.range())}function ri(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 ui(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
ii(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return
Math.ceil(t/n)*n}}:ls}function oi(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=Bo.bisect(n,t,1,a)-1;return i[e](u[e](t))}}func
tion ai(n,t,e,r){function u(){var
u=Math.min(n.length,t.length)>2?oi:ri,c=r?uu:ru;return
o=u(n,t,c,e),a=u(t,n,c,zr),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(Gr)},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
fi(n,t)},i.tickFormat=function(t,e){return hi(n,t,e)},i.nice=function(t){return
si(n,t),u()},i.copy=function(){return ai(n,t,e,r)},u()}function ci(n,t){return
Bo.rebind(n,t,"range","rangeRound","interpolate","clamp")}function
si(n,t){return ui(n,ii(li(n,t)[2]))}function li(n,t){null==t&&(t=10);var
e=ti(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.flo
or(e[1]/u)*u+.5*u,e[2]=u,e}function fi(n,t){return Bo.range.apply(Bo,li(n,t))}function
hi(n,t,e){var r=li(n,t);return
Bo.format(e?e.replace(ic,function(n,t,e,u,i,o,a,c,s,l){return[t,e,u,i,o,a,c,s||"."+pi(l,r),l].join("")}):",."+gi(r[2])+"f")}function
gi(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function pi(n,t){var e=gi(t[2]);return
n in fs?Math.abs(e-gi(Math.max(Math.abs(t[0]),Math.abs(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=ui(r.map(u),e?Math:gs);return n.domain(t),r=t.map(i),o},o.ticks=function(){var
n=ti(r),o=[],a=n[0],c=n[1],s=Math.floor(u(a)),l=Math.cei
l(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
hs;arguments.length<2?t=hs:"function"!=typeof t&&(t=Bo.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)},ci(o,n)}function di(n,t,e){function r(t){return n(u(t))}var
u=mi(t),i=mi(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
fi(e,n)},r.tickFormat=function(n,t){return hi(e,n,t)},r.nice=function(n){return
r.domain(si(e,n))},r.exponent=function(o){return
arguments.length?(u=mi(t=o),i=mi(1/t),n.domain(e.map(u)),r):t},r.cop
y=function(){return di(n.copy(),t,e)},ci(r,n)}function mi(n){return function(t){return
0>t?-Math.pow(-t,n):Math.pow(t,n)}}function yi(n,t){function e(e){return
o[((i.get(e)||"range"===t.t&&i.set(e,n.push(e)))-1)%o.length]}function
r(t,e){return Bo.range(n.length).map(function(n){return t+e*n})}var i,o,a;return
e.domain=function(r){if(!arguments.length)return n;n=[],i=new u;for(var
o,a=-1,c=r.length;++a<c;)i.has(o=r[a])||i.set(o,n.push(o));return
e[t.t].apply(e,t.a)},e.range=function(n){return
arguments.length?(o=n,a=0,t={t:"range",a:arguments},e):o},e.rangePoints=function(u,i){arguments.length<2&&(i=0);var
c=u[0],s=u[1],l=(s-c)/(Math.max(1,n.length-1)+i);return
o=r(n.length<2?(c+s)/2:c+l*i/2,l),a=0,t={t:"rangePoints",a:arguments},e},e.rangeBands=function(u,i,c){arguments.length<2&&(i=0),arguments.length<3&&(c=i);var
s=u[1]<u[0],l=u[s-0],f=u[1-s],h=(f-l)/(n.length-i+2*c);return
o=r(l+h*c,h),s&&o.reverse(),a=h*(1-i),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(
u,i,c){arguments.length<2&&(i=0),arguments.length<3&&(c=i);var
s=u[1]<u[0],l=u[s-0],f=u[1-s],h=Math.floor((f-l)/(n.length-i+2*c)),g=f-l-(n.length-i)*h;return
o=r(l+Math.round(g/2),h),s&&o.reverse(),a=Math.round(h*(1-i)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return
a},e.rangeExtent=function(){return ti(t.a[0])},e.copy=function(){return
yi(n,t)},e.domain(n)}function xi(n,t){function e(){var
e=0,i=t.length;for(u=[];++e<i;)u[e-1]=Bo.quantile(n,e/i);return r}function r(n){return
isNaN(n=+n)?void 0:t[Bo.bisect(u,n)]}var u;return r.domain=function(t){return
arguments.length?(n=t.filter(function(n){return!isNaN(n)}).sort(Bo.ascending),e()):n},r.range=function(n){return
arguments.length?(t=n,e()):t},r.quantiles=function(){return
u},r.invertExtent=function(e){return
e=t.indexOf(e),0>e?[0/0,0/0]:[e>0?u[e-1]:n[0],e<u.length?u[e]:n[n.length-1]]},r.copy=function(){return
xi(n,t)},e()}function Mi(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
Mi(n,t,e)},u()}function _i(n,t){function e(e){return e>=e?t[Bo.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 _i(n,t)},e}function bi(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
fi(n,t)},t.tickFormat=function(t,e){return hi(n,t,e)},t.copy=function(){return
bi(n)},t}function wi(n){return n.innerRadius}function Si(n){return n.outerRadius}function
ki(n){return n.startAngle}function Ei(n){return n.en
dAngle}function Ai(n){function t(t){function o(){s.push("M",i(n(l),a))}for(var
c,s=[],l=[],f=-1,h=t.length,g=vt(e),p=vt(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=Ve,r=Xe,u=Vt,i=Ci,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=Ms.get(n)||Ci).key,t):o},t.tension=function(n){return
arguments.length?(a=n,t):a},t}function Ci(n){return n.join("L")}function
Ni(n){return Ci(n)+"Z"}function Li(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 Ti(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 qi(n){fo
r(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 zi(n,t){return
n.length<4?Ci(n):n[1]+Pi(n.slice(1,n.length-1),Ui(n,t))}function Ri(n,t){return
n.length<3?Ci(n):n[0]+Pi((n.push(n[0]),n),Ui([n[n.length-2]].concat(n,[n[1]]),t))}function
Di(n,t){return n.length<3?Ci(n):n[0]+Pi(n,Ui(n,t))}function
Pi(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return
Ci(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 Ui(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 ji(n){if(n.length<3)return Ci(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",Yi(ws,o),",",Yi(ws,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Ii(c,o,a);return
n.pop(),c.push("L",r),c.join("")}function
Hi(n){if(n.length<4)return Ci(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(Yi(ws,i)+","+Yi(ws,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),Ii(e,i,o);return
e.join("")}function Fi(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=[Yi(ws,o),",",Yi(ws,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Ii(t,o,a);return
t.join("")}function Oi(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
ji(n)}function Yi(n,
t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function
Ii(n,t,e){n.push("C",Yi(_s,t),",",Yi(_s,e),",",Yi(bs,t),",",Yi(bs,e),",",Yi(ws,t),",",Yi(ws,e))}function
Zi(n,t){return(t[1]-n[1])/(t[0]-n[0])}function Vi(n){for(var
t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=Zi(u,i);++t<e;)r[t]=(o+(o=Zi(u=i,i=n[t+1])))/2;return
r[t]=o,r}function Xi(n){for(var
t,e,r,u,i=[],o=Vi(n),a=-1,c=n.length-1;++a<c;)t=Zi(n[a],n[a+1]),ca(t)<Na?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 $i(n){return n.length<3?Ci(n):n[0]+Pi(n,Xi(n))}function Bi(n){for(var
t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]+ys,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return
n}function Wi(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=vt(e),_=vt(u),b=e===r?function(){retu
rn g}:vt(r),w=u===i?function(){return
p}:vt(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=Ve,r=Ve,u=0,i=Xe,o=Vt,a=Ci,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=Ms.get(n)||Ci).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 Ji(n){return n.radius}function
Gi(n){return[n.x,n.y]}function Ki(n){return function(){var t=n.apply(t
his,arguments),e=t[0],r=t[1]+ys;return[e*Math.cos(r),e*Math.sin(r)]}}function Qi(){return
64}function no(){return"circle"}function to(n){var
t=Math.sqrt(n/Ea);return"M0,"+t+"A"+t+","+t+" 0 1,1
0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function
eo(n,t){return ga(n,Ns),n.id=t,n}function ro(n,t,e,r){var u=n.id;return
N(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
uo(n){return null==n&&(n=""),function(){this.textContent=n}}function
io(n,t,e,r){var
i=n.__transition__||(n.__transition__={active:0,count:0}),o=i[e];if(!o){var
a=r.time;o=i[e]={tween:new
u,time:a,ease:r.ease,delay:r.delay,duration:r.duration},++i.count,Bo.timer(function(r){function
u(r){return
i.active>e?s():(i.active=e,o.event&&o.event.start.call(n,l,t),o.tween.forEach(function(e,r){(r=r.call(n,l,t))&&v.push(r)}),Bo.timer(function(){return
p.c=c(r||1)?Vt:c,1},0,a),void 0)}function c(r){if(i.active!==e
)return s();for(var u=r/g,a=f(u),c=v.length;c>0;)v[--c].call(n,a);return
u>=1?(o.event&&o.event.end.call(n,l,t),s()):void 0}function
s(){return--i.count?delete i[e]:delete n.__transition__,1}var
l=n.__data__,f=o.ease,h=o.delay,g=o.duration,p=Ka,v=[];return
p.t=h+a,r>=h?u(r-h):(p.c=u,void 0)},0,a)}}function
oo(n,t){n.attr("transform",function(n){return"translate("+t(n)+",0)"})}function
ao(n,t){n.attr("transform",function(n){return"translate(0,"+t(n)+")"})}function
co(){this._=new
Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function
so(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 Ps(e-1)),1),e}function i(n,e){return t(n=new Ps(+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{Ps=co;var r=new
co;return
r._=n,o(r,t,e)}finally{Ps=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n
.utc=lo(n);return
c.floor=c,c.round=lo(r),c.ceil=lo(u),c.offset=lo(i),c.range=a,n}function lo(n){return
function(t,e){try{Ps=co;var r=new co;return r._=t,n(r,e)._}finally{Ps=Date}}}function
fo(n){function t(t){for(var
r,u,i,o=[],a=-1,c=0;++a<e;)37===n.charCodeAt(a)&&(o.push(n.substring(c,a)),null!=(u=tl[r=n.charAt(++a)])&&(r=n.charAt(++a)),(i=el[r])&&(r=i(t,null==u?"e"===r?"
":"0":u)),o.push(r),c=a+1);return
o.push(n.substring(c,a)),o.join("")}var e=n.length;return
t.parse=function(t){var
e={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},r=ho(e,n,t,0);if(r!=t.length)return
null;"p"in e&&(e.H=e.H%12+12*e.p);var
u=null!=e.Z&&Ps!==co,i=new(u?co:Ps);return"j"in
e?i.setFullYear(e.y,0,e.j):"w"in e&&("W"in e||"U"in
e)?(i.setFullYear(e.y,0,1),i.setFullYear(e.y,0,"W"in
e?(e.w+6)%7+7*e.W-(i.getDay()+5)%7:e.w+7*e.U-(i.getDay()+6)%7)):i.setFullYear(e.y,e.m,e.d),i.setHours(e.H+Math.floor(e.Z/100),e.M+e.Z%100,e.S,e.L),u?i._:i},t.toString=function(){return
n},t}function ho(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=rl[o
in tl?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else
if(u!=e.charCodeAt(r++))return-1}return r}function go(n){return new
RegExp("^(?:"+n.map(Bo.requote).join("|")+")","i")}function
po(n){for(var t=new u,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return
t}function vo(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 mo(n,t,e){Bs.lastIndex=0;var
r=Bs.exec(t.substring(e));return
r?(n.w=Ws.get(r[0].toLowerCase()),e+r[0].length):-1}function yo(n,t,e){Xs.lastIndex=0;var
r=Xs.exec(t.substring(e));return
r?(n.w=$s.get(r[0].toLowerCase()),e+r[0].length):-1}function xo(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function
Mo(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e));return
r?(n.U=+r[0],e+r[0].length):-1}function _o(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring
(e));return r?(n.W=+r[0],e+r[0].length):-1}function bo(n,t,e){Ks.lastIndex=0;var
r=Ks.exec(t.substring(e));return
r?(n.m=Qs.get(r[0].toLowerCase()),e+r[0].length):-1}function wo(n,t,e){Js.lastIndex=0;var
r=Js.exec(t.substring(e));return
r?(n.m=Gs.get(r[0].toLowerCase()),e+r[0].length):-1}function So(n,t,e){return
ho(n,el.c.toString(),t,e)}function ko(n,t,e){return ho(n,el.x.toString(),t,e)}function
Eo(n,t,e){return ho(n,el.X.toString(),t,e)}function Ao(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function
Co(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e,e+2));return
r?(n.y=Lo(+r[0]),e+r[0].length):-1}function
No(n,t,e){return/^[+-]\d{4}$/.test(t=t.substring(e,e+5))?(n.Z=+t,e+5):-1}function
Lo(n){return n+(n>68?1900:2e3)}function To(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function
qo(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e,e+2));return
r?(n.d=+r[0],e+r[0].leng
th):-1}function zo(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e,e+3));return
r?(n.j=+r[0],e+r[0].length):-1}function Ro(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function
Do(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e,e+2));return
r?(n.M=+r[0],e+r[0].length):-1}function Po(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function
Uo(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e,e+3));return
r?(n.L=+r[0],e+r[0].length):-1}function jo(n,t,e){var
r=il.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}function Ho(n){var
t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(ca(t)/60),u=ca(t)%60;return
e+vo(r,"0",2)+vo(u,"0",2)}function Fo(n,t,e){nl.lastIndex=0;var
r=nl.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function Oo(n){function
t(n){try{Ps=co;var t=new Ps;return t._=n,e(t)}finally{Ps=Date}}var e=fo(n);return
t.parse=function(n){try{Ps=co;var t=e.par
se(n);return t&&t._}finally{Ps=Date}},t.toString=e.toString,t}function
Yo(n){return n.toISOString()}function Io(n,t,e){function r(t){return n(t)}function
u(n,e){var r=n[1]-n[0],u=r/e,i=Bo.bisect(al,u);return
i==al.length?[t.year,li(n.map(function(n){return
n/31536e6}),e)[2]]:i?t[u/al[i-1]<al[i]/u?i-1:i]:[fl,li(n,e)[2]]}return
r.invert=function(t){return Zo(n.invert(t))},r.domain=function(t){return
arguments.length?(n.domain(t),r):n.domain().map(Zo)},r.nice=function(n,t){function
e(e){return!isNaN(e)&&!n.range(e,Zo(+e+1),t).length}var
i=r.domain(),o=ti(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return
a&&(n=a[0],t=a[1]),r.domain(ui(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Zo(t-1);return
t},ceil:function(t){for(;e(t=n.ceil(t));)t=Zo(+t+1);return
t}}:n))},r.ticks=function(n,t){var
e=ti(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],Zo(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return
e},r.copy=
function(){return Io(n.copy(),t,e)},ci(r,n)}function Zo(n){return new Date(n)}function
Vo(n){return function(t){for(var e=n.length-1,r=n[e];!r[1](t);)r=n[--e];return
r[0](t)}}function Xo(n){return JSON.parse(n.responseText)}function $o(n){var
t=Go.createRange();return
t.selectNode(Go.body),t.createContextualFragment(n.responseText)}var
Bo={version:"3.3.13"};Date.now||(Date.now=function(){return+new Date});var
Wo=[].slice,Jo=function(n){return
Wo.call(n)},Go=document,Ko=Go.documentElement,Qo=window;try{Jo(Ko.childNodes)[0].nodeType}catch(na){Jo=function(n){for(var
t=n.length,e=new Array(t);t--;)e[t]=n[t];return
e}}try{Go.createElement("div").style.setProperty("opacity",0,"")}catch(ta){var
ea=Qo.Element.prototype,ra=ea.setAttribute,ua=ea.setAttributeNS,ia=Qo.CSSStyleDeclaration.prototype,oa=ia.setProperty;ea.setAttribute=function(n,t){ra.call(this,n,t+"")},ea.setAttributeNS=function(n,t,e){ua.call(this,n,t,e+"")},ia.setProperty=function(n,t,e){oa.call(this,n,t+"",e)}}Bo.ascend
ing=function(n,t){return
t>n?-1:n>t?1:n>=t?0:0/0},Bo.descending=function(n,t){return
n>t?-1:t>n?1:t>=n?0:0/0},Bo.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},Bo.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},Bo.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]},Bo
.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},Bo.mean=function(t,e){var
r,u=t.length,i=0,o=-1,a=0;if(1===arguments.length)for(;++o<u;)n(r=t[o])&&(i+=(r-i)/++a);else
for(;++o<u;)n(r=e.call(t,t[o],o))&&(i+=(r-i)/++a);return a?i:void
0},Bo.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},Bo.median=function(t,e){return
arguments.length>1&&(t=t.map(e)),t=t.filter(n),t.length?Bo.quantile(t.sort(Bo.ascending),.5):void
0},Bo.bisector=function(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.call(t,t[i],i)<e?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;e<n.call(t,t[i],i)?u=i:r=i+1}return r}}};var
aa=Bo.bisector(function(n){return
n});Bo.bisectLeft=aa.left,Bo.bisect=Bo.bisectRight=aa.right,Bo.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},Bo.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return
r},Bo.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},Bo.zip=function(){if(!(u=arguments.length))return[];for(var
n=-1,e=Bo.min(arguments,t),r=new Array(e);++n<e
;)for(var u,i=-1,o=r[n]=new Array(u);++i<u;)o[i]=arguments[i][n];return
r},Bo.transpose=function(n){return Bo.zip.apply(Bo,n)},Bo.keys=function(n){var
t=[];for(var e in n)t.push(e);return t},Bo.values=function(n){var t=[];for(var e in
n)t.push(n[e]);return t},Bo.entries=function(n){var t=[];for(var e in
n)t.push({key:e,value:n[e]});return t},Bo.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
ca=Math.abs;Bo.range=function(n,t,r){if(arguments.length<3&&(r=1,arguments.length<2&&(t=n,n=0)),1/0===(t-n)/r)throw
new Error("infinite range");var
u,i=[],o=e(ca(r)),a=-1;if(n*=o,t*=o,r*=o,0>r)for(;(u=n+r*++a)>t;)i.push(u/o);else
for(;(u=n+r*++a)<t;)i.push(u/o);return i},Bo.map=function(n){var t=new u;if(n
instanceof u)n.forEach(function(n,e){t.set(n,e)});else for(var e in n)t.set(e,n[e]);return
t},r(u,{has:function(n){return sa+n in this},get:function(n){return this[sa+n]},set:fu
nction(n,t){return this[sa+n]=t},remove:function(n){return n=sa+n,n in
this&&delete this[n]},keys:function(){var n=[];return
this.forEach(function(t){n.push(t)}),n},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},forEach:function(n){for(var t in
this)t.charCodeAt(0)===la&&n.call(this,t.substring(1),this[t])}});var
sa="\x00",la=sa.charCodeAt(0);Bo.nest=function(){function
n(t,a,c){if(c>=o.length)return r?r.call(i,a):e?a.sort(e):a;for(var
s,l,f,h,g=-1,p=a.length,v=o[c++],d=new
u;++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>=o.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,i={},o=[],a=[];return i.map=function(t,e){return n(e
,t,0)},i.entries=function(e){return t(n(Bo.map,e,0),0)},i.key=function(n){return
o.push(n),i},i.sortKeys=function(n){return
a[o.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return
r=n,i},i},Bo.set=function(n){var t=new i;if(n)for(var
e=0,r=n.length;r>e;++e)t.add(n[e]);return t},r(i,{has:function(n){return sa+n in
this},add:function(n){return this[sa+n]=!0,n},remove:function(n){return n=sa+n,n in
this&&delete this[n]},values:function(){var n=[];return
this.forEach(function(t){n.push(t)}),n},forEach:function(n){for(var t in
this)t.charCodeAt(0)===la&&n.call(this,t.substring(1))}}),Bo.behavior={},Bo.rebind=function(n,t){for(var
e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=o(n,t,t[e]);return n};var
fa=["webkit","ms","moz","Moz","o","O"];Bo.dispatch=function(){for(var
n=new s,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=l(n);return
n},s.prototype.on=function(n,t){var
e=n.indexOf("."),r="";if(e>=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)retu
rn
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}},Bo.event=null,Bo.requote=function(n){return n.replace(ha,"\\$&")};var
ha=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ga={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var
e in t)n[e]=t[e]},pa=function(n,t){return t.querySelector(n)},va=function(n,t){return
t.querySelectorAll(n)},da=Ko[a(Ko,"matchesSelector")],ma=function(n,t){return
da.call(n,t)};"function"==typeof Sizzle&&(pa=function(n,t){return
Sizzle(n,t)[0]||null},va=function(n,t){return
Sizzle.uniqueSort(Sizzle(n,t))},ma=Sizzle.matchesSelector),Bo.selection=function(){return
_a};var ya=Bo.selection.prototype=[];ya.select=function(n){var t,e,r,u,i=[];n=v(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.p
ush(null)}return p(i)},ya.selectAll=function(n){var t,e,r=[];n=d(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=Jo(n.call(e,e.__data__,a,u))),t.parentNode=e);return
p(r)};var
xa={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3....
t=n.indexOf(":"),e=n;return
t>=0&&(e=n.substring(0,t),n=n.substring(t+1)),xa.hasOwnProperty(e)?{space:xa[e],local:n}:n}},ya.attr=function(n,t){if(arguments.length<2){if("string"==typeof
n){var e=this.node();return
n=Bo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in
n)this.each(m(t,n[t]));return this}return
this.each(m(n,t))},ya.classed=function(n,t){if(arguments.length<2){if("string"==typeof
n){var
e=this.node(),r=(n=M(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))ret
urn!1}else
for(t=e.getAttribute("class");++u<r;)if(!x(n[u]).test(t))return!1;return!0}for(t
in n)this.each(_(t,n[t]));return this}return
this.each(_(n,t))},ya.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(w(e,n[e],t));return
this}if(2>r)return
Qo.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return
this.each(w(n,t,e))},ya.property=function(n,t){if(arguments.length<2){if("string"==typeof
n)return this.node()[n];for(t in n)this.each(S(t,n[t]));return this}return
this.each(S(n,t))},ya.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},ya.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=""}:f
unction(){this.innerHTML=n}):this.node().innerHTML},ya.append=function(n){return
n=k(n),this.select(function(){return
this.appendChild(n.apply(this,arguments))})},ya.insert=function(n,t){return
n=k(n),t=v(t),this.select(function(){return
this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},ya.remove=function(){return
this.each(function(){var
n=this.parentNode;n&&n.removeChild(this)})},ya.data=function(n,t){function
e(n,e){var r,i,o,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 u,y=new
u,x=[];for(r=-1;++r<a;)d=t.call(i=n[r],i.__data__,r),m.has(d)?v[r]=i:m.set(d,i),x.push(d);for(r=-1;++r<f;)d=t.call(e,o=e[r],r),(i=m.get(d))?(g[r]=i,i.__data__=o):y.has(d)||(p[r]=E(o)),y.set(d,o),m.remove(d);for(r=-1;++r<a;)m.has(x[r])&&(v[r]=n[r])}else{for(r=-1;++r<h;)i=n[r],o=e[r],i?(i.__data__=o,g[r]=i):p[r]=E(o);for(;f>r;++r)p[r]=E(e[r]);for(;a>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.par
entNode,c.push(p),s.push(g),l.push(v)}var
r,i,o=-1,a=this.length;if(!arguments.length){for(n=new
Array(a=(r=this[0]).length);++o<a;)(i=r[o])&&(n[o]=i.__data__);return n}var
c=L([]),s=p([]),l=p([]);if("function"==typeof
n)for(;++o<a;)e(r=this[o],n.call(r,r.parentNode.__data__,o));else
for(;++o<a;)e(r=this[o],n);return s.enter=function(){return c},s.exit=function(){return
l},s},ya.datum=function(n){return
arguments.length?this.property("__data__",n):this.property("__data__")},ya.filter=function(n){var
t,e,r,u=[];"function"!=typeof n&&(n=A(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
p(u)},ya.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},ya.sort=function(n){n=C.apply(this,arguments);for(var
t=-1,e=this.length;++t<e;)this
[t].sort(n);return this.order()},ya.each=function(n){return
N(this,function(t,e,r){n.call(t,t.__data__,e,r)})},ya.call=function(n){var
t=Jo(arguments);return
n.apply(t[0]=this,t),this},ya.empty=function(){return!this.node()},ya.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},ya.size=function(){var n=0;return
this.each(function(){++n}),n};var
Ma=[];Bo.selection.enter=L,Bo.selection.enter.prototype=Ma,Ma.append=ya.append,Ma.empty=ya.empty,Ma.node=ya.node,Ma.call=ya.call,Ma.size=ya.size,Ma.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
p(o)},Ma.insert=function(n,t){return
arguments.length<2&&(t=T(this)),ya.insert.call(this,n,t)},ya.transition=function(){for(var
n,t,e=ks||++Ls,r=[],u=E
s||{time:Date.now(),ease:Fr,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])&&io(t,c,e,u),n.push(t)}return
eo(r,e)},ya.interrupt=function(){return this.each(q)},Bo.select=function(n){var
t=["string"==typeof n?pa(n,Go):n];return
t.parentNode=Ko,p([t])},Bo.selectAll=function(n){var t=Jo("string"==typeof
n?va(n,Go):n);return t.parentNode=Ko,p([t])};var
_a=Bo.select(Ko);ya.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(z(e,n[e],t));return
this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return
this.each(z(n,t,e))};var
ba=Bo.map({mouseenter:"mouseover",mouseleave:"mouseout"});ba.forEach(function(n){"on"+n
in Go&&ba.remove(n)});var wa="onselectstart"in
Go?null:a(Ko.style,"userSelect"),Sa=0;Bo.mouse=function(n){return U(n,h())};var
ka=/WebKit/.test(Qo.navigator.userAgent)?-1:0;Bo.touches=function(n,t){return
arguments.length<2&&(t=h().touches),t?Jo(t).map(f
unction(t){var e=U(n,t);return
e.identifier=t.identifier,e}):[]},Bo.behavior.drag=function(){function
n(){this.on("mousedown.drag",o).on("touchstart.drag",a)}function
t(){return Bo.event.changedTouches[0].identifier}function e(n,t){return
Bo.touches(n).filter(function(n){return n.identifier===t})[0]}function r(n,t,e,r){return
function(){function o(){var
n=t(l,g),e=n[0]-v[0],r=n[1]-v[1];d|=e|r,v=n,f({type:"drag",x:n[0]+c[0],y:n[1]+c[1],dx:e,dy:r})}function
a(){m.on(e+"."+p,null).on(r+"."+p,null),y(d&&Bo.event.target===h),f({type:"dragend"})}var
c,s=this,l=s.parentNode,f=u.of(s,arguments),h=Bo.event.target,g=n(),p=null==g?"drag":"drag-"+g,v=t(l,g),d=0,m=Bo.select(Qo).on(e+"."+p,o).on(r+"."+p,a),y=P();i?(c=i.apply(s,arguments),c=[c.x-v[0],c.y-v[1]]):c=[0,0],f({type:"dragstart"})}}var
u=g(n,"drag","dragstart","dragend"),i=null,o=r(c,Bo.mouse,"mousemove","mouseup"),a=r(t,e,"touchmove","touchend");return
n.origin=function(t){return arguments.length?(i=t,n):i},Bo.rebind(n,u,"on")};
var
Ea=Math.PI,Aa=2*Ea,Ca=Ea/2,Na=1e-6,La=Na*Na,Ta=Ea/180,qa=180/Ea,za=Math.SQRT2,Ra=2,Da=4;Bo.interpolateZoom=function(n,t){function
e(n){var t=n*y;if(m){var
e=Y(v),o=i/(Ra*h)*(e*I(za*t+v)-O(v));return[r+o*s,u+o*l,i*e/Y(za*t+v)]}return[r+n*s,u+n*l,i*Math.exp(za*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+Da*f)/(2*i*Ra*h),p=(c*c-i*i-Da*f)/(2*c*Ra*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))/za;return
e.duration=1e3*y,e},Bo.behavior.zoom=function(){function
n(n){n.on(A,s).on(ja+".zoom",h).on(C,p).on("dblclick.zoom",v).on(L,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(M.range().map(function(n){return(n-S.x)/S.k}).map(M.invert)),w&&w.domain(b.range().map(function(n){return(n-S.y)/S.k}).map(b.inve
rt))}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(Bo.mouse(r),h),a(i)}function
e(){f.on(C,Qo===r?p:null).on(N,null),g(l&&Bo.event.target===s),c(i)}var
r=this,i=T.of(r,arguments),s=Bo.event.target,l=0,f=Bo.select(Qo).on(C,n).on(N,e),h=t(Bo.mouse(r)),g=P();q.call(r),o(i)}function
l(){function n(){var n=Bo.touches(p);return g=S.k,n.forEach(function(n){n.identifier in
d&&(d[n.identifier]=t(n))}),n}function e(){for(var
t=Bo.event.changedTouches,e=0,i=t.length;i>e;++e)d[t[e].identifier]=null;var
o=n(),c=Date.now();if(1===o.length){if(500>c-x){var
s=o[0],l=d[s.identifier];r(2*S.k),u(s,l),f(),a(v)}x=c}else if(o.length>1){var
s=o[0],h=o[1],g=s[0]-h[0],p=s[1]-h[1];m=g*g+p*p}}function i(){for(var
n,t,e,i,o=Bo.touches(p),c=0,s=o.length;s>c;++c,i=null)if(e=o[c],i=d[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=m&&Math.sqrt(l/m);n=[(n[
0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+i[0])/2,(t[1]+i[1])/2],r(f*g)}x=null,u(n,t),a(v)}function
h(){if(Bo.event.touches.length){for(var
t=Bo.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var u in
d)return void n()}b.on(M,null).on(_,null),w.on(A,s).on(L,l),k(),c(v)}var
g,p=this,v=T.of(p,arguments),d={},m=0,y=Bo.event.changedTouches[0].identifier,M="touchmove.zoom-"+y,_="touchend.zoom-"+y,b=Bo.select(Qo).on(M,i).on(_,h),w=Bo.select(p).on(A,null).on(L,e),k=P();q.call(p),e(),o(v)}function
h(){var
n=T.of(this,arguments);y?clearTimeout(y):(q.call(this),o(n)),y=setTimeout(function(){y=null,c(n)},50),f();var
e=m||Bo.mouse(this);d||(d=t(e)),r(Math.pow(2,.002*Pa())*S.k),u(e,d),a(n)}function
p(){d=null}function v(){var
n=T.of(this,arguments),e=Bo.mouse(this),i=t(e),s=Math.log(S.k)/Math.LN2;o(n),r(Math.pow(2,Bo.event.shiftKey?Math.ceil(s)-1:Math.floor(s)+1)),u(e,i),a(n),c(n)}var
d,m,y,x,M,_,b,w,S={x:0,y:0,k:1},k=[960,500],E=Ua,A="mousedown.zoom",C="mousemove.zoo
m",N="mouseup.zoom",L="touchstart.zoom",T=g(n,"zoomstart","zoom","zoomend");return
n.event=function(n){n.each(function(){var
n=T.of(this,arguments),t=S;ks?Bo.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=Bo.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?Ua:[+t[0],+t[1]],n):E},n.center=function(t){return
arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return
arguments.length?(k=t&&[+t[0],+t[1]],n):k},n.x=function(t){return arguments.l
ength?(_=t,M=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},Bo.rebind(n,T,"on")};var
Pa,Ua=[0,1/0],ja="onwheel"in
Go?(Pa=function(){return-Bo.event.deltaY*(Bo.event.deltaMode?120:1)},"wheel"):"onmousewheel"in
Go?(Pa=function(){return
Bo.event.wheelDelta},"mousewheel"):(Pa=function(){return-Bo.event.detail},"MozMousePixelScroll");V.prototype.toString=function(){return
this.rgb()+""},Bo.hsl=function(n,t,e){return 1===arguments.length?n instanceof
$?X(n.h,n.s,n.l):lt(""+n,ft,X):X(+n,+t,+e)};var Ha=$.prototype=new
V;Ha.brighter=function(n){return
n=Math.pow(.7,arguments.length?n:1),X(this.h,this.s,this.l/n)},Ha.darker=function(n){return
n=Math.pow(.7,arguments.length?n:1),X(this.h,this.s,n*this.l)},Ha.rgb=function(){return
B(this.h,this.s,this.l)},Bo.hcl=function(n,t,e){return 1===arguments.length?n instanceof
J?W(n.h,n.c,n.l):n instanceof
Q?tt(n.l,n.a,n.b):tt((n=ht((n=Bo.rgb(n)).r,n.g,n.b)).l,n.a,n.b):W(+n,+t,+e)};va
r Fa=J.prototype=new V;Fa.brighter=function(n){return
W(this.h,this.c,Math.min(100,this.l+Oa*(arguments.length?n:1)))},Fa.darker=function(n){return
W(this.h,this.c,Math.max(0,this.l-Oa*(arguments.length?n:1)))},Fa.rgb=function(){return
G(this.h,this.c,this.l).rgb()},Bo.lab=function(n,t,e){return 1===arguments.length?n
instanceof Q?K(n.l,n.a,n.b):n instanceof
J?G(n.l,n.c,n.h):ht((n=Bo.rgb(n)).r,n.g,n.b):K(+n,+t,+e)};var
Oa=18,Ya=.95047,Ia=1,Za=1.08883,Va=Q.prototype=new V;Va.brighter=function(n){return
K(Math.min(100,this.l+Oa*(arguments.length?n:1)),this.a,this.b)},Va.darker=function(n){return
K(Math.max(0,this.l-Oa*(arguments.length?n:1)),this.a,this.b)},Va.rgb=function(){return
nt(this.l,this.a,this.b)},Bo.rgb=function(n,t,e){return 1===arguments.length?n instanceof
ct?at(n.r,n.g,n.b):lt(""+n,at,B):at(~~n,~~t,~~e)};var Xa=ct.prototype=new
V;Xa.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),at(Math.min(255,~~(t/n)),Math.min(255,~~(e/n)),Math.min(255,~~(r/n)))):at(u,u,u)},Xa.darker=function(n){return
n=Math.pow(.7,arguments.length?n:1),at(~~(n*this.r),~~(n*this.g),~~(n*this.b))},Xa.hsl=function(){return
ft(this.r,this.g,this.b)},Xa.toString=function(){return"#"+st(this.r)+st(this.g)+st(this.b)};var
$a=Bo.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,darkslateg
ray: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,medium
orchid: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,whitesm
oke:16119285,yellow:16776960,yellowgreen:10145074});$a.forEach(function(n,t){$a.set(n,it(t))}),Bo.functor=vt,Bo.xhr=mt(dt),Bo.dsv=function(n,t){function
e(n,e,i){arguments.length<3&&(i=e,e=null);var o=yt(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 o(t){return t.map(a).join(n)}function a(n){return
c.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var
c=new RegExp('["'+n+"\n]"),s=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>=c)return o;if(u)return
u=!1,i;var t=l;if(34===n.charCodeAt(t)){for(var
e=t;e++<c;)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(;c>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!==s)continue;return
n.substring(t,l-a)}return n.substring(t)}for(var
r,u,i={},o={},a=[],c=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
i,u=[];return t.forEach(function(n){for(var t in
n)r.has(t)||u.push(r.add(t))}),[u.map(a).join(n)].concat(t.map(function(t){return
u.map(function(n){return
a(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return
n.map(o).join("\n")},e},Bo.csv=Bo.dsv(",","text/csv"),Bo.tsv=Bo.dsv(" ","text/tab-separated-values");var
Ba,Wa,Ja,Ga,Ka,Qa=Qo[a(Qo,"requestAnimationFrame")]||function(n){setTimeout(n,17)};Bo.timer=function(n,t,e){var
r=argumen
ts.length;2>r&&(t=0),3>r&&(e=Date.now());var
u=e+t,i={c:n,t:u,f:!1,n:null};Wa?Wa.n=i:Ba=i,Wa=i,Ja||(Ga=clearTimeout(Ga),Ja=1,Qa(Mt))},Bo.timer.flush=function(){_t(),bt()};var
nc=".",tc=",",ec=[3,3],rc="$",uc=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(wt);Bo.formatPrefix=function(n,t){var
e=0;return
n&&(0>n&&(n*=-1),t&&(n=Bo.round(n,St(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((0>=e?e+1:e-1)/3)))),uc[8+e/3]},Bo.round=function(n,t){return
t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)},Bo.format=function(n){var
t=ic.exec(n),e=t[1]||"
",r=t[2]||">",u=t[3]||"",i=t[4]||"",o=t[5],a=+t[6],c=t[7],s=t[8],l=t[9],f=1,h="",g=!1;switch(s&&(s=+s.substring(1)),(o||"0"===e&&"="===r)&&(o=e="0",r="=",c&&(a-=Math.floor((a-1)/4))),l){case"n":c=!0,l="g";break;case"%":f=100,h="%",l="f";break;case"p":f=100,h="%",l="r";break;case"b":case"o":case"x":case"X":"#"===i&&(i="0"+l.toLowerCase());case"c":case"d":g=!0,s=0;
break;case"s":f=-1,l="r"}"#"===i?i="":"$"===i&&(i=rc),"r"!=l||s||(l="g"),null!=s&&("g"==l?s=Math.max(1,Math.min(21,s)):("e"==l||"f"==l)&&(s=Math.max(0,Math.min(20,s)))),l=oc.get(l)||kt;var
p=o&&c;return function(n){if(g&&n%1)return"";var
t=0>n||0===n&&0>1/n?(n=-n,"-"):u;if(0>f){var
v=Bo.formatPrefix(n,s);n=v.scale(n),h=v.symbol}else n*=f;n=l(n,s);var
d=n.lastIndexOf("."),m=0>d?n:n.substring(0,d),y=0>d?"":nc+n.substring(d+1);!o&&c&&(m=ac(m));var
x=i.length+m.length+y.length+(p?0:t.length),M=a>x?new
Array(x=a-x+1).join(e):"";return
p&&(m=ac(M+m)),t+=i,n=m+y,("<"===r?t+n+M:">"===r?M+t+n:"^"===r?M.substring(0,x>>=1)+t+n+M.substring(x):t+(p?n:M+n))+h}};var
ic=/(?:([^{])?([<>=^]))?([+\-
])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,oc=Bo.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=Bo.round(n,St(n,t))).toFixed(Math.max(0,Math.min(20,St(n*(1+1e-15),t))))}}),ac=dt;if(ec){var
cc=ec.length;ac=function(n){for(var
t=n.length,e=[],r=0,u=ec[0];t>0&&u>0;)e.push(n.substring(t-=u,t+u)),u=ec[r=(r+1)%cc];return
e.reverse().join(tc)}}Bo.geo={},Et.prototype={s:0,t:0,add:function(n){At(n,this.t,sc),At(sc.s,this.s,this),this.s?this.t+=sc.t:this.s=sc.t},reset:function(){this.s=this.t=0},valueOf:function(){return
this.s}};var sc=new
Et;Bo.geo.stream=function(n,t){n&&lc.hasOwnProperty(n.type)?lc[n.type](n,t):Ct(n,t)};var
lc={Feature:function(n,t){Ct(n.geometry,t)},FeatureCollection:function(n,t){for(var
e=n.features,r=-1,u=e.length;++r<u;)Ct(e[r].geometry,t)}},fc={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])},LineSt
ring:function(n,t){Nt(n.coordinates,t,0)},MultiLineString:function(n,t){for(var
e=n.coordinates,r=-1,u=e.length;++r<u;)Nt(e[r],t,0)},Polygon:function(n,t){Lt(n.coordinates,t)},MultiPolygon:function(n,t){for(var
e=n.coordinates,r=-1,u=e.length;++r<u;)Lt(e[r],t)},GeometryCollection:function(n,t){for(var
e=n.geometries,r=-1,u=e.length;++r<u;)Ct(e[r],t)}};Bo.geo.area=function(n){return
hc=0,Bo.geo.stream(n,pc),hc};var hc,gc=new
Et,pc={sphere:function(){hc+=4*Ea},point:c,lineStart:c,lineEnd:c,polygonStart:function(){gc.reset(),pc.lineStart=Tt},polygonEnd:function(){var
n=2*gc;hc+=0>n?4*Ea+n:n,pc.lineStart=pc.lineEnd=pc.point=c}};Bo.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=qt([t*Ta,e*Ta]);if(m){var u=Rt(m,r),i=[u[1],-u[0],0],o=Rt(i,u);Ut(o),o=jt(o);var
c=t-p,s=c>0?1:-1,v=o[0]*qa*s,d=ca(c)>180;if(d^(v>s*p&&s*t>v)){var
y=o[1]*qa;y>g&&(g=y)}else
if(v=(v+360)%360-180,d^(v>s*p&&s*t>v)){var
y=-o[1]*qa;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+=ca(r)>180?r+(r>0?360:-360):r}else
v=n,d=e;pc.point(n,e),t(n,e)}function i(){pc.lineStart()}function
o(){u(v,d),pc.lineEnd(),ca(y)>Na&&(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,pc.polygonStart()},polygonEnd:function(){pc.polygonEnd(),_.point=n,_.lineStart=e,_.lineEnd=r,0>gc?(l=-(h=180),f=-(g=90)):y>Na?g=90:-Na>y&&(f=-90),M[0]=l,M[1]=h}};return
function(n){g=h=-(l=f=1/0),x=[],Bo.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]]}}(),Bo.geo.centroid=function(n){vc=dc=mc=yc=xc=Mc=_c=bc=wc=Sc=kc=0,Bo.geo.stream(n,Ec);var
t=wc,e=Sc,r=kc,u=t*t+e*e+r*r;return
La>u&&(t=Mc,e=_c,r=bc,Na>dc&&(t=mc,e=yc,r=xc),u=t*t+e*e+r*r,La>u)?[0/0,0/0]:[Math.atan2(e,t)*qa,F(r/Math.sqrt(u))*qa]};var
vc,dc,mc,yc,xc,Mc,_c,bc,wc,Sc,kc,Ec={sphere:c,point:Ft,lineStart:Yt,lineEnd:It,polygonStart:function(){Ec.lineStart=Zt},polygonEnd:function(){Ec.lineStart=Yt}},Ac=Wt(Vt,ne,ee,[-Ea,-Ea/2]),Cc=1e9;Bo.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=ie(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]])},(Bo.geo.conicEqualArea=function(){return
ae(ce)}).raw=ce,Bo.geo.albers=function(){return
Bo.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},Bo.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=Bo.geo.albers(),o=Bo.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=Bo.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+Na,f+.12*s+Na],[l-.214*s-Na,f+.234*s-Na]]).stream(c).point,u=a.translate([l-.205*s,f+.212*s]).clipExtent([[l-.214*s+Na,f+.166*s+Na],[l-.115*s-Na,f+.234*s-Na]]).stream(c).point,n},n.scale(1070)};var
Nc,Lc,Tc,qc,zc,Rc,Dc={point:c,lineStart:c,lineEnd:c,polygonStart:function(){Lc=0,Dc.lineStart=se},polygonEnd:function(){Dc.lineStart=Dc.l
ineEnd=Dc.point=c,Nc+=ca(Lc/2)}},Pc={point:le,lineStart:c,lineEnd:c,polygonStart:c,polygonEnd:c},Uc={point:ge,lineStart:pe,lineEnd:ve,polygonStart:function(){Uc.lineStart=de},polygonEnd:function(){Uc.point=ge,Uc.lineStart=pe,Uc.lineEnd=ve}};Bo.geo.path=function(){function
n(n){return n&&("function"==typeof
a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),Bo.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
Nc=0,Bo.geo.stream(n,u(Dc)),Nc},n.centroid=function(n){return
mc=yc=xc=Mc=_c=bc=wc=Sc=kc=0,Bo.geo.stream(n,u(Uc)),kc?[wc/kc,Sc/kc]:bc?[Mc/bc,_c/bc]:xc?[mc/xc,yc/xc]:[0/0,0/0]},n.bounds=function(n){return
zc=Rc=-(Tc=qc=1/0),Bo.geo.stream(n,u(Pc)),[[Tc,qc],[zc,Rc]]},n.projection=function(n){return
arguments.length?(u=(e=n)?n.stream||xe(n):dt,t()):e},n.context=function(n){return
arguments.length?(i=null==(r=n)?new fe:new me(n),"function"!=typeof
a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){ret
urn arguments.length?(a="function"==typeof
t?t:(i.pointRadius(+t),+t),n):a},n.projection(Bo.geo.albersUsa()).context(null)},Bo.geo.transform=function(n){return{stream:function(t){var
e=new Me(t);for(var r in n)e[r]=n[r];return
e}}},Me.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()}},Bo.geo.projection=be,Bo.geo.projectionMutator=we,(Bo.geo.equirectangular=function(){return
be(ke)}).raw=ke.invert=ke,Bo.geo.rotation=function(n){function t(t){return
t=n(t[0]*Ta,t[1]*Ta),t[0]*=qa,t[1]*=qa,t}return
n=Ae(n[0]%360*Ta,n[1]*Ta,n.length>2?n[2]*Ta:0),t.invert=function(t){return
t=n.invert(t[0]*Ta,t[1]*Ta),t[0]*=qa,t[1]*=qa,t},t},Ee.invert=ke,Bo.geo.circle=function(){function
n(){var n="function"==typeof
r?r.apply(this,arguments):r,t=Ae(-n[0]*Ta,-n[1]*Ta,0).invert,u=[];return
e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=qa,n[1]*=qa}}),{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=Te((t=+r)*Ta,u*Ta),n):t},n.precision=function(r){return
arguments.length?(e=Te(t*Ta,(u=+r)*Ta),n):u},n.angle(90)},Bo.g
eo.distance=function(n,t){var
e,r=(t[0]-n[0])*Ta,u=n[1]*Ta,i=t[1]*Ta,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)},Bo.geo.graticule=function(){function
n(){return{type:"MultiLineString",coordinates:t()}}function t(){return
Bo.range(Math.ceil(i/d)*d,u,d).map(h).concat(Bo.range(Math.ceil(s/m)*m,c,m).map(g)).concat(Bo.range(Math.ceil(r/p)*p,e,p).filter(function(n){return
ca(n%d)>Na}).map(l)).concat(Bo.range(Math.ceil(a/v)*v,o,v).filter(function(n){return
ca(n%m)>Na}).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){ret
urn
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=ze(a,o,90),f=Re(r,e,y),h=ze(s,c,90),g=Re(i,u,y),n):y},n.majorExtent([[-180,-90+Na],[180,90-Na]]).minorExtent([[-180,-80-Na],[180,80+Na]])},Bo.geo.greatArc=function(){function
n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var
t,e,r=De,u=Pe;return n.distance=function(){return
Bo.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},Bo.geo.interpolate=function(n,t){return
Ue(n[0]*Ta,n[1]*Ta,t[0]*Ta,t[1]*Ta)},Bo.geo.length=function(n){return
jc=0,Bo.geo.stream(n,Hc),jc};var
jc,Hc={sphere:c,point:c,lineStart:je,lineEnd:c,polygonStart:c,polygonEnd:c},Fc=He(function(n){return
Math.sqrt(2/(1+n))},function(n){return
2*Math.asin(n/2)});(Bo.geo.azimuthalEqualArea=function(){return be(Fc)}).raw=Fc;var
Oc=He(function(n){var t=Math.acos(n);return
t&&t/Math.sin(t)},dt);(Bo.geo.azimuthalEquidistant=function(){return
be(Oc)}).raw=Oc,(Bo.geo.conicConformal=function(){return
ae(Fe)}).raw=Fe,(Bo.geo.conicEquidistant=function(){return ae(Oe)}).raw=Oe;var
Yc=He(function(n){return 1/n},Math.atan);(Bo.geo.gnomonic=function(){return
be(Yc)}).raw=Yc,Ye.invert=function(n,t){return[n,2*Math.atan(Math.exp
(t))-Ca]},(Bo.geo.mercator=function(){return Ie(Ye)}).raw=Ye;var Ic=He(function(){return
1},Math.asin);(Bo.geo.orthographic=function(){return be(Ic)}).raw=Ic;var
Zc=He(function(n){return 1/(1+n)},function(n){return
2*Math.atan(n)});(Bo.geo.stereographic=function(){return
be(Zc)}).raw=Zc,Ze.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ca]},(Bo.geo.transverseMercator=function(){var
n=Ie(Ze),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])},n.rotate([0,0])}).raw=Ze,Bo.geom={},Bo.geom.hull=function(n){function
t(n){if(n.length<3)return[];var
t,u,i,o,a,c,s,l,f,h,g,p,v=vt(e),d=vt(r),m=n.length,y=m-1,x=[],M=[],_=0;if(v===Ve&&r===Xe)t=n;else
for(i=0,t=[];m>i;++i)t.push([+v.call(this,u=n[i],i),+d.call(this,u,i)]);for(i=1;m>i;++i)(t[i][1]<t[_][1]||t[i][1]==t[_][1]&&t[i][0]<t[_][0])&&(_=i);for(i=0;m>i;++i)i!==_&&(c=t[i][1]-t[_][1],a=t
[i][0]-t[_][0],x.push({angle:Math.atan2(c,a),index:i}));for(x.sort(function(n,t){return
n.angle-t.angle}),g=x[0].angle,h=x[0].index,f=0,i=1;y>i;++i){if(o=x[i].index,g==x[i].angle){if(a=t[h][0]-t[_][0],c=t[h][1]-t[_][1],s=t[o][0]-t[_][0],l=t[o][1]-t[_][1],a*a+c*c>=s*s+l*l){x[i].index=-1;continue}x[f].index=-1}g=x[i].angle,f=i,h=o}for(M.push(_),i=0,o=0;2>i;++o)x[o].index>-1&&(M.push(x[o].index),i++);for(p=M.length;y>o;++o)if(!(x[o].index<0)){for(;!$e(M[p-2],M[p-1],x[o].index,t);)--p;M[p++]=x[o].index}var
b=[];for(i=p-1;i>=0;--i)b.push(n[M[i]]);return b}var e=Ve,r=Xe;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)},Bo.geom.polygon=function(n){return ga(n,Vc),n};var
Vc=Bo.geom.polygon.prototype=[];Vc.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},Vc.centroid=function(n){var
t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(argu
ments.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]},Vc.clip=function(n){for(var
t,e,r,u,i,o,a=Je(n),c=-1,s=this.length-Je(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],Be(o,l,u)?(Be(i,l,u)||n.push(We(i,o,l,u)),n.push(o)):Be(i,l,u)&&n.push(We(i,o,l,u)),i=o;a&&n.push(n[0]),l=u}return
n};var Xc,$c,Bc,Wc,Jc,Gc=[],Kc=[];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(or),t.length},dr.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}},mr.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=_r(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&&(xr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,Mr(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(Mr(this,e),n=e,e=n.U),e.C=!1,r.C=!0,xr(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?_r(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,xr(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,Mr(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,xr(this,u),n=this._;break}}else
if(t=u.L,t.C&&(t.C=!1,u.C=!0,Mr(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,xr(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,Mr(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},Bo.geom.voronoi=functi
on(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
br(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)/Na)*Na,y:Math.round(o(n,t)/Na)*Na,i:t}})}var
r=Ve,u=Xe,i=r,o=u,a=Qc;return n?t(n):(t.links=function(n){return
br(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 br(e(n)).cells.forEach(function(e,r){for(var
u,i,o=e.site,a=e.edges.sort(or),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&&Sr(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return
arguments.length?(i=vt(r=n),t):r},t.y=function(n){return
arguments.length?(o=vt(u=n),t):u},t.clipExtent=fu
nction(n){return
arguments.length?(a=null==n?Qc:n,t):a===Qc?null:a},t.size=function(n){return
arguments.length?t.clipExtent(n&&[[0,0],n]):a===Qc?null:a&&a[1]},t)};var
Qc=[[-1e6,-1e6],[1e6,1e6]];Bo.geom.delaunay=function(n){return
Bo.geom.voronoi().triangles(n)},Bo.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(ca(c-e)+ca(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]=Ar()),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=vt(a),M=vt(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=Ar();if(k.add=function(n){i(k,n,+x(n,++g),+M(n,g),v,d,m,y)},k.visit=function(n){Cr(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=Ve,c=Xe;return(o=arguments.length)?(a=kr,c=Er,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)},Bo.interpolateRgb=Nr,Bo.interpolateObject=Lr,Bo.interpolateNumber=Tr,Bo.interpolateString=qr;var
ns=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;Bo.interpolate=zr,Bo.interpolators=[function(n,t){var
e=typeof t;return("strin
g"===e?$a.has(t)||/^(#|rgb\(|hsl\()/.test(t)?Nr:qr:t instanceof
V?Nr:"object"===e?Array.isArray(t)?Rr:Lr:Tr)(n,t)}],Bo.interpolateArray=Rr;var
ts=function(){return dt},es=Bo.map({linear:ts,poly:Or,quad:function(){return
jr},cubic:function(){return Hr},sin:function(){return Yr},exp:function(){return
Ir},circle:function(){return Zr},elastic:Vr,back:Xr,bounce:function(){return
$r}}),rs=Bo.map({"in":dt,out:Pr,"in-out":Ur,"out-in":function(n){return
Ur(Pr(n))}});Bo.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=es.get(e)||ts,r=rs.get(r)||dt,Dr(r(e.apply(null,Wo.call(arguments,1))))},Bo.interpolateHcl=Br,Bo.interpolateHsl=Wr,Bo.interpolateLab=Jr,Bo.interpolateRound=Gr,Bo.transform=function(n){var
t=Go.createElementNS(Bo.ns.prefix.svg,"g");return(Bo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var
e=t.transform.baseVal.consolidate()}return new
Kr(e?e.matrix:us)})(n)},Kr.prototype.toString=function(){return"tr
anslate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var
us={a:1,b:0,c:0,d:1,e:0,f:0};Bo.interpolateTransform=eu,Bo.layout={},Bo.layout.bundle=function(){return
function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(iu(n[e]));return
t}},Bo.layout.chord=function(){function n(){var
n,s,f,h,g,p={},v=[],d=Bo.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(Bo.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=(Aa-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},Bo.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=1/Math.sqrt(i*i+o*o);if(v>(u-e)*a){var c=t.charge*a*a;return
n.px-=i*c,n.py-=o*c,!0}if(t.point&&isFinite(a)){var
c=t.pointCharge*a*a;n.px-=i*c,n.py-=o*c}}return!t.charge}}function
t(n){n.px=Bo.event.x,n.py=Bo.event.y,a.resume()}var
e,r,u,i,o,a={},c=Bo.dispatch("start","tick","end"),s=[1,1],l=.9,f=is,h=os,g=-30,p=.1,v=.8,d=[],m=[];re
turn a.tick=function(){if((r*=.99)<.005)return
c.end({type:"end",alpha:r=0}),!0;var
t,e,a,f,h,v,y,x,M,_=d.length,b=m.length;for(e=0;b>e;++e)a=m[e],f=a.source,h=a.target,x=h.x-f.x,M=h.y-f.y,(v=x*x+M*M)&&(v=r*i[e]*((v=Math.sqrt(v))-u[e])/v,x*=v,M*=v,h.x-=x*(y=f.weight/(h.weight+f.weight)),h.y-=M*y,f.x+=x*(y=1-y),f.y+=M*y);if((y=r*p)&&(x=s[0]/2,M=s[1]/2,e=-1,y))for(;++e<_;)a=d[e],a.x+=(x-a.x)*y,a.y+=(M-a.y)*y;if(g)for(hu(t=Bo.geom.quadtree(d),r,o),e=-1;++e<_;)(a=d[e]).fixed||t.visit(n(a));for(e=-1;++e<_;)a=d[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?(d=n,a):d},a.links=function(n){return
arguments.length?(m=n,a):m},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.gravity=function(n){return
arguments.length?(p=+n,a):p},a.theta=function(n){return
arguments.length?(v=+n,a):v},a.alpha=function(n){return
arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),Bo.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=m[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=d.length,l=m.length,p=s[0],v=s[1];for(t=0;c>t;++t)(r=d[t]).index=t,r.weight=0;for(t=0;l>t;++t)r=m[t],"number"==typeof
r.source&&(r.source=d[r.source]),"number"==typeof
r.target&&(r.target=d[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=d[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.p
x=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,m[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,m[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,d[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=Bo.behavior.drag().origin(dt).on("dragstart.force",cu).on("drag.force",t).on("dragend.force",su)),arguments.length?(this.on("mouseover.force",lu).on("mouseout.force",fu).call(e),void
0):e},Bo.rebind(a,c,"on")};var
is=20,os=1;Bo.layout.hierarchy=function(){function n(t,o,a){var
c=u.call(e,t,o);if(t.depth=o,a.push(t),c&&(s=c.length)){for(var
s,l,f=-1,h=t.children=new
Array(s),g=0,p=o+1;++f<s;)l=h[f]=n(c[f],p,a),l.parent=t,g+=l.value;r&&h.sort(r),i&&(t.value=g)}else
delete t.children,i&&(t.value=+i.call(e,t,o)||0);return t}function
t(n,r){var u=n.children,o=0;if(u&&(a=u.length))for(var
a,c=-1,s=r+1;++c<a;)o+=t(u[c],s);else i&&(o=+i.call(e,n,r)||0);return
i&&(n.value=o),o}function e(t){var e=[];return n(t,0,e),e}var
r=du,u=pu,i=vu;return e.sort=function(n){return
arguments.length?(r=n,e):r},e.children=function(n){return
arguments.length?(u=n,e):u},e.value=function(n){return
arguments.length?(i=n,e):i},e.revalue=function(n){return
t(n,0),n},e},Bo.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=Bo.layout.hierarchy(),u=[1,1];return e.size=function(n){return
arguments.length?(u=n,e):u},gu(e,r)},Bo.layout.pie=function(){function n(i){var
o=i.map(function(e,r){return+t.cal
l(n,e,r)}),a=+("function"==typeof
r?r.apply(this,arguments):r),c=(("function"==typeof
u?u.apply(this,arguments):u)-a)/Bo.sum(o),s=Bo.range(i.length);null!=e&&s.sort(e===as?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=as,r=0,u=Aa;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 as={};Bo.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=Bo.permute(s,f),l=Bo.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=dt,e=_u,r=bu,u=Mu,i=yu,o=xu;return
n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return
arguments.length?(e="function"==typeof
t?t:cs.get(t)||_u,n):e},n.offset=function(t){return
arguments.length?(r="function"==typeof
t?t:ss.get(t)||bu,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
cs=Bo.map({"inside-out":function(n){var
t,e,r=n.length,u=n.map(wu),i=n.map(Su),o=Bo.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
Bo.range(n.length).reverse()},"default":_u}),ss=Bo.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:bu});Bo.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[Bo.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return
c}var t=!0,e=Number,r=Cu,u=Eu;return n.value=function(t){return
arguments.length?(e=t,n):e},n.range=function(t){r
eturn arguments.length?(r=vt(t),n):r},n.bins=function(t){return
arguments.length?(u="number"==typeof t?function(n){return
Au(n,t)}:vt(t),n):u},n.frequency=function(e){return
arguments.length?(t=!!e,n):t},n},Bo.layout.tree=function(){function n(n,i){function
o(n,t){var r=n.children,u=n._tree;if(r&&(i=r.length)){for(var
i,a,s,l=r[0],f=l,h=-1;++h<i;)s=r[h],o(s,a),f=c(s,a,f),a=s;Uu(n);var
g=.5*(l._tree.prelim+s._tree.prelim);t?(u.prelim=t._tree.prelim+e(n,t),u.mod=u.prelim-g):u.prelim=g}else
t&&(u.prelim=t._tree.prelim+e(n,t))}function a(n,t){n.x=n._tree.prelim+t;var
e=n.children;if(e&&(r=e.length)){var
r,u=-1;for(t+=n._tree.mod;++u<r;)a(e[u],t)}}function c(n,t,r){if(t){for(var
u,i=n,o=n,a=t,c=n.parent.children[0],s=i._tree.mod,l=o._tree.mod,f=a._tree.mod,h=c._tree.mod;a=Tu(a),i=Lu(i),a&&i;)c=Lu(c),o=Tu(o),o._tree.ancestor=n,u=a._tree.prelim+f-i._tree.prelim-s+e(a,i),u>0&&(ju(Hu(a,n,r),n,u),s+=u,l+=u),f+=a._tree.mod,s+=i._tree.mod,h+=c._tree.mod,l+=o._tree.mod;a&&!Tu(o)&&(o._tre
e.thread=a,o._tree.mod+=f-l),i&&!Lu(c)&&(c._tree.thread=i,c._tree.mod+=s-h,r=n)}return
r}var
s=t.call(this,n,i),l=s[0];Pu(l,function(n,t){n._tree={ancestor:n,prelim:0,mod:0,change:0,shift:0,number:t?t._tree.number+1:0}}),o(l),a(l,-l._tree.prelim);var
f=qu(l,Ru),h=qu(l,zu),g=qu(l,Du),p=f.x-e(f,h)/2,v=h.x+e(h,f)/2,d=g.depth||1;return
Pu(l,u?function(n){n.x*=r[0],n.y=n.depth*r[1],delete
n._tree}:function(n){n.x=(n.x-p)/(v-p)*r[0],n.y=n.depth/d*r[1],delete n._tree}),s}var
t=Bo.layout.hierarchy().sort(null).value(null),e=Nu,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},gu(n,t)},Bo.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,Pu(a,function(n){n.r=+l(n.value)}),Pu(a,Zu),r){var
f=r*(t?1:Math.m
ax(2*a.r/c,2*a.r/s))/2;Pu(a,function(n){n.r+=f}),Pu(a,Zu),Pu(a,function(n){n.r-=f})}return
$u(a,c/2,s/2,t?1:1/Math.max(2*a.r/c,2*a.r/s)),o}var
t,e=Bo.layout.hierarchy().sort(Fu),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},gu(n,e)},Bo.layout.cluster=function(){function n(n,i){var
o,a=t.call(this,n,i),c=a[0],s=0;Pu(c,function(n){var
t=n.children;t&&t.length?(n.x=Ju(t),n.y=Wu(t)):(n.x=o?s+=e(n,o):0,n.y=0,o=n)});var
l=Gu(c),f=Ku(c),h=l.x-e(l,f)/2,g=f.x+e(f,l)/2;return
Pu(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=Bo.layout.hierarchy().sort(null).value(null),e=Nu,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},gu(n,t)},Bo.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=Bo.layout.hierarchy(),c=Math.round,s=[1,1],l=null,f=Qu,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?Qu(t):ni(t,"number"==typeof
e?[e,e,e,e]:e)}function e(t){return ni(t,n)}if(!arguments.length)return l;var r;return
f=null==(l=n)?Qu:"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},gu(i,a)},Bo.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=Bo.random.normal.apply(Bo,arguments);return function(){return
Math.exp(n())}},bates:function(n){var t=Bo.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}}},Bo.scale={};var
ls={floor:dt,ceil:dt};Bo.scale.linear=function(){return ai([0,1],[0,1],zr,!1)};var
fs={s:1,g:1,p:1,r:1,e:1};Bo.scale.log=function(){return
vi(Bo.scale.linear().domain([0,1]),10,!0,[1,10])};var hs=Bo.format(".0e")
,gs={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};Bo.scale.pow=function(){return
di(Bo.scale.linear(),1,[0,1])},Bo.scale.sqrt=function(){return
Bo.scale.pow().exponent(.5)},Bo.scale.ordinal=function(){return
yi([],{t:"range",a:[[]]})},Bo.scale.category10=function(){return
Bo.scale.ordinal().range(ps)},Bo.scale.category20=function(){return
Bo.scale.ordinal().range(vs)},Bo.scale.category20b=function(){return
Bo.scale.ordinal().range(ds)},Bo.scale.category20c=function(){return
Bo.scale.ordinal().range(ms)};var
ps=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(ot),vs=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(ot),ds=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,1083432
4,13528509,14589654].map(ot),ms=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(ot);Bo.scale.quantile=function(){return
xi([],[])},Bo.scale.quantize=function(){return
Mi(0,1,[0,1])},Bo.scale.threshold=function(){return
_i([.5],[0,1])},Bo.scale.identity=function(){return
bi([0,1])},Bo.svg={},Bo.svg.arc=function(){function n(){var
n=t.apply(this,arguments),i=e.apply(this,arguments),o=r.apply(this,arguments)+ys,a=u.apply(this,arguments)+ys,c=(o>a&&(c=o,o=a,a=c),a-o),s=Ea>c?"0":"1",l=Math.cos(o),f=Math.sin(o),h=Math.cos(a),g=Math.sin(a);return
c>=xs?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=wi,e=Si,r=ki,u=Ei;return n.innerRadius=function(e){return
arguments.length?(t=vt(e),n):t},n.outerRadius=function(t){return
arguments.length?(e=vt(t),n):e},n.startAngle=function(t){return
arguments.length?(r=vt(t),n):r},n.endAngle=function(t){return
arguments.length?(u=vt(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+ys;return[Math.cos(i)*n,Math.sin(i)*n]},n};var
ys=-Ca,xs=Aa-Na;Bo.svg.line=function(){return Ai(dt)};var
Ms=Bo.map({linear:Ci,"linear-closed":Ni,step:Li,"step-before":Ti,"step-after":qi,basis:ji,"basis-open":Hi,"basis-closed":Fi,bundle:Oi,cardinal:Di,"cardinal-open":zi,"cardinal-closed":Ri,monotone:$i});Ms.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var
_s=[0,2/3,1/3,0],bs=[0,1/3,2/3,0],ws=[0,1/6,2/3,1/6];Bo.svg.line.radial=function(){var
n=Ai(Bi);return n.radius=n.x,delete n.x,n.a
ngle=n.y,delete n.y,n},Ti.reverse=qi,qi.reverse=Ti,Bo.svg.area=function(){return
Wi(dt)},Bo.svg.area.radial=function(){var n=Wi(Bi);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},Bo.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)+ys,l=s.call(n,u,r)+ys;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>Ea)+",1
"+t}function u(n,t,e,r){return"Q 0,0 "+r}var
i=De,o=Pe,a=Ji,c=ki,s=Ei;return n.radius=function(t){return
arguments.length?(a=vt(t),n):a},n.source=function(t){return arguments.length?(i=v
t(t),n):i},n.target=function(t){return
arguments.length?(o=vt(t),n):o},n.startAngle=function(t){return
arguments.length?(c=vt(t),n):c},n.endAngle=function(t){return
arguments.length?(s=vt(t),n):s},n},Bo.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=De,e=Pe,r=Gi;return n.source=function(e){return
arguments.length?(t=vt(e),n):t},n.target=function(t){return
arguments.length?(e=vt(t),n):e},n.projection=function(t){return
arguments.length?(r=t,n):r},n},Bo.svg.diagonal.radial=function(){var
n=Bo.svg.diagonal(),t=Gi,e=n.projection;return n.projection=function(n){return
arguments.length?e(Ki(t=n)):t},n},Bo.svg.symbol=function(){function
n(n,r){return(Ss.get(t.call(this,n,r))||to)(e.call(this,n,r))}var t=no,e=Qi;return
n.type=function(e){return arguments.length?(t=vt(e),n):t},n.size=function(t){return
arguments.length?(e=vt(t),n):e},n};var Ss=B
o.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*Cs)),e=t*Cs;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/As),e=t*As/2;return"M0,"+e+"L"+t+","+-e+"
"+-t+","+-e+"Z"},"triangle-up":function(n){var
t=Math.sqrt(n/As),e=t*As/2;return"M0,"+-e+"L"+t+","+e+"
"+-t+","+e+"Z"}});Bo.svg.symbolTypes=Ss.keys();var
ks,Es,As=Math.sqrt(3),Cs=Math.tan(30*Ta),Ns=[],Ls=0;Ns.call=ya.call,Ns.empty=ya.empty,Ns.node=ya.node,Ns.size=ya.size,Bo.transition=function(n){return
arguments.length?ks?n.transition():n:_a.transition()},Bo.transition.prototype=Ns,Ns.select=function(n){var
t,e,r,u=this.id,i=[];n=v(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__),io(e,s,u,r.__transition__[u]),t.push(e)):t.push(null)}return
eo(i,u)},Ns.selectAll=function(n){var t,e,r,u,i,o=this.id,a=[];n=d(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])&&io(u,g,o,i),t.push(u)}return
eo(a,o)},Ns.filter=function(n){var t,e,r,u=[];"function"!=typeof
n&&(n=A(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
eo(u,this.id)},Ns.tween=function(n,t){var e=this.id;return
arguments.length<2?this.node().__transition__[e].tween.get(n):N(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Ns.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?eu:zr,a=Bo.ns.qualify(n);return
ro(this,"attr."+n,t,a.local?i:u)},Ns.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=Bo.ns.qualify(n);return
this.tween("attr."+n,u.local?r:e)},Ns.style=function(n,t,e){function
r(){this.style.removeProperty(n)}function u(t){return
null==t?r:(t+="",function(){var
r,u=Qo.getComputedStyle(this,null).getPropertyValue(n);return
u!==t&&(r=zr(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)},Ns.styleTween=function(n,t,e){function r(r,u){var
i=t.call(this,r,u,Qo.getComputedStyle(this,null).getPropertyValue(n));return
i&&function(t){th
is.style.setProperty(n,i(t),e)}}return
arguments.length<3&&(e=""),this.tween("style."+n,r)},Ns.text=function(n){return
ro(this,"text",n,uo)},Ns.remove=function(){return
this.each("end.transition",function(){var
n;this.__transition__.count<2&&(n=this.parentNode)&&n.removeChild(this)})},Ns.ease=function(n){var
t=this.id;return
arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof
n&&(n=Bo.ease.apply(Bo,arguments)),N(this,function(e){e.__transition__[t].ease=n}))},Ns.delay=function(n){var
t=this.id;return N(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}))},Ns.duration=function(n){var
t=this.id;return N(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}))},Ns.each=function(n,t){var
e=this.id;if(arguments.length<2){var r=Es,u=ks;ks=e,N(this,function(
t,r,u){Es=t.__transition__[e],n.call(t,t.__data__,r,u)}),Es=r,ks=u}else
N(this,function(r){var
u=r.__transition__[e];(u.event||(u.event=Bo.dispatch("start","end"))).on(n,t)});return
this},Ns.transition=function(){for(var
n,t,e,r,u=this.id,i=++Ls,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,io(e,s,i,r)),n.push(e)}return
eo(o,i)},Bo.svg.axis=function(){function n(n){n.each(function(){var
n,s=Bo.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):dt:t,p=s.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Na),d=Bo.transition(p.exit()).style("opacity",Na).remove(),m=Bo.transition(p).style("opacity",1),y=ei(f),x=s.selectAll(".domain").data([0]),M=(x.enter().append("path").attr("class","domain"),Bo.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=oo,_.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=oo,_.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=ao,_.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=ao,_.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=Bo.scale.linear(),r=Ts,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
qs?t+"":Ts,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
Ts="bottom",qs={top:1,right:1,bottom:1,left:1};Bo.svg.brush=function(){func
tion n(i){i.each(function(){var
i=Bo.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(d,dt);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize
"+n}).style("cursor",function(n){return
zs[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=Bo.transition(i),h=Bo.transition(o);c&&(l=ei(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),e(f)),s&&(l=ei(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)]+","+h[+/^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",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function
u(){function
u(){32==Bo.event.keyCode&&(C||(x=null,L[0]-=l[1],L[1]-=h[1],C=2),f())}function
g(){32==Bo.event.keyCode&&2==C&&(L[0]+=l[1],L[1]+=h[1],C=0,f())}function
d(){var
n=Bo.mouse(_),u=!1;M&&(n[0]+=M[0],n[1]+=M[1]),C||(Bo.event.altKey?(x||(x=[(l[0]+l[1])/2,(h[0]+h[1])/2]),L[0]=l[+(n[0]<x[0])],L[1]=h[+(n[1]<x[1])]):x=null),E&&m(n,c,0)&&(e(S),u=!0),A&&m(n,s,1)&&(r(S),u=!0),u&&(t(S),w({type:"brush",mode:C?"move":"resize"}))}function
m(n,t,e){var r,u,a=ei(t),c=a[0],s=a[1],f=L[e],g=e?h:l,d=g[1]-g[0];return
C&&(c-=f,s-=d+f),r=(e?v:p)?Math.max(c,Math.min(s,n[e])):n[e],C?u=(r+=f)+d:(x&&(f=Math.max(c,Math.min(s,2*x[e]-r
))),r>f?(u=r,r=f):u=f),g[0]!=r||g[1]!=u?(e?o=null:i=null,g[0]=r,g[1]=u,!0):void
0}function
y(){d(),S.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),Bo.select("body").style("cursor",null),T.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=Bo.select(Bo.event.target),w=a.of(_,arguments),S=Bo.select(_),k=b.datum(),E=!/^(n|s)$/.test(k)&&c,A=!/^(e|w)$/.test(k)&&s,C=b.classed("extent"),N=P(),L=Bo.mouse(_),T=Bo.select(Qo).on("keydown.brush",u).on("keyup.brush",g);if(Bo.event.changedTouches?T.on("touchmove.brush",d).on("touchend.brush",y):T.on("mousemove.brush",d).on("mouseup.brush",y),S.interrupt().selectAll("*").interrupt(),C)L[0]=l[0]-L[0],L[1]=h[0]-L[1];else
if(k){var
q=+/w$/.test(k),z=+/^n/.test(k);M=[l[1-q]-L[0],h[1-z]-L[1]],L[0]=l[q],L[1]=h[z]}else
Bo.event.altKey&&(x=L.slice());S.style("poi
nter-events","none").selectAll(".resize").style("display",null),Bo.select("body").style("cursor",b.style("cursor")),w({type:"brushstart"}),d()}var
i,o,a=g(n,"brushstart","brush","brushend"),c=null,s=null,l=[0,0],h=[0,0],p=!0,v=!0,d=Rs[0];return
n.event=function(n){n.each(function(){var
n=a.of(this,arguments),t={x:l,y:h,i:i,j:o},e=this.__chart__||t;this.__chart__=t,ks?Bo.select(this).transition().each("start.brush",function(){i=e.i,o=e.j,l=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var
e=Rr(l,t.x),r=Rr(h,t.y);return
i=o=null,function(u){l=t.x=e(u),h=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,d=Rs[!c<<1|!s],n):c},n.y=function(t){return
arguments.length?(s=t,d=Rs[!c<<1|!s],n):s},n.clamp=function(t){return
arguments.length?(c&&s?(p=!!t[0]
,v=!!t[1]):c?p=!!t:s&&(v=!!t),n):c&&s?[p,v]:c?p:s?v:null},n.extent=function(t){var
e,r,u,a,f;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&&(f=e,e=r,r=f),(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&&(f=u,u=a,a=f),(u!=h[0]||a!=h[1])&&(h=[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&&(f=e,e=r,r=f))),s&&(o?(u=o[0],a=o[1]):(u=h[0],a=h[1],s.invert&&(u=s.invert(u),a=s.invert(a)),u>a&&(f=u,u=a,a=f))),c&&s?[[e,u],[r,a]]:c?[e,r]:s&&[u,a])},n.clear=function(){return
n.empty()||(l=[0,0],h=[0,0],i=o=null),n},n.empty=function(){return!!c&&l[0]==l[1]||!!s&&h[0]==h[1]},Bo.rebind(n,a,"on")};var
zs={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Rs=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Ds=Bo.time={},Ps=Date,Us=["Sunday","Monday","
Tuesday","Wednesday","Thursday","Friday","Saturday"];co.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(){js.setUTCDate.apply(this._,arguments)},setDay:function(){js.setUTCDay.apply(this._,arguments)},setFullYear:function(){js.setUTCFullYear.apply(this._,arguments)},setHours:function(){js.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){js.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){js.setUTCMinutes.apply(this._,arguments)},set
Month:function(){js.setUTCMonth.apply(this._,arguments)},setSeconds:function(){js.setUTCSeconds.apply(this._,arguments)},setTime:function(){js.setTime.apply(this._,arguments)}};var
js=Date.prototype,Hs="%a %b %e %X
%Y",Fs="%m/%d/%Y",Os="%H:%M:%S",Ys=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],Is=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],Zs=["January","February","March","April","May","June","July","August","September","October","November","December"],Vs=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];Ds.year=so(function(n){return
n=Ds.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return
n.getFullYear()}),Ds.years=Ds.year.range,Ds.years.utc=Ds.year.utc.range,Ds.day=so(function(n){var
t=new Ps(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}),Ds.days=Ds.day.range,Ds.days.utc=Ds.day.utc.
range,Ds.dayOfYear=function(n){var t=Ds.year(n);return
Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},Us.forEach(function(n,t){n=n.toLowerCase(),t=7-t;var
e=Ds[n]=so(function(n){return(n=Ds.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=Ds.year(n).getDay();return
Math.floor((Ds.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});Ds[n+"s"]=e.range,Ds[n+"s"].utc=e.utc.range,Ds[n+"OfYear"]=function(n){var
e=Ds.year(n).getDay();return
Math.floor((Ds.dayOfYear(n)+(e+t)%7)/7)}}),Ds.week=Ds.sunday,Ds.weeks=Ds.sunday.range,Ds.weeks.utc=Ds.sunday.utc.range,Ds.weekOfYear=Ds.sundayOfYear,Ds.format=fo;var
Xs=go(Ys),$s=po(Ys),Bs=go(Is),Ws=po(Is),Js=go(Zs),Gs=po(Zs),Ks=go(Vs),Qs=po(Vs),nl=/^%/,tl={"-":"",_:"
",0:"0"},el={a:function(n){return Is[n.getDay()]},A:function(n){return
Ys[n.getDay()]},b:function(n){return Vs[n.getMonth()]},B:function(n){return
Zs[n.getMonth()]},c:fo(Hs),d:function(n,t){return vo(
n.getDate(),t,2)},e:function(n,t){return vo(n.getDate(),t,2)},H:function(n,t){return
vo(n.getHours(),t,2)},I:function(n,t){return
vo(n.getHours()%12||12,t,2)},j:function(n,t){return
vo(1+Ds.dayOfYear(n),t,3)},L:function(n,t){return
vo(n.getMilliseconds(),t,3)},m:function(n,t){return
vo(n.getMonth()+1,t,2)},M:function(n,t){return
vo(n.getMinutes(),t,2)},p:function(n){return
n.getHours()>=12?"PM":"AM"},S:function(n,t){return
vo(n.getSeconds(),t,2)},U:function(n,t){return
vo(Ds.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return
vo(Ds.mondayOfYear(n),t,2)},x:fo(Fs),X:fo(Os),y:function(n,t){return
vo(n.getFullYear()%100,t,2)},Y:function(n,t){return
vo(n.getFullYear()%1e4,t,4)},Z:Ho,"%":function(){return"%"}},rl={a:mo,A:yo,b:bo,B:wo,c:So,d:qo,e:qo,H:Ro,I:Ro,j:zo,L:Uo,m:To,M:Do,p:jo,S:Po,U:Mo,w:xo,W:_o,x:ko,X:Eo,y:Co,Y:Ao,Z:No,"%":Fo},ul=/^\s*\d+/,il=Bo.map({am:0,pm:1});fo.utc=Oo;var
ol=Oo("%Y-%m-%dT%H:%M:%S.%LZ");fo.iso=Date.prototype.toISOString&&+new
D
ate("2000-01-01T00:00:00.000Z")?Yo:ol,Yo.parse=function(n){var t=new
Date(n);return isNaN(t)?null:t},Yo.toString=ol.toString,Ds.second=so(function(n){return
new
Ps(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return
n.getSeconds()}),Ds.seconds=Ds.second.range,Ds.seconds.utc=Ds.second.utc.range,Ds.minute=so(function(n){return
new
Ps(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return
n.getMinutes()}),Ds.minutes=Ds.minute.range,Ds.minutes.utc=Ds.minute.utc.range,Ds.hour=so(function(n){var
t=n.getTimezoneOffset()/60;return new
Ps(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return
n.getHours()}),Ds.hours=Ds.hour.range,Ds.hours.utc=Ds.hour.utc.range,Ds.month=so(function(n){return
n=Ds.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return
n.getMonth()}),Ds.months=Ds.month.range,Ds.months.utc=Ds.month.ut
c.range;var
al=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],cl=[[Ds.second,1],[Ds.second,5],[Ds.second,15],[Ds.second,30],[Ds.minute,1],[Ds.minute,5],[Ds.minute,15],[Ds.minute,30],[Ds.hour,1],[Ds.hour,3],[Ds.hour,6],[Ds.hour,12],[Ds.day,1],[Ds.day,2],[Ds.week,1],[Ds.month,1],[Ds.month,3],[Ds.year,1]],sl=[[fo("%Y"),Vt],[fo("%B"),function(n){return
n.getMonth()}],[fo("%b %d"),function(n){return 1!=n.getDate()}],[fo("%a
%d"),function(n){return n.getDay()&&1!=n.getDate()}],[fo("%I
%p"),function(n){return n.getHours()}],[fo("%I:%M"),function(n){return
n.getMinutes()}],[fo(":%S"),function(n){return
n.getSeconds()}],[fo(".%L"),function(n){return
n.getMilliseconds()}]],ll=Vo(sl);cl.year=Ds.year,Ds.scale=function(){return
Io(Bo.scale.linear(),cl,ll)};var fl={range:function(n,t,e){return
Bo.range(+n,+t,e).map(Zo)},floor:dt,ceil:dt},hl=cl.map(function(n){return[n[0].utc,n[1]]}),gl=[[Oo("%Y"),Vt],[Oo("%B"),function(n){return
n.getU
TCMonth()}],[Oo("%b %d"),function(n){return 1!=n.getUTCDate()}],[Oo("%a
%d"),function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],[Oo("%I
%p"),function(n){return n.getUTCHours()}],[Oo("%I:%M"),function(n){return
n.getUTCMinutes()}],[Oo(":%S"),function(n){return
n.getUTCSeconds()}],[Oo(".%L"),function(n){return
n.getUTCMilliseconds()}]],pl=Vo(gl);return
hl.year=Ds.year.utc,Ds.scale.utc=function(){return
Io(Bo.scale.linear(),hl,pl)},Bo.text=mt(function(n){return
n.responseText}),Bo.json=function(n,t){return
yt(n,"application/json",Xo,t)},Bo.html=function(n,t){return
yt(n,"text/html",$o,t)},Bo.xml=mt(function(n){return n.responseXML}),Bo}();
\ No newline at end of file
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.js
b/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.js
deleted file mode 100644
index 61e11cc..0000000
--- a/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.js
+++ /dev/null
@@ -1,8768 +0,0 @@
-d3 = function() {
- var d3 = {
- version: "3.2.2"
- };
- if (!Date.now) Date.now = function() {
- return +new Date();
- };
- var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window
= window;
- try {
- d3_document.createElement("div").style.setProperty("opacity", 0,
"");
- } catch (error) {
- var d3_style_prototype = d3_window.CSSStyleDeclaration.prototype,
d3_style_setProperty = d3_style_prototype.setProperty;
- d3_style_prototype.setProperty = function(name, value, priority) {
- d3_style_setProperty.call(this, name, value + "", priority);
- };
- }
- d3.ascending = function(a, b) {
- return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
- };
- d3.descending = function(a, b) {
- return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
- };
- d3.min = function(array, f) {
- var i = -1, n = array.length, a, b;
- if (arguments.length === 1) {
- while (++i < n && !((a = array[i]) != null && a <= a)) a =
undefined;
- while (++i < n) if ((b = array[i]) != null && a > b) a = b;
- } else {
- while (++i < n && !((a = f.call(array, array[i], i)) != null &&
a <= a)) a = undefined;
- while (++i < n) if ((b = f.call(array, array[i], i)) != null && a >
b) a = b;
- }
- return a;
- };
- d3.max = function(array, f) {
- var i = -1, n = array.length, a, b;
- if (arguments.length === 1) {
- while (++i < n && !((a = array[i]) != null && a <= a)) a =
undefined;
- while (++i < n) if ((b = array[i]) != null && b > a) a = b;
- } else {
- while (++i < n && !((a = f.call(array, array[i], i)) != null &&
a <= a)) a = undefined;
- while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >
a) a = b;
- }
- return a;
- };
- d3.extent = function(array, f) {
- var i = -1, n = array.length, a, b, c;
- if (arguments.length === 1) {
- while (++i < n && !((a = c = array[i]) != null && a <= a)) a
= c = undefined;
- while (++i < n) if ((b = array[i]) != null) {
- if (a > b) a = b;
- if (c < b) c = b;
- }
- } else {
- while (++i < n && !((a = c = f.call(array, array[i], i)) != null
&& a <= a)) a = undefined;
- while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
- if (a > b) a = b;
- if (c < b) c = b;
- }
- }
- return [ a, c ];
- };
- d3.sum = function(array, f) {
- var s = 0, n = array.length, a, i = -1;
- if (arguments.length === 1) {
- while (++i < n) if (!isNaN(a = +array[i])) s += a;
- } else {
- while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
- }
- return s;
- };
- function d3_number(x) {
- return x != null && !isNaN(x);
- }
- d3.mean = function(array, f) {
- var n = array.length, a, m = 0, i = -1, j = 0;
- if (arguments.length === 1) {
- while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
- } else {
- while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) /
++j;
- }
- return j ? m : undefined;
- };
- d3.quantile = function(values, p) {
- var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H -
h;
- return e ? v + e * (values[h] - v) : v;
- };
- d3.median = function(array, f) {
- if (arguments.length > 1) array = array.map(f);
- array = array.filter(d3_number);
- return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
- };
- d3.bisector = function(f) {
- return {
- left: function(a, x, lo, hi) {
- if (arguments.length < 3) lo = 0;
- if (arguments.length < 4) hi = a.length;
- while (lo < hi) {
- var mid = lo + hi >>> 1;
- if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid;
- }
- return lo;
- },
- right: function(a, x, lo, hi) {
- if (arguments.length < 3) lo = 0;
- if (arguments.length < 4) hi = a.length;
- while (lo < hi) {
- var mid = lo + hi >>> 1;
- if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1;
- }
- return lo;
- }
- };
- };
- var d3_bisector = d3.bisector(function(d) {
- return d;
- });
- d3.bisectLeft = d3_bisector.left;
- d3.bisect = d3.bisectRight = d3_bisector.right;
- d3.shuffle = function(array) {
- var m = array.length, t, i;
- while (m) {
- i = Math.random() * m-- | 0;
- t = array[m], array[m] = array[i], array[i] = t;
- }
- return array;
- };
- d3.permute = function(array, indexes) {
- var permutes = [], i = -1, n = indexes.length;
- while (++i < n) permutes[i] = array[indexes[i]];
- return permutes;
- };
- d3.zip = function() {
- if (!(n = arguments.length)) return [];
- for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i <
m; ) {
- for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
- zip[j] = arguments[j][i];
- }
- }
- return zips;
- };
- function d3_zipLength(d) {
- return d.length;
- }
- d3.transpose = function(matrix) {
- return d3.zip.apply(d3, matrix);
- };
- d3.keys = function(map) {
- var keys = [];
- for (var key in map) keys.push(key);
- return keys;
- };
- d3.values = function(map) {
- var values = [];
- for (var key in map) values.push(map[key]);
- return values;
- };
- d3.entries = function(map) {
- var entries = [];
- for (var key in map) entries.push({
- key: key,
- value: map[key]
- });
- return entries;
- };
- d3.merge = function(arrays) {
- return Array.prototype.concat.apply([], arrays);
- };
- d3.range = function(start, stop, step) {
- if (arguments.length < 3) {
- step = 1;
- if (arguments.length < 2) {
- stop = start;
- start = 0;
- }
- }
- if ((stop - start) / step === Infinity) throw new Error("infinite range");
- var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j;
- start *= k, stop *= k, step *= k;
- if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else
while ((j = start + step * ++i) < stop) range.push(j / k);
- return range;
- };
- function d3_range_integerScale(x) {
- var k = 1;
- while (x * k % 1) k *= 10;
- return k;
- }
- function d3_class(ctor, properties) {
- try {
- for (var key in properties) {
- Object.defineProperty(ctor.prototype, key, {
- value: properties[key],
- enumerable: false
- });
- }
- } catch (e) {
- ctor.prototype = properties;
- }
- }
- d3.map = function(object) {
- var map = new d3_Map();
- for (var key in object) map.set(key, object[key]);
- return map;
- };
- function d3_Map() {}
- d3_class(d3_Map, {
- has: function(key) {
- return d3_map_prefix + key in this;
- },
- get: function(key) {
- return this[d3_map_prefix + key];
- },
- set: function(key, value) {
- return this[d3_map_prefix + key] = value;
- },
- remove: function(key) {
- key = d3_map_prefix + key;
- return key in this && delete this[key];
- },
- keys: function() {
- var keys = [];
- this.forEach(function(key) {
- keys.push(key);
- });
- return keys;
- },
- values: function() {
- var values = [];
- this.forEach(function(key, value) {
- values.push(value);
- });
- return values;
- },
- entries: function() {
- var entries = [];
- this.forEach(function(key, value) {
- entries.push({
- key: key,
- value: value
- });
- });
- return entries;
- },
- forEach: function(f) {
- for (var key in this) {
- if (key.charCodeAt(0) === d3_map_prefixCode) {
- f.call(this, key.substring(1), this[key]);
- }
- }
- }
- });
- var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
- d3.nest = function() {
- var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
- function map(mapType, array, depth) {
- if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues
? array.sort(sortValues) : array;
- var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter,
valuesByKey = new d3_Map(), values;
- while (++i < n) {
- if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
- values.push(object);
- } else {
- valuesByKey.set(keyValue, [ object ]);
- }
- }
- if (mapType) {
- object = mapType();
- setter = function(keyValue, values) {
- object.set(keyValue, map(mapType, values, depth));
- };
- } else {
- object = {};
- setter = function(keyValue, values) {
- object[keyValue] = map(mapType, values, depth);
- };
- }
- valuesByKey.forEach(setter);
- return object;
- }
- function entries(map, depth) {
- if (depth >= keys.length) return map;
- var array = [], sortKey = sortKeys[depth++];
- map.forEach(function(key, keyMap) {
- array.push({
- key: key,
- values: entries(keyMap, depth)
- });
- });
- return sortKey ? array.sort(function(a, b) {
- return sortKey(a.key, b.key);
- }) : array;
- }
- nest.map = function(array, mapType) {
- return map(mapType, array, 0);
- };
- nest.entries = function(array) {
- return entries(map(d3.map, array, 0), 0);
- };
- nest.key = function(d) {
- keys.push(d);
- return nest;
- };
- nest.sortKeys = function(order) {
- sortKeys[keys.length - 1] = order;
- return nest;
- };
- nest.sortValues = function(order) {
- sortValues = order;
- return nest;
- };
- nest.rollup = function(f) {
- rollup = f;
- return nest;
- };
- return nest;
- };
- d3.set = function(array) {
- var set = new d3_Set();
- if (array) for (var i = 0; i < array.length; i++) set.add(array[i]);
- return set;
- };
- function d3_Set() {}
- d3_class(d3_Set, {
- has: function(value) {
- return d3_map_prefix + value in this;
- },
- add: function(value) {
- this[d3_map_prefix + value] = true;
- return value;
- },
- remove: function(value) {
- value = d3_map_prefix + value;
- return value in this && delete this[value];
- },
- values: function() {
- var values = [];
- this.forEach(function(value) {
- values.push(value);
- });
- return values;
- },
- forEach: function(f) {
- for (var value in this) {
- if (value.charCodeAt(0) === d3_map_prefixCode) {
- f.call(this, value.substring(1));
- }
- }
- }
- });
- d3.behavior = {};
- d3.rebind = function(target, source) {
- var i = 1, n = arguments.length, method;
- while (++i < n) target[method = arguments[i]] = d3_rebind(target, source,
source[method]);
- return target;
- };
- function d3_rebind(target, source, method) {
- return function() {
- var value = method.apply(source, arguments);
- return value === source ? target : value;
- };
- }
- function d3_vendorSymbol(object, name) {
- if (name in object) return name;
- name = name.charAt(0).toUpperCase() + name.substring(1);
- for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
- var prefixName = d3_vendorPrefixes[i] + name;
- if (prefixName in object) return prefixName;
- }
- }
- var d3_vendorPrefixes = [ "webkit", "ms", "moz",
"Moz", "o", "O" ];
- var d3_array = d3_arraySlice;
- function d3_arrayCopy(pseudoarray) {
- var i = -1, n = pseudoarray.length, array = [];
- while (++i < n) array.push(pseudoarray[i]);
- return array;
- }
- function d3_arraySlice(pseudoarray) {
- return Array.prototype.slice.call(pseudoarray);
- }
- try {
- d3_array(d3_documentElement.childNodes)[0].nodeType;
- } catch (e) {
- d3_array = d3_arrayCopy;
- }
- var d3_arraySubclass = [].__proto__ ? function(array, prototype) {
- array.__proto__ = prototype;
- } : function(array, prototype) {
- for (var property in prototype) array[property] = prototype[property];
- };
- function d3_noop() {}
- d3.dispatch = function() {
- var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
- while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
- return dispatch;
- };
- function d3_dispatch() {}
- d3_dispatch.prototype.on = function(type, listener) {
- var i = type.indexOf("."), name = "";
- if (i >= 0) {
- name = type.substring(i + 1);
- type = type.substring(0, i);
- }
- if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name,
listener);
- if (arguments.length === 2) {
- if (listener == null) for (type in this) {
- if (this.hasOwnProperty(type)) this[type].on(name, null);
- }
- return this;
- }
- };
- function d3_dispatch_event(dispatch) {
- var listeners = [], listenerByName = new d3_Map();
- function event() {
- var z = listeners, i = -1, n = z.length, l;
- while (++i < n) if (l = z[i].on) l.apply(this, arguments);
- return dispatch;
- }
- event.on = function(name, listener) {
- var l = listenerByName.get(name), i;
- if (arguments.length < 2) return l && l.on;
- if (l) {
- l.on = null;
- listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i
+ 1));
- listenerByName.remove(name);
- }
- if (listener) listeners.push(listenerByName.set(name, {
- on: listener
- }));
- return dispatch;
- };
- return event;
- }
- d3.event = null;
- function d3_eventPreventDefault() {
- d3.event.preventDefault();
- }
- function d3_eventSource() {
- var e = d3.event, s;
- while (s = e.sourceEvent) e = s;
- return e;
- }
- function d3_eventDispatch(target) {
- var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
- while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
- dispatch.of = function(thiz, argumentz) {
- return function(e1) {
- try {
- var e0 = e1.sourceEvent = d3.event;
- e1.target = target;
- d3.event = e1;
- dispatch[e1.type].apply(thiz, argumentz);
- } finally {
- d3.event = e0;
- }
- };
- };
- return dispatch;
- }
- d3.requote = function(s) {
- return s.replace(d3_requote_re, "\\$&");
- };
- var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
- function d3_selection(groups) {
- d3_arraySubclass(groups, d3_selectionPrototype);
- return groups;
- }
- var d3_select = function(s, n) {
- return n.querySelector(s);
- }, d3_selectAll = function(s, n) {
- return n.querySelectorAll(s);
- }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement,
"matchesSelector")], d3_selectMatches = function(n, s) {
- return d3_selectMatcher.call(n, s);
- };
- if (typeof Sizzle === "function") {
- d3_select = function(s, n) {
- return Sizzle(s, n)[0] || null;
- };
- d3_selectAll = function(s, n) {
- return Sizzle.uniqueSort(Sizzle(s, n));
- };
- d3_selectMatches = Sizzle.matchesSelector;
- }
- d3.selection = function() {
- return d3_selectionRoot;
- };
- var d3_selectionPrototype = d3.selection.prototype = [];
- d3_selectionPrototype.select = function(selector) {
- var subgroups = [], subgroup, subnode, group, node;
- if (typeof selector !== "function") selector =
d3_selection_selector(selector);
- for (var j = -1, m = this.length; ++j < m; ) {
- subgroups.push(subgroup = []);
- subgroup.parentNode = (group = this[j]).parentNode;
- for (var i = -1, n = group.length; ++i < n; ) {
- if (node = group[i]) {
- subgroup.push(subnode = selector.call(node, node.__data__, i));
- if (subnode && "__data__" in node) subnode.__data__ =
node.__data__;
- } else {
- subgroup.push(null);
- }
- }
- }
- return d3_selection(subgroups);
- };
- function d3_selection_selector(selector) {
- return function() {
- return d3_select(selector, this);
- };
- }
- d3_selectionPrototype.selectAll = function(selector) {
- var subgroups = [], subgroup, node;
- if (typeof selector !== "function") selector =
d3_selection_selectorAll(selector);
- for (var j = -1, m = this.length; ++j < m; ) {
- for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
- if (node = group[i]) {
- subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i)));
- subgroup.parentNode = node;
- }
- }
- }
- return d3_selection(subgroups);
- };
- function d3_selection_selectorAll(selector) {
- return function() {
- return d3_selectAll(selector, this);
- };
- }
- var d3_nsPrefix = {
- 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/"
- };
- d3.ns = {
- prefix: d3_nsPrefix,
- qualify: function(name) {
- var i = name.indexOf(":"), prefix = name;
- if (i >= 0) {
- prefix = name.substring(0, i);
- name = name.substring(i + 1);
- }
- return d3_nsPrefix.hasOwnProperty(prefix) ? {
- space: d3_nsPrefix[prefix],
- local: name
- } : name;
- }
- };
- d3_selectionPrototype.attr = function(name, value) {
- if (arguments.length < 2) {
- if (typeof name === "string") {
- var node = this.node();
- name = d3.ns.qualify(name);
- return name.local ? node.getAttributeNS(name.space, name.local) :
node.getAttribute(name);
- }
- for (value in name) this.each(d3_selection_attr(value, name[value]));
- return this;
- }
- return this.each(d3_selection_attr(name, value));
- };
- function d3_selection_attr(name, value) {
- name = d3.ns.qualify(name);
- function attrNull() {
- this.removeAttribute(name);
- }
- function attrNullNS() {
- this.removeAttributeNS(name.space, name.local);
- }
- function attrConstant() {
- this.setAttribute(name, value);
- }
- function attrConstantNS() {
- this.setAttributeNS(name.space, name.local, value);
- }
- function attrFunction() {
- var x = value.apply(this, arguments);
- if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
- }
- function attrFunctionNS() {
- var x = value.apply(this, arguments);
- if (x == null) this.removeAttributeNS(name.space, name.local); else
this.setAttributeNS(name.space, name.local, x);
- }
- return value == null ? name.local ? attrNullNS : attrNull : typeof value ===
"function" ? name.local ? attrFunctionNS : attrFunction : name.local ?
attrConstantNS : attrConstant;
- }
- function d3_collapse(s) {
- return s.trim().replace(/\s+/g, " ");
- }
- d3_selectionPrototype.classed = function(name, value) {
- if (arguments.length < 2) {
- if (typeof name === "string") {
- var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1;
- if (value = node.classList) {
- while (++i < n) if (!value.contains(name[i])) return false;
- } else {
- value = node.getAttribute("class");
- while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return
false;
- }
- return true;
- }
- for (value in name) this.each(d3_selection_classed(value, name[value]));
- return this;
- }
- return this.each(d3_selection_classed(name, value));
- };
- function d3_selection_classedRe(name) {
- return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)",
"g");
- }
- function d3_selection_classed(name, value) {
- name = name.trim().split(/\s+/).map(d3_selection_classedName);
- var n = name.length;
- function classedConstant() {
- var i = -1;
- while (++i < n) name[i](this, value);
- }
- function classedFunction() {
- var i = -1, x = value.apply(this, arguments);
- while (++i < n) name[i](this, x);
- }
- return typeof value === "function" ? classedFunction : classedConstant;
- }
- function d3_selection_classedName(name) {
- var re = d3_selection_classedRe(name);
- return function(node, value) {
- if (c = node.classList) return value ? c.add(name) : c.remove(name);
- var c = node.getAttribute("class") || "";
- if (value) {
- re.lastIndex = 0;
- if (!re.test(c)) node.setAttribute("class", d3_collapse(c + "
" + name));
- } else {
- node.setAttribute("class", d3_collapse(c.replace(re, " ")));
- }
- };
- }
- d3_selectionPrototype.style = function(name, value, priority) {
- var n = arguments.length;
- if (n < 3) {
- if (typeof name !== "string") {
- if (n < 2) value = "";
- for (priority in name) this.each(d3_selection_style(priority, name[priority],
value));
- return this;
- }
- if (n < 2) return d3_window.getComputedStyle(this.node(),
null).getPropertyValue(name);
- priority = "";
- }
- return this.each(d3_selection_style(name, value, priority));
- };
- function d3_selection_style(name, value, priority) {
- function styleNull() {
- this.style.removeProperty(name);
- }
- function styleConstant() {
- this.style.setProperty(name, value, priority);
- }
- function styleFunction() {
- var x = value.apply(this, arguments);
- if (x == null) this.style.removeProperty(name); else this.style.setProperty(name,
x, priority);
- }
- return value == null ? styleNull : typeof value === "function" ?
styleFunction : styleConstant;
- }
- d3_selectionPrototype.property = function(name, value) {
- if (arguments.length < 2) {
- if (typeof name === "string") return this.node()[name];
- for (value in name) this.each(d3_selection_property(value, name[value]));
- return this;
- }
- return this.each(d3_selection_property(name, value));
- };
- function d3_selection_property(name, value) {
- function propertyNull() {
- delete this[name];
- }
- function propertyConstant() {
- this[name] = value;
- }
- function propertyFunction() {
- var x = value.apply(this, arguments);
- if (x == null) delete this[name]; else this[name] = x;
- }
- return value == null ? propertyNull : typeof value === "function" ?
propertyFunction : propertyConstant;
- }
- d3_selectionPrototype.text = function(value) {
- return arguments.length ? this.each(typeof value === "function" ?
function() {
- var v = value.apply(this, arguments);
- this.textContent = v == null ? "" : v;
- } : value == null ? function() {
- this.textContent = "";
- } : function() {
- this.textContent = value;
- }) : this.node().textContent;
- };
- d3_selectionPrototype.html = function(value) {
- return arguments.length ? this.each(typeof value === "function" ?
function() {
- var v = value.apply(this, arguments);
- this.innerHTML = v == null ? "" : v;
- } : value == null ? function() {
- this.innerHTML = "";
- } : function() {
- this.innerHTML = value;
- }) : this.node().innerHTML;
- };
- d3_selectionPrototype.append = function(name) {
- name = d3.ns.qualify(name);
- function append() {
- return this.appendChild(d3_document.createElementNS(this.namespaceURI, name));
- }
- function appendNS() {
- return this.appendChild(d3_document.createElementNS(name.space, name.local));
- }
- return this.select(name.local ? appendNS : append);
- };
- d3_selectionPrototype.insert = function(name, before) {
- name = d3.ns.qualify(name);
- if (typeof before !== "function") before = d3_selection_selector(before);
- function insert(d, i) {
- return this.insertBefore(d3_document.createElementNS(this.namespaceURI, name),
before.call(this, d, i));
- }
- function insertNS(d, i) {
- return this.insertBefore(d3_document.createElementNS(name.space, name.local),
before.call(this, d, i));
- }
- return this.select(name.local ? insertNS : insert);
- };
- d3_selectionPrototype.remove = function() {
- return this.each(function() {
- var parent = this.parentNode;
- if (parent) parent.removeChild(this);
- });
- };
- d3_selectionPrototype.data = function(value, key) {
- var i = -1, n = this.length, group, node;
- if (!arguments.length) {
- value = new Array(n = (group = this[0]).length);
- while (++i < n) {
- if (node = group[i]) {
- value[i] = node.__data__;
- }
- }
- return value;
- }
- function bind(group, groupData) {
- var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes =
new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
- if (key) {
- var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [],
keyValue;
- for (i = -1; ++i < n; ) {
- keyValue = key.call(node = group[i], node.__data__, i);
- if (nodeByKeyValue.has(keyValue)) {
- exitNodes[i] = node;
- } else {
- nodeByKeyValue.set(keyValue, node);
- }
- keyValues.push(keyValue);
- }
- for (i = -1; ++i < m; ) {
- keyValue = key.call(groupData, nodeData = groupData[i], i);
- if (node = nodeByKeyValue.get(keyValue)) {
- updateNodes[i] = node;
- node.__data__ = nodeData;
- } else if (!dataByKeyValue.has(keyValue)) {
- enterNodes[i] = d3_selection_dataNode(nodeData);
- }
- dataByKeyValue.set(keyValue, nodeData);
- nodeByKeyValue.remove(keyValue);
- }
- for (i = -1; ++i < n; ) {
- if (nodeByKeyValue.has(keyValues[i])) {
- exitNodes[i] = group[i];
- }
- }
- } else {
- for (i = -1; ++i < n0; ) {
- node = group[i];
- nodeData = groupData[i];
- if (node) {
- node.__data__ = nodeData;
- updateNodes[i] = node;
- } else {
- enterNodes[i] = d3_selection_dataNode(nodeData);
- }
- }
- for (;i < m; ++i) {
- enterNodes[i] = d3_selection_dataNode(groupData[i]);
- }
- for (;i < n; ++i) {
- exitNodes[i] = group[i];
- }
- }
- enterNodes.update = updateNodes;
- enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode =
group.parentNode;
- enter.push(enterNodes);
- update.push(updateNodes);
- exit.push(exitNodes);
- }
- var enter = d3_selection_enter([]), update = d3_selection([]), exit =
d3_selection([]);
- if (typeof value === "function") {
- while (++i < n) {
- bind(group = this[i], value.call(group, group.parentNode.__data__, i));
- }
- } else {
- while (++i < n) {
- bind(group = this[i], value);
- }
- }
- update.enter = function() {
- return enter;
- };
- update.exit = function() {
- return exit;
- };
- return update;
- };
- function d3_selection_dataNode(data) {
- return {
- __data__: data
- };
- }
- d3_selectionPrototype.datum = function(value) {
- return arguments.length ? this.property("__data__", value) :
this.property("__data__");
- };
- d3_selectionPrototype.filter = function(filter) {
- var subgroups = [], subgroup, group, node;
- if (typeof filter !== "function") filter = d3_selection_filter(filter);
- for (var j = 0, m = this.length; j < m; j++) {
- subgroups.push(subgroup = []);
- subgroup.parentNode = (group = this[j]).parentNode;
- for (var i = 0, n = group.length; i < n; i++) {
- if ((node = group[i]) && filter.call(node, node.__data__, i)) {
- subgroup.push(node);
- }
- }
- }
- return d3_selection(subgroups);
- };
- function d3_selection_filter(selector) {
- return function() {
- return d3_selectMatches(this, selector);
- };
- }
- d3_selectionPrototype.order = function() {
- for (var j = -1, m = this.length; ++j < m; ) {
- for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0;
) {
- if (node = group[i]) {
- if (next && next !== node.nextSibling)
next.parentNode.insertBefore(node, next);
- next = node;
- }
- }
- }
- return this;
- };
- d3_selectionPrototype.sort = function(comparator) {
- comparator = d3_selection_sortComparator.apply(this, arguments);
- for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
- return this.order();
- };
- function d3_selection_sortComparator(comparator) {
- if (!arguments.length) comparator = d3.ascending;
- return function(a, b) {
- return !a - !b || comparator(a.__data__, b.__data__);
- };
- }
- d3_selectionPrototype.each = function(callback) {
- return d3_selection_each(this, function(node, i, j) {
- callback.call(node, node.__data__, i, j);
- });
- };
- function d3_selection_each(groups, callback) {
- for (var j = 0, m = groups.length; j < m; j++) {
- for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
- if (node = group[i]) callback(node, i, j);
- }
- }
- return groups;
- }
- d3_selectionPrototype.call = function(callback) {
- var args = d3_array(arguments);
- callback.apply(args[0] = this, args);
- return this;
- };
- d3_selectionPrototype.empty = function() {
- return !this.node();
- };
- d3_selectionPrototype.node = function() {
- for (var j = 0, m = this.length; j < m; j++) {
- for (var group = this[j], i = 0, n = group.length; i < n; i++) {
- var node = group[i];
- if (node) return node;
- }
- }
- return null;
- };
- d3_selectionPrototype.size = function() {
- var n = 0;
- this.each(function() {
- ++n;
- });
- return n;
- };
- function d3_selection_enter(selection) {
- d3_arraySubclass(selection, d3_selection_enterPrototype);
- return selection;
- }
- var d3_selection_enterPrototype = [];
- d3.selection.enter = d3_selection_enter;
- d3.selection.enter.prototype = d3_selection_enterPrototype;
- d3_selection_enterPrototype.append = d3_selectionPrototype.append;
- d3_selection_enterPrototype.insert = d3_selectionPrototype.insert;
- d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
- d3_selection_enterPrototype.node = d3_selectionPrototype.node;
- d3_selection_enterPrototype.call = d3_selectionPrototype.call;
- d3_selection_enterPrototype.size = d3_selectionPrototype.size;
- d3_selection_enterPrototype.select = function(selector) {
- var subgroups = [], subgroup, subnode, upgroup, group, node;
- for (var j = -1, m = this.length; ++j < m; ) {
- upgroup = (group = this[j]).update;
- subgroups.push(subgroup = []);
- subgroup.parentNode = group.parentNode;
- for (var i = -1, n = group.length; ++i < n; ) {
- if (node = group[i]) {
- subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode,
node.__data__, i));
- subnode.__data__ = node.__data__;
- } else {
- subgroup.push(null);
- }
- }
- }
- return d3_selection(subgroups);
- };
- d3_selectionPrototype.transition = function() {
- var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node,
transition = Object.create(d3_transitionInherit);
- transition.time = Date.now();
- for (var j = -1, m = this.length; ++j < m; ) {
- subgroups.push(subgroup = []);
- for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
- if (node = group[i]) d3_transitionNode(node, i, id, transition);
- subgroup.push(node);
- }
- }
- return d3_transition(subgroups, id);
- };
- d3.select = function(node) {
- var group = [ typeof node === "string" ? d3_select(node, d3_document) :
node ];
- group.parentNode = d3_documentElement;
- return d3_selection([ group ]);
- };
- d3.selectAll = function(nodes) {
- var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes,
d3_document) : nodes);
- group.parentNode = d3_documentElement;
- return d3_selection([ group ]);
- };
- var d3_selectionRoot = d3.select(d3_documentElement);
- d3_selectionPrototype.on = function(type, listener, capture) {
- var n = arguments.length;
- if (n < 3) {
- if (typeof type !== "string") {
- if (n < 2) listener = false;
- for (capture in type) this.each(d3_selection_on(capture, type[capture],
listener));
- return this;
- }
- if (n < 2) return (n = this.node()["__on" + type]) && n._;
- capture = false;
- }
- return this.each(d3_selection_on(type, listener, capture));
- };
- function d3_selection_on(type, listener, capture) {
- var name = "__on" + type, i = type.indexOf("."), wrap =
d3_selection_onListener;
- if (i > 0) type = type.substring(0, i);
- var filter = d3_selection_onFilters.get(type);
- if (filter) type = filter, wrap = d3_selection_onFilter;
- function onRemove() {
- var l = this[name];
- if (l) {
- this.removeEventListener(type, l, l.$);
- delete this[name];
- }
- }
- function onAdd() {
- var l = wrap(listener, d3_array(arguments));
- onRemove.call(this);
- this.addEventListener(type, this[name] = l, l.$ = capture);
- l._ = listener;
- }
- function removeAll() {
- var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"),
match;
- for (var name in this) {
- if (match = name.match(re)) {
- var l = this[name];
- this.removeEventListener(match[1], l, l.$);
- delete this[name];
- }
- }
- }
- return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll;
- }
- var d3_selection_onFilters = d3.map({
- mouseenter: "mouseover",
- mouseleave: "mouseout"
- });
- d3_selection_onFilters.forEach(function(k) {
- if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
- });
- function d3_selection_onListener(listener, argumentz) {
- return function(e) {
- var o = d3.event;
- d3.event = e;
- argumentz[0] = this.__data__;
- try {
- listener.apply(this, argumentz);
- } finally {
- d3.event = o;
- }
- };
- }
- function d3_selection_onFilter(listener, argumentz) {
- var l = d3_selection_onListener(listener, argumentz);
- return function(e) {
- var target = this, related = e.relatedTarget;
- if (!related || related !== target &&
!(related.compareDocumentPosition(target) & 8)) {
- l.call(target, e);
- }
- };
- }
- var d3_event_dragSelect = d3_vendorSymbol(d3_documentElement.style,
"userSelect");
- function d3_event_dragSuppress(type) {
- var selectstart = "selectstart." + type, dragstart = "dragstart."
+ type, click = "click." + type, w = d3.select(d3_window).on(selectstart,
d3_eventPreventDefault).on(dragstart, d3_eventPreventDefault), style =
d3_documentElement.style, select = style[d3_event_dragSelect];
- style[d3_event_dragSelect] = "none";
- return function(suppressClick) {
- w.on(selectstart, null).on(dragstart, null);
- style[d3_event_dragSelect] = select;
- if (suppressClick) {
- function off() {
- w.on(click, null);
- }
- w.on(click, function() {
- d3_eventPreventDefault();
- off();
- }, true);
- setTimeout(off, 0);
- }
- };
- }
- d3.mouse = function(container) {
- return d3_mousePoint(container, d3_eventSource());
- };
- var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0;
- function d3_mousePoint(container, e) {
- var svg = container.ownerSVGElement || container;
- if (svg.createSVGPoint) {
- var point = svg.createSVGPoint();
- if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY))
{
- svg = d3.select("body").append("svg").style({
- position: "absolute",
- top: 0,
- left: 0,
- margin: 0,
- padding: 0,
- border: "none"
- }, "important");
- var ctm = svg[0][0].getScreenCTM();
- d3_mouse_bug44083 = !(ctm.f || ctm.e);
- svg.remove();
- }
- if (d3_mouse_bug44083) {
- point.x = e.pageX;
- point.y = e.pageY;
- } else {
- point.x = e.clientX;
- point.y = e.clientY;
- }
- point = point.matrixTransform(container.getScreenCTM().inverse());
- return [ point.x, point.y ];
- }
- var rect = container.getBoundingClientRect();
- return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top -
container.clientTop ];
- }
- d3.touches = function(container, touches) {
- if (arguments.length < 2) touches = d3_eventSource().touches;
- return touches ? d3_array(touches).map(function(touch) {
- var point = d3_mousePoint(container, touch);
- point.identifier = touch.identifier;
- return point;
- }) : [];
- };
- d3.behavior.drag = function() {
- var event = d3_eventDispatch(drag, "drag", "dragstart",
"dragend"), origin = null;
- function drag() {
- this.on("mousedown.drag", mousedown).on("touchstart.drag",
mousedown);
- }
- function mousedown() {
- var target = this, event_ = event.of(target, arguments), eventTarget =
d3.event.target, touchId = d3.event.touches ? d3.event.changedTouches[0].identifier :
null, offset, origin_ = point(), moved = 0, dragRestore = d3_event_dragSuppress(touchId !=
null ? "drag-" + touchId : "drag");
- var w = d3.select(d3_window).on(touchId != null ? "touchmove.drag-" +
touchId : "mousemove.drag", dragmove).on(touchId != null ?
"touchend.drag-" + touchId : "mouseup.drag", dragend, true);
- if (origin) {
- offset = origin.apply(target, arguments);
- offset = [ offset.x - origin_[0], offset.y - origin_[1] ];
- } else {
- offset = [ 0, 0 ];
- }
- event_({
- type: "dragstart"
- });
- function point() {
- var p = target.parentNode;
- return touchId != null ? d3.touches(p).filter(function(p) {
- return p.identifier === touchId;
- })[0] : d3.mouse(p);
- }
- function dragmove() {
- if (!target.parentNode) return dragend();
- var p = point(), dx = p[0] - origin_[0], dy = p[1] - origin_[1];
- moved |= dx | dy;
- origin_ = p;
- event_({
- type: "drag",
- x: p[0] + offset[0],
- y: p[1] + offset[1],
- dx: dx,
- dy: dy
- });
- }
- function dragend() {
- w.on(touchId != null ? "touchmove.drag-" + touchId :
"mousemove.drag", null).on(touchId != null ? "touchend.drag-" +
touchId : "mouseup.drag", null);
- dragRestore(moved && d3.event.target === eventTarget);
- event_({
- type: "dragend"
- });
- }
- }
- drag.origin = function(x) {
- if (!arguments.length) return origin;
- origin = x;
- return drag;
- };
- return d3.rebind(drag, event, "on");
- };
- d3.behavior.zoom = function() {
- var translate = [ 0, 0 ], translate0, scale = 1, distance0, scale0, scaleExtent =
d3_behavior_zoomInfinity, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0,
y1, touchtime;
- function zoom() {
- this.on("mousedown.zoom", mousedown).on("mousemove.zoom",
mousemove).on(d3_behavior_zoomWheel + ".zoom",
mousewheel).on("dblclick.zoom", dblclick).on("touchstart.zoom",
touchstart).on("touchmove.zoom", touchmove).on("touchend.zoom",
touchstart);
- }
- zoom.translate = function(x) {
- if (!arguments.length) return translate;
- translate = x.map(Number);
- rescale();
- return zoom;
- };
- zoom.scale = function(x) {
- if (!arguments.length) return scale;
- scale = +x;
- rescale();
- return zoom;
- };
- zoom.scaleExtent = function(x) {
- if (!arguments.length) return scaleExtent;
- scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number);
- return zoom;
- };
- zoom.x = function(z) {
- if (!arguments.length) return x1;
- x1 = z;
- x0 = z.copy();
- translate = [ 0, 0 ];
- scale = 1;
- return zoom;
- };
- zoom.y = function(z) {
- if (!arguments.length) return y1;
- y1 = z;
- y0 = z.copy();
- translate = [ 0, 0 ];
- scale = 1;
- return zoom;
- };
- function location(p) {
- return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ];
- }
- function point(l) {
- return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ];
- }
- function scaleTo(s) {
- scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
- }
- function translateTo(p, l) {
- l = point(l);
- translate[0] += p[0] - l[0];
- translate[1] += p[1] - l[1];
- }
- function rescale() {
- if (x1) x1.domain(x0.range().map(function(x) {
- return (x - translate[0]) / scale;
- }).map(x0.invert));
- if (y1) y1.domain(y0.range().map(function(y) {
- return (y - translate[1]) / scale;
- }).map(y0.invert));
- }
- function dispatch(event) {
- rescale();
- d3.event.preventDefault();
- event({
- type: "zoom",
- scale: scale,
- translate: translate
- });
- }
- function mousedown() {
- var target = this, event_ = event.of(target, arguments), eventTarget =
d3.event.target, moved = 0, w = d3.select(d3_window).on("mousemove.zoom",
mousemove).on("mouseup.zoom", mouseup), l = location(d3.mouse(target)),
dragRestore = d3_event_dragSuppress("zoom");
- function mousemove() {
- moved = 1;
- translateTo(d3.mouse(target), l);
- dispatch(event_);
- }
- function mouseup() {
- w.on("mousemove.zoom", null).on("mouseup.zoom", null);
- dragRestore(moved && d3.event.target === eventTarget);
- }
- }
- function mousewheel() {
- if (!translate0) translate0 = location(d3.mouse(this));
- scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale);
- translateTo(d3.mouse(this), translate0);
- dispatch(event.of(this, arguments));
- }
- function mousemove() {
- translate0 = null;
- }
- function dblclick() {
- var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2;
- scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));
- translateTo(p, l);
- dispatch(event.of(this, arguments));
- }
- function touchstart() {
- var touches = d3.touches(this), now = Date.now();
- scale0 = scale;
- translate0 = {};
- distance0 = 0;
- touches.forEach(function(t) {
- translate0[t.identifier] = location(t);
- });
- if (touches.length === 1) {
- if (now - touchtime < 500) {
- var p = touches[0], l = location(touches[0]);
- scaleTo(scale * 2);
- translateTo(p, l);
- dispatch(event.of(this, arguments));
- }
- touchtime = now;
- } else if (touches.length > 1) {
- var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1];
- distance0 = dx * dx + dy * dy;
- }
- }
- function touchmove() {
- var touches = d3.touches(this), p0 = touches[0], l0 = translate0[p0.identifier];
- if (p1 = touches[1]) {
- var p1, l1 = translate0[p1.identifier], scale1 = d3.event.scale;
- if (scale1 == null) {
- var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] -
p0[1]) * distance1;
- scale1 = distance0 && Math.sqrt(distance1 / distance0);
- }
- p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
- l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
- scaleTo(scale1 * scale0);
- }
- translateTo(p0, l0);
- touchtime = null;
- dispatch(event.of(this, arguments));
- }
- return d3.rebind(zoom, event, "on");
- };
- var d3_behavior_zoomInfinity = [ 0, Infinity ];
- var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ?
(d3_behavior_zoomDelta = function() {
- return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1);
- }, "wheel") : "onmousewheel" in d3_document ?
(d3_behavior_zoomDelta = function() {
- return d3.event.wheelDelta;
- }, "mousewheel") : (d3_behavior_zoomDelta = function() {
- return -d3.event.detail;
- }, "MozMousePixelScroll");
- function d3_Color() {}
- d3_Color.prototype.toString = function() {
- return this.rgb() + "";
- };
- d3.hsl = function(h, s, l) {
- return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) :
d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);
- };
- function d3_hsl(h, s, l) {
- return new d3_Hsl(h, s, l);
- }
- function d3_Hsl(h, s, l) {
- this.h = h;
- this.s = s;
- this.l = l;
- }
- var d3_hslPrototype = d3_Hsl.prototype = new d3_Color();
- d3_hslPrototype.brighter = function(k) {
- k = Math.pow(.7, arguments.length ? k : 1);
- return d3_hsl(this.h, this.s, this.l / k);
- };
- d3_hslPrototype.darker = function(k) {
- k = Math.pow(.7, arguments.length ? k : 1);
- return d3_hsl(this.h, this.s, k * this.l);
- };
- d3_hslPrototype.rgb = function() {
- return d3_hsl_rgb(this.h, this.s, this.l);
- };
- function d3_hsl_rgb(h, s, l) {
- var m1, m2;
- h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
- s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
- l = l < 0 ? 0 : l > 1 ? 1 : l;
- m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
- m1 = 2 * l - m2;
- function v(h) {
- if (h > 360) h -= 360; else if (h < 0) h += 360;
- if (h < 60) return m1 + (m2 - m1) * h / 60;
- if (h < 180) return m2;
- if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
- return m1;
- }
- function vv(h) {
- return Math.round(v(h) * 255);
- }
- return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
- }
- var Ï = Math.PI, ε = 1e-6, ε2 = ε * ε, d3_radians = Ï / 180, d3_degrees = 180 /
Ï;
- function d3_sgn(x) {
- return x > 0 ? 1 : x < 0 ? -1 : 0;
- }
- function d3_acos(x) {
- return x > 1 ? 0 : x < -1 ? Ï : Math.acos(x);
- }
- function d3_asin(x) {
- return x > 1 ? Ï / 2 : x < -1 ? -Ï / 2 : Math.asin(x);
- }
- function d3_sinh(x) {
- return (Math.exp(x) - Math.exp(-x)) / 2;
- }
- function d3_cosh(x) {
- return (Math.exp(x) + Math.exp(-x)) / 2;
- }
- function d3_haversin(x) {
- return (x = Math.sin(x / 2)) * x;
- }
- d3.hcl = function(h, c, l) {
- return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h
instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h =
d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l);
- };
- function d3_hcl(h, c, l) {
- return new d3_Hcl(h, c, l);
- }
- function d3_Hcl(h, c, l) {
- this.h = h;
- this.c = c;
- this.l = l;
- }
- var d3_hclPrototype = d3_Hcl.prototype = new d3_Color();
- d3_hclPrototype.brighter = function(k) {
- return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k
: 1)));
- };
- d3_hclPrototype.darker = function(k) {
- return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k :
1)));
- };
- d3_hclPrototype.rgb = function() {
- return d3_hcl_lab(this.h, this.c, this.l).rgb();
- };
- function d3_hcl_lab(h, c, l) {
- if (isNaN(h)) h = 0;
- if (isNaN(c)) c = 0;
- return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
- }
- d3.lab = function(l, a, b) {
- return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l
instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) :
d3_lab(+l, +a, +b);
- };
- function d3_lab(l, a, b) {
- return new d3_Lab(l, a, b);
- }
- function d3_Lab(l, a, b) {
- this.l = l;
- this.a = a;
- this.b = b;
- }
- var d3_lab_K = 18;
- var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
- var d3_labPrototype = d3_Lab.prototype = new d3_Color();
- d3_labPrototype.brighter = function(k) {
- return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a,
this.b);
- };
- d3_labPrototype.darker = function(k) {
- return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a,
this.b);
- };
- d3_labPrototype.rgb = function() {
- return d3_lab_rgb(this.l, this.a, this.b);
- };
- function d3_lab_rgb(l, a, b) {
- var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
- x = d3_lab_xyz(x) * d3_lab_X;
- y = d3_lab_xyz(y) * d3_lab_Y;
- z = d3_lab_xyz(z) * d3_lab_Z;
- return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z),
d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259
* y + 1.0572252 * z));
- }
- function d3_lab_hcl(l, a, b) {
- return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l)
: d3_hcl(NaN, NaN, l);
- }
- function d3_lab_xyz(x) {
- return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
- }
- function d3_xyz_lab(x) {
- return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
- }
- function d3_xyz_rgb(r) {
- return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) -
.055));
- }
- d3.rgb = function(r, g, b) {
- return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) :
d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b);
- };
- function d3_rgb(r, g, b) {
- return new d3_Rgb(r, g, b);
- }
- function d3_Rgb(r, g, b) {
- this.r = r;
- this.g = g;
- this.b = b;
- }
- var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color();
- d3_rgbPrototype.brighter = function(k) {
- k = Math.pow(.7, arguments.length ? k : 1);
- var r = this.r, g = this.g, b = this.b, i = 30;
- if (!r && !g && !b) return d3_rgb(i, i, i);
- if (r && r < i) r = i;
- if (g && g < i) g = i;
- if (b && b < i) b = i;
- return d3_rgb(Math.min(255, Math.floor(r / k)), Math.min(255, Math.floor(g / k)),
Math.min(255, Math.floor(b / k)));
- };
- d3_rgbPrototype.darker = function(k) {
- k = Math.pow(.7, arguments.length ? k : 1);
- return d3_rgb(Math.floor(k * this.r), Math.floor(k * this.g), Math.floor(k *
this.b));
- };
- d3_rgbPrototype.hsl = function() {
- return d3_rgb_hsl(this.r, this.g, this.b);
- };
- d3_rgbPrototype.toString = function() {
- return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
- };
- function d3_rgb_hex(v) {
- return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255,
v).toString(16);
- }
- function d3_rgb_parse(format, rgb, hsl) {
- var r = 0, g = 0, b = 0, m1, m2, name;
- m1 = /([a-z]+)\((.*)\)/i.exec(format);
- if (m1) {
- m2 = m1[2].split(",");
- switch (m1[1]) {
- case "hsl":
- {
- return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) /
100);
- }
-
- case "rgb":
- {
- return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]),
d3_rgb_parseNumber(m2[2]));
- }
- }
- }
- if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b);
- if (format != null && format.charAt(0) === "#") {
- if (format.length === 4) {
- r = format.charAt(1);
- r += r;
- g = format.charAt(2);
- g += g;
- b = format.charAt(3);
- b += b;
- } else if (format.length === 7) {
- r = format.substring(1, 3);
- g = format.substring(3, 5);
- b = format.substring(5, 7);
- }
- r = parseInt(r, 16);
- g = parseInt(g, 16);
- b = parseInt(b, 16);
- }
- return rgb(r, g, b);
- }
- function d3_rgb_hsl(r, g, b) {
- var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max -
min, h, s, l = (max + min) / 2;
- if (d) {
- s = l < .5 ? d / (max + min) : d / (2 - max - min);
- if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r)
/ d + 2; else h = (r - g) / d + 4;
- h *= 60;
- } else {
- h = NaN;
- s = l > 0 && l < 1 ? 0 : h;
- }
- return d3_hsl(h, s, l);
- }
- function d3_rgb_lab(r, g, b) {
- r = d3_rgb_xyz(r);
- g = d3_rgb_xyz(g);
- b = d3_rgb_xyz(b);
- var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y =
d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z =
d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
- return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
- }
- function d3_rgb_xyz(r) {
- return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
- }
- function d3_rgb_parseNumber(c) {
- var f = parseFloat(c);
- return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
- }
- var d3_rgb_names = d3.map({
- aliceblue: "#f0f8ff",
- antiquewhite: "#faebd7",
- aqua: "#00ffff",
- aquamarine: "#7fffd4",
- azure: "#f0ffff",
- beige: "#f5f5dc",
- bisque: "#ffe4c4",
- black: "#000000",
- blanchedalmond: "#ffebcd",
- blue: "#0000ff",
- blueviolet: "#8a2be2",
- brown: "#a52a2a",
- burlywood: "#deb887",
- cadetblue: "#5f9ea0",
- chartreuse: "#7fff00",
- chocolate: "#d2691e",
- coral: "#ff7f50",
- cornflowerblue: "#6495ed",
- cornsilk: "#fff8dc",
- crimson: "#dc143c",
- cyan: "#00ffff",
- darkblue: "#00008b",
- darkcyan: "#008b8b",
- darkgoldenrod: "#b8860b",
- darkgray: "#a9a9a9",
- darkgreen: "#006400",
- darkgrey: "#a9a9a9",
- darkkhaki: "#bdb76b",
- darkmagenta: "#8b008b",
- darkolivegreen: "#556b2f",
- darkorange: "#ff8c00",
- darkorchid: "#9932cc",
- darkred: "#8b0000",
- darksalmon: "#e9967a",
- darkseagreen: "#8fbc8f",
- darkslateblue: "#483d8b",
- darkslategray: "#2f4f4f",
- darkslategrey: "#2f4f4f",
- darkturquoise: "#00ced1",
- darkviolet: "#9400d3",
- deeppink: "#ff1493",
- deepskyblue: "#00bfff",
- dimgray: "#696969",
- dimgrey: "#696969",
- dodgerblue: "#1e90ff",
- firebrick: "#b22222",
- floralwhite: "#fffaf0",
- forestgreen: "#228b22",
- fuchsia: "#ff00ff",
- gainsboro: "#dcdcdc",
- ghostwhite: "#f8f8ff",
- gold: "#ffd700",
- goldenrod: "#daa520",
- gray: "#808080",
- green: "#008000",
- greenyellow: "#adff2f",
- grey: "#808080",
- honeydew: "#f0fff0",
- hotpink: "#ff69b4",
- indianred: "#cd5c5c",
- indigo: "#4b0082",
- ivory: "#fffff0",
- khaki: "#f0e68c",
- lavender: "#e6e6fa",
- lavenderblush: "#fff0f5",
- lawngreen: "#7cfc00",
- lemonchiffon: "#fffacd",
- lightblue: "#add8e6",
- lightcoral: "#f08080",
- lightcyan: "#e0ffff",
- lightgoldenrodyellow: "#fafad2",
- lightgray: "#d3d3d3",
- lightgreen: "#90ee90",
- lightgrey: "#d3d3d3",
- lightpink: "#ffb6c1",
- lightsalmon: "#ffa07a",
- lightseagreen: "#20b2aa",
- lightskyblue: "#87cefa",
- lightslategray: "#778899",
- lightslategrey: "#778899",
- lightsteelblue: "#b0c4de",
- lightyellow: "#ffffe0",
- lime: "#00ff00",
- limegreen: "#32cd32",
- linen: "#faf0e6",
- magenta: "#ff00ff",
- maroon: "#800000",
- mediumaquamarine: "#66cdaa",
- mediumblue: "#0000cd",
- mediumorchid: "#ba55d3",
- mediumpurple: "#9370db",
- mediumseagreen: "#3cb371",
- mediumslateblue: "#7b68ee",
- mediumspringgreen: "#00fa9a",
- mediumturquoise: "#48d1cc",
- mediumvioletred: "#c71585",
- midnightblue: "#191970",
- mintcream: "#f5fffa",
- mistyrose: "#ffe4e1",
- moccasin: "#ffe4b5",
- navajowhite: "#ffdead",
- navy: "#000080",
- oldlace: "#fdf5e6",
- olive: "#808000",
- olivedrab: "#6b8e23",
- orange: "#ffa500",
- orangered: "#ff4500",
- orchid: "#da70d6",
- palegoldenrod: "#eee8aa",
- palegreen: "#98fb98",
- paleturquoise: "#afeeee",
- palevioletred: "#db7093",
- papayawhip: "#ffefd5",
- peachpuff: "#ffdab9",
- peru: "#cd853f",
- pink: "#ffc0cb",
- plum: "#dda0dd",
- powderblue: "#b0e0e6",
- purple: "#800080",
- red: "#ff0000",
- rosybrown: "#bc8f8f",
- royalblue: "#4169e1",
- saddlebrown: "#8b4513",
- salmon: "#fa8072",
- sandybrown: "#f4a460",
- seagreen: "#2e8b57",
- seashell: "#fff5ee",
- sienna: "#a0522d",
- silver: "#c0c0c0",
- skyblue: "#87ceeb",
- slateblue: "#6a5acd",
- slategray: "#708090",
- slategrey: "#708090",
- snow: "#fffafa",
- springgreen: "#00ff7f",
- steelblue: "#4682b4",
- tan: "#d2b48c",
- teal: "#008080",
- thistle: "#d8bfd8",
- tomato: "#ff6347",
- turquoise: "#40e0d0",
- violet: "#ee82ee",
- wheat: "#f5deb3",
- white: "#ffffff",
- whitesmoke: "#f5f5f5",
- yellow: "#ffff00",
- yellowgreen: "#9acd32"
- });
- d3_rgb_names.forEach(function(key, value) {
- d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb));
- });
- function d3_functor(v) {
- return typeof v === "function" ? v : function() {
- return v;
- };
- }
- d3.functor = d3_functor;
- function d3_identity(d) {
- return d;
- }
- d3.xhr = d3_xhrType(d3_identity);
- function d3_xhrType(response) {
- return function(url, mimeType, callback) {
- if (arguments.length === 2 && typeof mimeType === "function")
callback = mimeType,
- mimeType = null;
- return d3_xhr(url, mimeType, response, callback);
- };
- }
- function d3_xhr(url, mimeType, response, callback) {
- var xhr = {}, dispatch = d3.dispatch("progress", "load",
"error"), headers = {}, request = new XMLHttpRequest(), responseType = null;
- if (d3_window.XDomainRequest && !("withCredentials" in request)
&& /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest();
- "onload" in request ? request.onload = request.onerror = respond :
request.onreadystatechange = function() {
- request.readyState > 3 && respond();
- };
- function respond() {
- var status = request.status, result;
- if (!status && request.responseText || status >= 200 && status
< 300 || status === 304) {
- try {
- result = response.call(xhr, request);
- } catch (e) {
- dispatch.error.call(xhr, e);
- return;
- }
- dispatch.load.call(xhr, result);
- } else {
- dispatch.error.call(xhr, request);
- }
- }
- request.onprogress = function(event) {
- var o = d3.event;
- d3.event = event;
- try {
- dispatch.progress.call(xhr, request);
- } finally {
- d3.event = o;
- }
- };
- xhr.header = function(name, value) {
- name = (name + "").toLowerCase();
- if (arguments.length < 2) return headers[name];
- if (value == null) delete headers[name]; else headers[name] = value +
"";
- return xhr;
- };
- xhr.mimeType = function(value) {
- if (!arguments.length) return mimeType;
- mimeType = value == null ? null : value + "";
- return xhr;
- };
- xhr.responseType = function(value) {
- if (!arguments.length) return responseType;
- responseType = value;
- return xhr;
- };
- xhr.response = function(value) {
- response = value;
- return xhr;
- };
- [ "get", "post" ].forEach(function(method) {
- xhr[method] = function() {
- return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));
- };
- });
- xhr.send = function(method, data, callback) {
- if (arguments.length === 2 && typeof data === "function")
callback = data, data = null;
- request.open(method, url, true);
- if (mimeType != null && !("accept" in headers))
headers["accept"] = mimeType + ",*/*";
- if (request.setRequestHeader) for (var name in headers)
request.setRequestHeader(name, headers[name]);
- if (mimeType != null && request.overrideMimeType)
request.overrideMimeType(mimeType);
- if (responseType != null) request.responseType = responseType;
- if (callback != null) xhr.on("error", callback).on("load",
function(request) {
- callback(null, request);
- });
- request.send(data == null ? null : data);
- return xhr;
- };
- xhr.abort = function() {
- request.abort();
- return xhr;
- };
- d3.rebind(xhr, dispatch, "on");
- return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
- }
- function d3_xhr_fixCallback(callback) {
- return callback.length === 1 ? function(error, request) {
- callback(error == null ? request : null);
- } : callback;
- }
- d3.dsv = function(delimiter, mimeType) {
- var reFormat = new RegExp('["' + delimiter + "\n]"),
delimiterCode = delimiter.charCodeAt(0);
- function dsv(url, row, callback) {
- if (arguments.length < 3) callback = row, row = null;
- var xhr = d3.xhr(url, mimeType, callback);
- xhr.row = function(_) {
- return arguments.length ? xhr.response((row = _) == null ? response :
typedResponse(_)) : row;
- };
- return xhr.row(row);
- }
- function response(request) {
- return dsv.parse(request.responseText);
- }
- function typedResponse(f) {
- return function(request) {
- return dsv.parse(request.responseText, f);
- };
- }
- dsv.parse = function(text, f) {
- var o;
- return dsv.parseRows(text, function(row, i) {
- if (o) return o(row, i - 1);
- var a = new Function("d", "return {" + row.map(function(name,
i) {
- return JSON.stringify(name) + ": d[" + i + "]";
- }).join(",") + "}");
- o = f ? function(row, i) {
- return f(a(row), i);
- } : a;
- });
- };
- dsv.parseRows = function(text, f) {
- var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
- function token() {
- if (I >= N) return EOF;
- if (eol) return eol = false, EOL;
- var j = I;
- if (text.charCodeAt(j) === 34) {
- var i = j;
- while (i++ < N) {
- if (text.charCodeAt(i) === 34) {
- if (text.charCodeAt(i + 1) !== 34) break;
- ++i;
- }
- }
- I = i + 2;
- var c = text.charCodeAt(i + 1);
- if (c === 13) {
- eol = true;
- if (text.charCodeAt(i + 2) === 10) ++I;
- } else if (c === 10) {
- eol = true;
- }
- return text.substring(j + 1, i).replace(/""/g, '"');
- }
- while (I < N) {
- var c = text.charCodeAt(I++), k = 1;
- if (c === 10) eol = true; else if (c === 13) {
- eol = true;
- if (text.charCodeAt(I) === 10) ++I, ++k;
- } else if (c !== delimiterCode) continue;
- return text.substring(j, I - k);
- }
- return text.substring(j);
- }
- while ((t = token()) !== EOF) {
- var a = [];
- while (t !== EOL && t !== EOF) {
- a.push(t);
- t = token();
- }
- if (f && !(a = f(a, n++))) continue;
- rows.push(a);
- }
- return rows;
- };
- dsv.format = function(rows) {
- if (Array.isArray(rows[0])) return dsv.formatRows(rows);
- var fieldSet = new d3_Set(), fields = [];
- rows.forEach(function(row) {
- for (var field in row) {
- if (!fieldSet.has(field)) {
- fields.push(fieldSet.add(field));
- }
- }
- });
- return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) {
- return fields.map(function(field) {
- return formatValue(row[field]);
- }).join(delimiter);
- })).join("\n");
- };
- dsv.formatRows = function(rows) {
- return rows.map(formatRow).join("\n");
- };
- function formatRow(row) {
- return row.map(formatValue).join(delimiter);
- }
- function formatValue(text) {
- return reFormat.test(text) ? '"' + text.replace(/\"/g,
'""') + '"' : text;
- }
- return dsv;
- };
- d3.csv = d3.dsv(",", "text/csv");
- d3.tsv = d3.dsv(" ", "text/tab-separated-values");
- var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout;
- d3.timer = function(callback, delay, then) {
- if (arguments.length < 3) {
- if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return;
- then = Date.now();
- }
- var time = then + delay;
- var timer = {
- callback: callback,
- time: time,
- next: null
- };
- if (d3_timer_queueTail) d3_timer_queueTail.next = timer; else d3_timer_queueHead =
timer;
- d3_timer_queueTail = timer;
- if (!d3_timer_interval) {
- d3_timer_timeout = clearTimeout(d3_timer_timeout);
- d3_timer_interval = 1;
- d3_timer_frame(d3_timer_step);
- }
- };
- function d3_timer_step() {
- var now = d3_timer_mark(), delay = d3_timer_sweep() - now;
- if (delay > 24) {
- if (isFinite(delay)) {
- clearTimeout(d3_timer_timeout);
- d3_timer_timeout = setTimeout(d3_timer_step, delay);
- }
- d3_timer_interval = 0;
- } else {
- d3_timer_interval = 1;
- d3_timer_frame(d3_timer_step);
- }
- }
- d3.timer.flush = function() {
- d3_timer_mark();
- d3_timer_sweep();
- };
- function d3_timer_mark() {
- var now = Date.now(), timer = d3_timer_queueHead;
- while (timer) {
- if (now >= timer.time) timer.flush = timer.callback(now - timer.time);
- timer = timer.next;
- }
- return now;
- }
- function d3_timer_sweep() {
- var t0, t1 = d3_timer_queueHead, time = Infinity;
- while (t1) {
- if (t1.flush) {
- t1 = t0 ? t0.next = t1.next : d3_timer_queueHead = t1.next;
- } else {
- if (t1.time < time) time = t1.time;
- t1 = (t0 = t1).next;
- }
- }
- d3_timer_queueTail = t0;
- return time;
- }
- var d3_timer_frame = d3_window[d3_vendorSymbol(d3_window,
"requestAnimationFrame")] || function(callback) {
- setTimeout(callback, 17);
- };
- var d3_format_decimalPoint = ".", d3_format_thousandsSeparator =
",", d3_format_grouping = [ 3, 3 ];
- var d3_formatPrefixes = [ "y", "z", "a", "f",
"p", "n", "µ", "m", "", "k",
"M", "G", "T", "P", "E", "Z",
"Y" ].map(d3_formatPrefix);
- d3.formatPrefix = function(value, precision) {
- var i = 0;
- if (value) {
- if (value < 0) value *= -1;
- if (precision) value = d3.round(value, d3_format_precision(value, precision));
- i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
- i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
- }
- return d3_formatPrefixes[8 + i / 3];
- };
- function d3_formatPrefix(d, i) {
- var k = Math.pow(10, Math.abs(8 - i) * 3);
- return {
- scale: i > 8 ? function(d) {
- return d / k;
- } : function(d) {
- return d * k;
- },
- symbol: d
- };
- }
- d3.round = function(x, n) {
- return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
- };
- d3.format = function(specifier) {
- var match = d3_format_re.exec(specifier), fill = match[1] || " ", align =
match[2] || ">", sign = match[3] || "", basePrefix = match[4] ||
"", zfill = match[5], width = +match[6], comma = match[7], precision = match[8],
type = match[9], scale = 1, suffix = "", integer = false;
- if (precision) precision = +precision.substring(1);
- if (zfill || fill === "0" && align === "=") {
- zfill = fill = "0";
- align = "=";
- if (comma) width -= Math.floor((width - 1) / 4);
- }
- switch (type) {
- case "n":
- comma = true;
- type = "g";
- break;
-
- case "%":
- scale = 100;
- suffix = "%";
- type = "f";
- break;
-
- case "p":
- scale = 100;
- suffix = "%";
- type = "r";
- break;
-
- case "b":
- case "o":
- case "x":
- case "X":
- if (basePrefix) basePrefix = "0" + type.toLowerCase();
-
- case "c":
- case "d":
- integer = true;
- precision = 0;
- break;
-
- case "s":
- scale = -1;
- type = "r";
- break;
- }
- if (basePrefix === "#") basePrefix = "";
- if (type == "r" && !precision) type = "g";
- if (precision != null) {
- if (type == "g") precision = Math.max(1, Math.min(21, precision)); else
if (type == "e" || type == "f") precision = Math.max(0, Math.min(20,
precision));
- }
- type = d3_format_types.get(type) || d3_format_typeDefault;
- var zcomma = zfill && comma;
- return function(value) {
- if (integer && value % 1) return "";
- var negative = value < 0 || value === 0 && 1 / value < 0 ? (value =
-value, "-") : sign;
- if (scale < 0) {
- var prefix = d3.formatPrefix(value, precision);
- value = prefix.scale(value);
- suffix = prefix.symbol;
- } else {
- value *= scale;
- }
- value = type(value, precision);
- if (!zfill && comma) value = d3_format_group(value);
- var length = basePrefix.length + value.length + (zcomma ? 0 : negative.length),
padding = length < width ? new Array(length = width - length + 1).join(fill) :
"";
- if (zcomma) value = d3_format_group(padding + value);
- if (d3_format_decimalPoint) value.replace(".", d3_format_decimalPoint);
- negative += basePrefix;
- return (align === "<" ? negative + value + padding : align ===
">" ? padding + negative + value : align === "^" ?
padding.substring(0, length >>= 1) + negative + value + padding.substring(length) :
negative + (zcomma ? value : padding + value)) + suffix;
- };
- };
- var d3_format_re = /(?:([^{])?([<>=^]))?([+\-
])?(#)?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
- var d3_format_types = d3.map({
- b: function(x) {
- return x.toString(2);
- },
- c: function(x) {
- return String.fromCharCode(x);
- },
- o: function(x) {
- return x.toString(8);
- },
- x: function(x) {
- return x.toString(16);
- },
- X: function(x) {
- return x.toString(16).toUpperCase();
- },
- g: function(x, p) {
- return x.toPrecision(p);
- },
- e: function(x, p) {
- return x.toExponential(p);
- },
- f: function(x, p) {
- return x.toFixed(p);
- },
- r: function(x, p) {
- return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0,
Math.min(20, d3_format_precision(x * (1 + 1e-15), p))));
- }
- });
- function d3_format_precision(x, p) {
- return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);
- }
- function d3_format_typeDefault(x) {
- return x + "";
- }
- var d3_format_group = d3_identity;
- if (d3_format_grouping) {
- var d3_format_groupingLength = d3_format_grouping.length;
- d3_format_group = function(value) {
- var i = value.lastIndexOf("."), f = i >= 0 ? "." +
value.substring(i + 1) : (i = value.length,
- ""), t = [], j = 0, g = d3_format_grouping[0];
- while (i > 0 && g > 0) {
- t.push(value.substring(i -= g, i + g));
- g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength];
- }
- return t.reverse().join(d3_format_thousandsSeparator || "") + f;
- };
- }
- d3.geo = {};
- function d3_adder() {}
- d3_adder.prototype = {
- s: 0,
- t: 0,
- add: function(y) {
- d3_adderSum(y, this.t, d3_adderTemp);
- d3_adderSum(d3_adderTemp.s, this.s, this);
- if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t;
- },
- reset: function() {
- this.s = this.t = 0;
- },
- valueOf: function() {
- return this.s;
- }
- };
- var d3_adderTemp = new d3_adder();
- function d3_adderSum(a, b, o) {
- var x = o.s = a + b, bv = x - a, av = x - bv;
- o.t = a - av + (b - bv);
- }
- d3.geo.stream = function(object, listener) {
- if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
- d3_geo_streamObjectType[object.type](object, listener);
- } else {
- d3_geo_streamGeometry(object, listener);
- }
- };
- function d3_geo_streamGeometry(geometry, listener) {
- if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
- d3_geo_streamGeometryType[geometry.type](geometry, listener);
- }
- }
- var d3_geo_streamObjectType = {
- Feature: function(feature, listener) {
- d3_geo_streamGeometry(feature.geometry, listener);
- },
- FeatureCollection: function(object, listener) {
- var features = object.features, i = -1, n = features.length;
- while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
- }
- };
- var d3_geo_streamGeometryType = {
- Sphere: function(object, listener) {
- listener.sphere();
- },
- Point: function(object, listener) {
- var coordinate = object.coordinates;
- listener.point(coordinate[0], coordinate[1]);
- },
- MultiPoint: function(object, listener) {
- var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate;
- while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0],
coordinate[1]);
- },
- LineString: function(object, listener) {
- d3_geo_streamLine(object.coordinates, listener, 0);
- },
- MultiLineString: function(object, listener) {
- var coordinates = object.coordinates, i = -1, n = coordinates.length;
- while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
- },
- Polygon: function(object, listener) {
- d3_geo_streamPolygon(object.coordinates, listener);
- },
- MultiPolygon: function(object, listener) {
- var coordinates = object.coordinates, i = -1, n = coordinates.length;
- while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
- },
- GeometryCollection: function(object, listener) {
- var geometries = object.geometries, i = -1, n = geometries.length;
- while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
- }
- };
- function d3_geo_streamLine(coordinates, listener, closed) {
- var i = -1, n = coordinates.length - closed, coordinate;
- listener.lineStart();
- while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0],
coordinate[1]);
- listener.lineEnd();
- }
- function d3_geo_streamPolygon(coordinates, listener) {
- var i = -1, n = coordinates.length;
- listener.polygonStart();
- while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
- listener.polygonEnd();
- }
- d3.geo.area = function(object) {
- d3_geo_areaSum = 0;
- d3.geo.stream(object, d3_geo_area);
- return d3_geo_areaSum;
- };
- var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder();
- var d3_geo_area = {
- sphere: function() {
- d3_geo_areaSum += 4 * Ï;
- },
- point: d3_noop,
- lineStart: d3_noop,
- lineEnd: d3_noop,
- polygonStart: function() {
- d3_geo_areaRingSum.reset();
- d3_geo_area.lineStart = d3_geo_areaRingStart;
- },
- polygonEnd: function() {
- var area = 2 * d3_geo_areaRingSum;
- d3_geo_areaSum += area < 0 ? 4 * Ï + area : area;
- d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
- }
- };
- function d3_geo_areaRingStart() {
- var λ00, Ï00, λ0, cosÏ0, sinÏ0;
- d3_geo_area.point = function(λ, Ï) {
- d3_geo_area.point = nextPoint;
- λ0 = (λ00 = λ) * d3_radians, cosÏ0 = Math.cos(Ï = (Ï00 = Ï) * d3_radians / 2
+ Ï / 4),
- sinÏ0 = Math.sin(Ï);
- };
- function nextPoint(λ, Ï) {
- λ *= d3_radians;
- Ï = Ï * d3_radians / 2 + Ï / 4;
- var dλ = λ - λ0, cosÏ = Math.cos(Ï), sinÏ = Math.sin(Ï), k = sinÏ0 * sinÏ,
u = cosÏ0 * cosÏ + k * Math.cos(dλ), v = k * Math.sin(dλ);
- d3_geo_areaRingSum.add(Math.atan2(v, u));
- λ0 = λ, cosÏ0 = cosÏ, sinÏ0 = sinÏ;
- }
- d3_geo_area.lineEnd = function() {
- nextPoint(λ00, Ï00);
- };
- }
- function d3_geo_cartesian(spherical) {
- var λ = spherical[0], Ï = spherical[1], cosÏ = Math.cos(Ï);
- return [ cosÏ * Math.cos(λ), cosÏ * Math.sin(λ), Math.sin(Ï) ];
- }
- function d3_geo_cartesianDot(a, b) {
- return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
- }
- function d3_geo_cartesianCross(a, b) {
- return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] *
b[0] ];
- }
- function d3_geo_cartesianAdd(a, b) {
- a[0] += b[0];
- a[1] += b[1];
- a[2] += b[2];
- }
- function d3_geo_cartesianScale(vector, k) {
- return [ vector[0] * k, vector[1] * k, vector[2] * k ];
- }
- function d3_geo_cartesianNormalize(d) {
- var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
- d[0] /= l;
- d[1] /= l;
- d[2] /= l;
- }
- function d3_geo_spherical(cartesian) {
- return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ];
- }
- function d3_geo_sphericalEqual(a, b) {
- return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε;
- }
- d3.geo.bounds = function() {
- var λ0, Ï0, λ1, Ï1, λ_, λ__, Ï__, p0, dλSum, ranges, range;
- var bound = {
- point: point,
- lineStart: lineStart,
- lineEnd: lineEnd,
- polygonStart: function() {
- bound.point = ringPoint;
- bound.lineStart = ringStart;
- bound.lineEnd = ringEnd;
- dλSum = 0;
- d3_geo_area.polygonStart();
- },
- polygonEnd: function() {
- d3_geo_area.polygonEnd();
- bound.point = point;
- bound.lineStart = lineStart;
- bound.lineEnd = lineEnd;
- if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), Ï0 = -(Ï1 = 90); else if
(dλSum > ε) Ï1 = 90; else if (dλSum < -ε) Ï0 = -90;
- range[0] = λ0, range[1] = λ1;
- }
- };
- function point(λ, Ï) {
- ranges.push(range = [ λ0 = λ, λ1 = λ ]);
- if (Ï < Ï0) Ï0 = Ï;
- if (Ï > Ï1) Ï1 = Ï;
- }
- function linePoint(λ, Ï) {
- var p = d3_geo_cartesian([ λ * d3_radians, Ï * d3_radians ]);
- if (p0) {
- var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0],
0 ], inflection = d3_geo_cartesianCross(equatorial, normal);
- d3_geo_cartesianNormalize(inflection);
- inflection = d3_geo_spherical(inflection);
- var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees *
s, antimeridian = Math.abs(dλ) > 180;
- if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
- var Ïi = inflection[1] * d3_degrees;
- if (Ïi > Ï1) Ï1 = Ïi;
- } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi
&& λi < s * λ)) {
- var Ïi = -inflection[1] * d3_degrees;
- if (Ïi < Ï0) Ï0 = Ïi;
- } else {
- if (Ï < Ï0) Ï0 = Ï;
- if (Ï > Ï1) Ï1 = Ï;
- }
- if (antimeridian) {
- if (λ < λ_) {
- if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
- } else {
- if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
- }
- } else {
- if (λ1 >= λ0) {
- if (λ < λ0) λ0 = λ;
- if (λ > λ1) λ1 = λ;
- } else {
- if (λ > λ_) {
- if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
- } else {
- if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
- }
- }
- }
- } else {
- point(λ, Ï);
- }
- p0 = p, λ_ = λ;
- }
- function lineStart() {
- bound.point = linePoint;
- }
- function lineEnd() {
- range[0] = λ0, range[1] = λ1;
- bound.point = point;
- p0 = null;
- }
- function ringPoint(λ, Ï) {
- if (p0) {
- var dλ = λ - λ_;
- dλSum += Math.abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
- } else λ__ = λ, Ï__ = Ï;
- d3_geo_area.point(λ, Ï);
- linePoint(λ, Ï);
- }
- function ringStart() {
- d3_geo_area.lineStart();
- }
- function ringEnd() {
- ringPoint(λ__, Ï__);
- d3_geo_area.lineEnd();
- if (Math.abs(dλSum) > ε) λ0 = -(λ1 = 180);
- range[0] = λ0, range[1] = λ1;
- p0 = null;
- }
- function angle(λ0, λ1) {
- return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1;
- }
- function compareRanges(a, b) {
- return a[0] - b[0];
- }
- function withinRange(x, range) {
- return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x
< range[0] || range[1] < x;
- }
- return function(feature) {
- Ï1 = λ1 = -(λ0 = Ï0 = Infinity);
- ranges = [];
- d3.geo.stream(feature, bound);
- var n = ranges.length;
- if (n) {
- ranges.sort(compareRanges);
- for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) {
- b = ranges[i];
- if (withinRange(b[0], a) || withinRange(b[1], a)) {
- if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
- if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
- } else {
- merged.push(a = b);
- }
- }
- var best = -Infinity, dλ;
- for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i)
{
- b = merged[i];
- if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
- }
- }
- ranges = range = null;
- return λ0 === Infinity || Ï0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [
λ0, Ï0 ], [ λ1, Ï1 ] ];
- };
- }();
- d3.geo.centroid = function(object) {
- d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 =
d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 =
d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
- d3.geo.stream(object, d3_geo_centroid);
- var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x +
y * y + z * z;
- if (m < ε2) {
- x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
- if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z =
d3_geo_centroidZ0;
- m = x * x + y * y + z * z;
- if (m < ε2) return [ NaN, NaN ];
- }
- return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ];
- };
- var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0,
d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1,
d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2;
- var d3_geo_centroid = {
- sphere: d3_noop,
- point: d3_geo_centroidPoint,
- lineStart: d3_geo_centroidLineStart,
- lineEnd: d3_geo_centroidLineEnd,
- polygonStart: function() {
- d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
- },
- polygonEnd: function() {
- d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
- }
- };
- function d3_geo_centroidPoint(λ, Ï) {
- λ *= d3_radians;
- var cosÏ = Math.cos(Ï *= d3_radians);
- d3_geo_centroidPointXYZ(cosÏ * Math.cos(λ), cosÏ * Math.sin(λ), Math.sin(Ï));
- }
- function d3_geo_centroidPointXYZ(x, y, z) {
- ++d3_geo_centroidW0;
- d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
- d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
- d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
- }
- function d3_geo_centroidLineStart() {
- var x0, y0, z0;
- d3_geo_centroid.point = function(λ, Ï) {
- λ *= d3_radians;
- var cosÏ = Math.cos(Ï *= d3_radians);
- x0 = cosÏ * Math.cos(λ);
- y0 = cosÏ * Math.sin(λ);
- z0 = Math.sin(Ï);
- d3_geo_centroid.point = nextPoint;
- d3_geo_centroidPointXYZ(x0, y0, z0);
- };
- function nextPoint(λ, Ï) {
- λ *= d3_radians;
- var cosÏ = Math.cos(Ï *= d3_radians), x = cosÏ * Math.cos(λ), y = cosÏ *
Math.sin(λ), z = Math.sin(Ï), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w =
z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
- d3_geo_centroidW1 += w;
- d3_geo_centroidX1 += w * (x0 + (x0 = x));
- d3_geo_centroidY1 += w * (y0 + (y0 = y));
- d3_geo_centroidZ1 += w * (z0 + (z0 = z));
- d3_geo_centroidPointXYZ(x0, y0, z0);
- }
- }
- function d3_geo_centroidLineEnd() {
- d3_geo_centroid.point = d3_geo_centroidPoint;
- }
- function d3_geo_centroidRingStart() {
- var λ00, Ï00, x0, y0, z0;
- d3_geo_centroid.point = function(λ, Ï) {
- λ00 = λ, Ï00 = Ï;
- d3_geo_centroid.point = nextPoint;
- λ *= d3_radians;
- var cosÏ = Math.cos(Ï *= d3_radians);
- x0 = cosÏ * Math.cos(λ);
- y0 = cosÏ * Math.sin(λ);
- z0 = Math.sin(Ï);
- d3_geo_centroidPointXYZ(x0, y0, z0);
- };
- d3_geo_centroid.lineEnd = function() {
- nextPoint(λ00, Ï00);
- d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
- d3_geo_centroid.point = d3_geo_centroidPoint;
- };
- function nextPoint(λ, Ï) {
- λ *= d3_radians;
- var cosÏ = Math.cos(Ï *= d3_radians), x = cosÏ * Math.cos(λ), y = cosÏ *
Math.sin(λ), z = Math.sin(Ï), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y -
y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m
&& -d3_acos(u) / m, w = Math.atan2(m, u);
- d3_geo_centroidX2 += v * cx;
- d3_geo_centroidY2 += v * cy;
- d3_geo_centroidZ2 += v * cz;
- d3_geo_centroidW1 += w;
- d3_geo_centroidX1 += w * (x0 + (x0 = x));
- d3_geo_centroidY1 += w * (y0 + (y0 = y));
- d3_geo_centroidZ1 += w * (z0 + (z0 = z));
- d3_geo_centroidPointXYZ(x0, y0, z0);
- }
- }
- function d3_true() {
- return true;
- }
- function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) {
- var subject = [], clip = [];
- segments.forEach(function(segment) {
- if ((n = segment.length - 1) <= 0) return;
- var n, p0 = segment[0], p1 = segment[n];
- if (d3_geo_sphericalEqual(p0, p1)) {
- listener.lineStart();
- for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
- listener.lineEnd();
- return;
- }
- var a = {
- point: p0,
- points: segment,
- other: null,
- visited: false,
- entry: true,
- subject: true
- }, b = {
- point: p0,
- points: [ p0 ],
- other: a,
- visited: false,
- entry: false,
- subject: false
- };
- a.other = b;
- subject.push(a);
- clip.push(b);
- a = {
- point: p1,
- points: [ p1 ],
- other: null,
- visited: false,
- entry: false,
- subject: true
- };
- b = {
- point: p1,
- points: [ p1 ],
- other: a,
- visited: false,
- entry: true,
- subject: false
- };
- a.other = b;
- subject.push(a);
- clip.push(b);
- });
- clip.sort(compare);
- d3_geo_clipPolygonLinkCircular(subject);
- d3_geo_clipPolygonLinkCircular(clip);
- if (!subject.length) return;
- if (inside) for (var i = 1, e = !inside(clip[0].point), n = clip.length; i < n;
++i) {
- clip[i].entry = e = !e;
- }
- var start = subject[0], current, points, point;
- while (1) {
- current = start;
- while (current.visited) if ((current = current.next) === start) return;
- points = current.points;
- listener.lineStart();
- do {
- current.visited = current.other.visited = true;
- if (current.entry) {
- if (current.subject) {
- for (var i = 0; i < points.length; i++) listener.point((point =
points[i])[0], point[1]);
- } else {
- interpolate(current.point, current.next.point, 1, listener);
- }
- current = current.next;
- } else {
- if (current.subject) {
- points = current.prev.points;
- for (var i = points.length; --i >= 0; ) listener.point((point =
points[i])[0], point[1]);
- } else {
- interpolate(current.point, current.prev.point, -1, listener);
- }
- current = current.prev;
- }
- current = current.other;
- points = current.points;
- } while (!current.visited);
- listener.lineEnd();
- }
- }
- function d3_geo_clipPolygonLinkCircular(array) {
- if (!(n = array.length)) return;
- var n, i = 0, a = array[0], b;
- while (++i < n) {
- a.next = b = array[i];
- b.prev = a;
- a = b;
- }
- a.next = b = array[0];
- b.prev = a;
- }
- function d3_geo_clip(pointVisible, clipLine, interpolate, polygonContains) {
- return function(listener) {
- var line = clipLine(listener);
- var clip = {
- point: point,
- lineStart: lineStart,
- lineEnd: lineEnd,
- polygonStart: function() {
- clip.point = pointRing;
- clip.lineStart = ringStart;
- clip.lineEnd = ringEnd;
- segments = [];
- polygon = [];
- listener.polygonStart();
- },
- polygonEnd: function() {
- clip.point = point;
- clip.lineStart = lineStart;
- clip.lineEnd = lineEnd;
- segments = d3.merge(segments);
- if (segments.length) {
- d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener);
- } else if (polygonContains(polygon)) {
- listener.lineStart();
- interpolate(null, null, 1, listener);
- listener.lineEnd();
- }
- listener.polygonEnd();
- segments = polygon = null;
- },
- sphere: function() {
- listener.polygonStart();
- listener.lineStart();
- interpolate(null, null, 1, listener);
- listener.lineEnd();
- listener.polygonEnd();
- }
- };
- function point(λ, Ï) {
- if (pointVisible(λ, Ï)) listener.point(λ, Ï);
- }
- function pointLine(λ, Ï) {
- line.point(λ, Ï);
- }
- function lineStart() {
- clip.point = pointLine;
- line.lineStart();
- }
- function lineEnd() {
- clip.point = point;
- line.lineEnd();
- }
- var segments;
- var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon,
ring;
- function pointRing(λ, Ï) {
- ringListener.point(λ, Ï);
- ring.push([ λ, Ï ]);
- }
- function ringStart() {
- ringListener.lineStart();
- ring = [];
- }
- function ringEnd() {
- pointRing(ring[0][0], ring[0][1]);
- ringListener.lineEnd();
- var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n =
ringSegments.length;
- ring.pop();
- polygon.push(ring);
- ring = null;
- if (!n) return;
- if (clean & 1) {
- segment = ringSegments[0];
- var n = segment.length - 1, i = -1, point;
- listener.lineStart();
- while (++i < n) listener.point((point = segment[i])[0], point[1]);
- listener.lineEnd();
- return;
- }
- if (n > 1 && clean & 2)
ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
- segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
- }
- return clip;
- };
- }
- function d3_geo_clipSegmentLength1(segment) {
- return segment.length > 1;
- }
- function d3_geo_clipBufferListener() {
- var lines = [], line;
- return {
- lineStart: function() {
- lines.push(line = []);
- },
- point: function(λ, Ï) {
- line.push([ λ, Ï ]);
- },
- lineEnd: d3_noop,
- buffer: function() {
- var buffer = lines;
- lines = [];
- line = null;
- return buffer;
- },
- rejoin: function() {
- if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
- }
- };
- }
- function d3_geo_clipSort(a, b) {
- return ((a = a.point)[0] < 0 ? a[1] - Ï / 2 - ε : Ï / 2 - a[1]) - ((b =
b.point)[0] < 0 ? b[1] - Ï / 2 - ε : Ï / 2 - b[1]);
- }
- function d3_geo_pointInPolygon(point, polygon) {
- var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian),
-Math.cos(meridian), 0 ], polarAngle = 0, polar = false, southPole = false, winding = 0;
- d3_geo_areaRingSum.reset();
- for (var i = 0, n = polygon.length; i < n; ++i) {
- var ring = polygon[i], m = ring.length;
- if (!m) continue;
- var point0 = ring[0], λ0 = point0[0], Ï0 = point0[1] / 2 + Ï / 4, sinÏ0 =
Math.sin(Ï0), cosÏ0 = Math.cos(Ï0), j = 1;
- while (true) {
- if (j === m) j = 0;
- point = ring[j];
- var λ = point[0], Ï = point[1] / 2 + Ï / 4, sinÏ = Math.sin(Ï), cosÏ =
Math.cos(Ï), dλ = λ - λ0, antimeridian = Math.abs(dλ) > Ï, k = sinÏ0 * sinÏ;
- d3_geo_areaRingSum.add(Math.atan2(k * Math.sin(dλ), cosÏ0 * cosÏ + k *
Math.cos(dλ)));
- if (Math.abs(Ï) < ε) southPole = true;
- polarAngle += antimeridian ? dλ + (dλ >= 0 ? 2 : -2) * Ï : dλ;
- if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
- var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0),
d3_geo_cartesian(point));
- d3_geo_cartesianNormalize(arc);
- var intersection = d3_geo_cartesianCross(meridianNormal, arc);
- d3_geo_cartesianNormalize(intersection);
- var Ïarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
- if (parallel > Ïarc) {
- winding += antimeridian ^ dλ >= 0 ? 1 : -1;
- }
- }
- if (!j++) break;
- λ0 = λ, sinÏ0 = sinÏ, cosÏ0 = cosÏ, point0 = point;
- }
- if (Math.abs(polarAngle) > ε) polar = true;
- }
- return (!southPole && !polar && d3_geo_areaRingSum < 0 ||
polarAngle < -ε) ^ winding & 1;
- }
- var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine,
d3_geo_clipAntimeridianInterpolate, d3_geo_clipAntimeridianPolygonContains);
- function d3_geo_clipAntimeridianLine(listener) {
- var λ0 = NaN, Ï0 = NaN, sλ0 = NaN, clean;
- return {
- lineStart: function() {
- listener.lineStart();
- clean = 1;
- },
- point: function(λ1, Ï1) {
- var sλ1 = λ1 > 0 ? Ï : -Ï, dλ = Math.abs(λ1 - λ0);
- if (Math.abs(dλ - Ï) < ε) {
- listener.point(λ0, Ï0 = (Ï0 + Ï1) / 2 > 0 ? Ï / 2 : -Ï / 2);
- listener.point(sλ0, Ï0);
- listener.lineEnd();
- listener.lineStart();
- listener.point(sλ1, Ï0);
- listener.point(λ1, Ï0);
- clean = 0;
- } else if (sλ0 !== sλ1 && dλ >= Ï) {
- if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
- if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
- Ï0 = d3_geo_clipAntimeridianIntersect(λ0, Ï0, λ1, Ï1);
- listener.point(sλ0, Ï0);
- listener.lineEnd();
- listener.lineStart();
- listener.point(sλ1, Ï0);
- clean = 0;
- }
- listener.point(λ0 = λ1, Ï0 = Ï1);
- sλ0 = sλ1;
- },
- lineEnd: function() {
- listener.lineEnd();
- λ0 = Ï0 = NaN;
- },
- clean: function() {
- return 2 - clean;
- }
- };
- }
- function d3_geo_clipAntimeridianIntersect(λ0, Ï0, λ1, Ï1) {
- var cosÏ0, cosÏ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
- return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(Ï0) * (cosÏ1 =
Math.cos(Ï1)) * Math.sin(λ1) - Math.sin(Ï1) * (cosÏ0 = Math.cos(Ï0)) * Math.sin(λ0))
/ (cosÏ0 * cosÏ1 * sinλ0_λ1)) : (Ï0 + Ï1) / 2;
- }
- function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
- var Ï;
- if (from == null) {
- Ï = direction * Ï / 2;
- listener.point(-Ï, Ï);
- listener.point(0, Ï);
- listener.point(Ï, Ï);
- listener.point(Ï, 0);
- listener.point(Ï, -Ï);
- listener.point(0, -Ï);
- listener.point(-Ï, -Ï);
- listener.point(-Ï, 0);
- listener.point(-Ï, Ï);
- } else if (Math.abs(from[0] - to[0]) > ε) {
- var s = (from[0] < to[0] ? 1 : -1) * Ï;
- Ï = direction * s / 2;
- listener.point(-s, Ï);
- listener.point(0, Ï);
- listener.point(s, Ï);
- } else {
- listener.point(to[0], to[1]);
- }
- }
- var d3_geo_clipAntimeridianPoint = [ -Ï, 0 ];
- function d3_geo_clipAntimeridianPolygonContains(polygon) {
- return d3_geo_pointInPolygon(d3_geo_clipAntimeridianPoint, polygon);
- }
- function d3_geo_clipCircle(radius) {
- var cr = Math.cos(radius), smallRadius = cr > 0, point = [ radius, 0 ],
notHemisphere = Math.abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 *
d3_radians);
- return d3_geo_clip(visible, clipLine, interpolate, polygonContains);
- function visible(λ, Ï) {
- return Math.cos(λ) * Math.cos(Ï) > cr;
- }
- function clipLine(listener) {
- var point0, c0, v0, v00, clean;
- return {
- lineStart: function() {
- v00 = v0 = false;
- clean = 1;
- },
- point: function(λ, Ï) {
- var point1 = [ λ, Ï ], point2, v = visible(λ, Ï), c = smallRadius ? v ? 0 :
code(λ, Ï) : v ? code(λ + (λ < 0 ? Ï : -Ï), Ï) : 0;
- if (!point0 && (v00 = v0 = v)) listener.lineStart();
- if (v !== v0) {
- point2 = intersect(point0, point1);
- if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1,
point2)) {
- point1[0] += ε;
- point1[1] += ε;
- v = visible(point1[0], point1[1]);
- }
- }
- if (v !== v0) {
- clean = 0;
- if (v) {
- listener.lineStart();
- point2 = intersect(point1, point0);
- listener.point(point2[0], point2[1]);
- } else {
- point2 = intersect(point0, point1);
- listener.point(point2[0], point2[1]);
- listener.lineEnd();
- }
- point0 = point2;
- } else if (notHemisphere && point0 && smallRadius ^ v) {
- var t;
- if (!(c & c0) && (t = intersect(point1, point0, true))) {
- clean = 0;
- if (smallRadius) {
- listener.lineStart();
- listener.point(t[0][0], t[0][1]);
- listener.point(t[1][0], t[1][1]);
- listener.lineEnd();
- } else {
- listener.point(t[1][0], t[1][1]);
- listener.lineEnd();
- listener.lineStart();
- listener.point(t[0][0], t[0][1]);
- }
- }
- }
- if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
- listener.point(point1[0], point1[1]);
- }
- point0 = point1, v0 = v, c0 = c;
- },
- lineEnd: function() {
- if (v0) listener.lineEnd();
- point0 = null;
- },
- clean: function() {
- return clean | (v00 && v0) << 1;
- }
- };
- }
- function intersect(a, b, two) {
- var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b);
- var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 =
d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
- if (!determinant) return !two && a;
- var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 =
d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B =
d3_geo_cartesianScale(n2, c2);
- d3_geo_cartesianAdd(A, B);
- var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 =
w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
- if (t2 < 0) return;
- var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu);
- d3_geo_cartesianAdd(q, A);
- q = d3_geo_spherical(q);
- if (!two) return q;
- var λ0 = a[0], λ1 = b[0], Ï0 = a[1], Ï1 = b[1], z;
- if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
- var Ύλ = λ1 - λ0, polar = Math.abs(Ύλ - Ï) < ε, meridian = polar || Ύλ
< ε;
- if (!polar && Ï1 < Ï0) z = Ï0, Ï0 = Ï1, Ï1 = z;
- if (meridian ? polar ? Ï0 + Ï1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ?
Ï0 : Ï1) : Ï0 <= q[1] && q[1] <= Ï1 : Ύλ > Ï ^ (λ0 <= q[0]
&& q[0] <= λ1)) {
- var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
- d3_geo_cartesianAdd(q1, A);
- return [ q, d3_geo_spherical(q1) ];
- }
- }
- function code(λ, Ï) {
- var r = smallRadius ? radius : Ï - radius, code = 0;
- if (λ < -r) code |= 1; else if (λ > r) code |= 2;
- if (Ï < -r) code |= 4; else if (Ï > r) code |= 8;
- return code;
- }
- function polygonContains(polygon) {
- return d3_geo_pointInPolygon(point, polygon);
- }
- }
- var d3_geo_clipViewMAX = 1e9;
- function d3_geo_clipView(x0, y0, x1, y1) {
- return function(listener) {
- var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments,
polygon, ring;
- var clip = {
- point: point,
- lineStart: lineStart,
- lineEnd: lineEnd,
- polygonStart: function() {
- listener = bufferListener;
- segments = [];
- polygon = [];
- },
- polygonEnd: function() {
- listener = listener_;
- if ((segments = d3.merge(segments)).length) {
- listener.polygonStart();
- d3_geo_clipPolygon(segments, compare, inside, interpolate, listener);
- listener.polygonEnd();
- } else if (insidePolygon([ x0, y0 ])) {
- listener.polygonStart(), listener.lineStart();
- interpolate(null, null, 1, listener);
- listener.lineEnd(), listener.polygonEnd();
- }
- segments = polygon = ring = null;
- }
- };
- function inside(point) {
- var a = corner(point, -1), i = insidePolygon([ a === 0 || a === 3 ? x0 : x1, a
> 1 ? y1 : y0 ]);
- return i;
- }
- function insidePolygon(p) {
- var wn = 0, n = polygon.length, y = p[1];
- for (var i = 0; i < n; ++i) {
- for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
- b = v[j];
- if (a[1] <= y) {
- if (b[1] > y && isLeft(a, b, p) > 0) ++wn;
- } else {
- if (b[1] <= y && isLeft(a, b, p) < 0) --wn;
- }
- a = b;
- }
- }
- return wn !== 0;
- }
- function isLeft(a, b, c) {
- return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
- }
- function interpolate(from, to, direction, listener) {
- var a = 0, a1 = 0;
- if (from == null || (a = corner(from, direction)) !== (a1 = corner(to,
direction)) || comparePoints(from, to) < 0 ^ direction > 0) {
- do {
- listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
- } while ((a = (a + direction + 4) % 4) !== a1);
- } else {
- listener.point(to[0], to[1]);
- }
- }
- function visible(x, y) {
- return x0 <= x && x <= x1 && y0 <= y && y <=
y1;
- }
- function point(x, y) {
- if (visible(x, y)) listener.point(x, y);
- }
- var x__, y__, v__, x_, y_, v_, first;
- function lineStart() {
- clip.point = linePoint;
- if (polygon) polygon.push(ring = []);
- first = true;
- v_ = false;
- x_ = y_ = NaN;
- }
- function lineEnd() {
- if (segments) {
- linePoint(x__, y__);
- if (v__ && v_) bufferListener.rejoin();
- segments.push(bufferListener.buffer());
- }
- clip.point = point;
- if (v_) listener.lineEnd();
- }
- function linePoint(x, y) {
- x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x));
- y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y));
- var v = visible(x, y);
- if (polygon) ring.push([ x, y ]);
- if (first) {
- x__ = x, y__ = y, v__ = v;
- first = false;
- if (v) {
- listener.lineStart();
- listener.point(x, y);
- }
- } else {
- if (v && v_) listener.point(x, y); else {
- var a = [ x_, y_ ], b = [ x, y ];
- if (clipLine(a, b)) {
- if (!v_) {
- listener.lineStart();
- listener.point(a[0], a[1]);
- }
- listener.point(b[0], b[1]);
- if (!v) listener.lineEnd();
- } else if (v) {
- listener.lineStart();
- listener.point(x, y);
- }
- }
- }
- x_ = x, y_ = y, v_ = v;
- }
- return clip;
- };
- function corner(p, direction) {
- return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1)
< ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 :
0 : direction > 0 ? 3 : 2;
- }
- function compare(a, b) {
- return comparePoints(a.point, b.point);
- }
- function comparePoints(a, b) {
- var ca = corner(a, 1), cb = corner(b, 1);
- return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca
=== 2 ? a[1] - b[1] : b[0] - a[0];
- }
- function clipLine(a, b) {
- var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ];
- if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0]
&& a[0] <= x1 && y0 <= a[1] && a[1] <= y1;
- if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx,
t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1,
-dy, t)) {
- if (t[1] < 1) {
- b[0] = a[0] + t[1] * dx;
- b[1] = a[1] + t[1] * dy;
- }
- if (t[0] > 0) {
- a[0] += t[0] * dx;
- a[1] += t[0] * dy;
- }
- return true;
- }
- return false;
- }
- }
- function d3_geo_clipViewT(num, denominator, t) {
- if (Math.abs(denominator) < ε) return num <= 0;
- var u = num / denominator;
- if (denominator > 0) {
- if (u > t[1]) return false;
- if (u > t[0]) t[0] = u;
- } else {
- if (u < t[0]) return false;
- if (u < t[1]) t[1] = u;
- }
- return true;
- }
- function d3_geo_compose(a, b) {
- function compose(x, y) {
- return x = a(x, y), b(x[0], x[1]);
- }
- if (a.invert && b.invert) compose.invert = function(x, y) {
- return x = b.invert(x, y), x && a.invert(x[0], x[1]);
- };
- return compose;
- }
- function d3_geo_conic(projectAt) {
- var Ï0 = 0, Ï1 = Ï / 3, m = d3_geo_projectionMutator(projectAt), p = m(Ï0, Ï1);
- p.parallels = function(_) {
- if (!arguments.length) return [ Ï0 / Ï * 180, Ï1 / Ï * 180 ];
- return m(Ï0 = _[0] * Ï / 180, Ï1 = _[1] * Ï / 180);
- };
- return p;
- }
- function d3_geo_conicEqualArea(Ï0, Ï1) {
- var sinÏ0 = Math.sin(Ï0), n = (sinÏ0 + Math.sin(Ï1)) / 2, C = 1 + sinÏ0 * (2 * n
- sinÏ0), Ï0 = Math.sqrt(C) / n;
- function forward(λ, Ï) {
- var Ï = Math.sqrt(C - 2 * n * Math.sin(Ï)) / n;
- return [ Ï * Math.sin(λ *= n), Ï0 - Ï * Math.cos(λ) ];
- }
- forward.invert = function(x, y) {
- var Ï0_y = Ï0 - y;
- return [ Math.atan2(x, Ï0_y) / n, d3_asin((C - (x * x + Ï0_y * Ï0_y) * n * n) /
(2 * n)) ];
- };
- return forward;
- }
- (d3.geo.conicEqualArea = function() {
- return d3_geo_conic(d3_geo_conicEqualArea);
- }).raw = d3_geo_conicEqualArea;
- d3.geo.albers = function() {
- return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([
29.5, 45.5 ]).scale(1070);
- };
- d3.geo.albersUsa = function() {
- var lower48 = d3.geo.albers();
- var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5
]).parallels([ 55, 65 ]);
- var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9
]).parallels([ 8, 18 ]);
- var point, pointStream = {
- point: function(x, y) {
- point = [ x, y ];
- }
- }, lower48Point, alaskaPoint, hawaiiPoint;
- function albersUsa(coordinates) {
- var x = coordinates[0], y = coordinates[1];
- point = null;
- (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y);
- return point;
- }
- albersUsa.invert = function(coordinates) {
- var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k,
y = (coordinates[1] - t[1]) / k;
- return (y >= .12 && y < .234 && x >= -.425 && x
< -.214 ? alaska : y >= .166 && y < .234 && x >= -.214
&& x < -.115 ? hawaii : lower48).invert(coordinates);
- };
- albersUsa.stream = function(stream) {
- var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream),
hawaiiStream = hawaii.stream(stream);
- return {
- point: function(x, y) {
- lower48Stream.point(x, y);
- alaskaStream.point(x, y);
- hawaiiStream.point(x, y);
- },
- sphere: function() {
- lower48Stream.sphere();
- alaskaStream.sphere();
- hawaiiStream.sphere();
- },
- lineStart: function() {
- lower48Stream.lineStart();
- alaskaStream.lineStart();
- hawaiiStream.lineStart();
- },
- lineEnd: function() {
- lower48Stream.lineEnd();
- alaskaStream.lineEnd();
- hawaiiStream.lineEnd();
- },
- polygonStart: function() {
- lower48Stream.polygonStart();
- alaskaStream.polygonStart();
- hawaiiStream.polygonStart();
- },
- polygonEnd: function() {
- lower48Stream.polygonEnd();
- alaskaStream.polygonEnd();
- hawaiiStream.polygonEnd();
- }
- };
- };
- albersUsa.precision = function(_) {
- if (!arguments.length) return lower48.precision();
- lower48.precision(_);
- alaska.precision(_);
- hawaii.precision(_);
- return albersUsa;
- };
- albersUsa.scale = function(_) {
- if (!arguments.length) return lower48.scale();
- lower48.scale(_);
- alaska.scale(_ * .35);
- hawaii.scale(_);
- return albersUsa.translate(lower48.translate());
- };
- albersUsa.translate = function(_) {
- if (!arguments.length) return lower48.translate();
- var k = lower48.scale(), x = +_[0], y = +_[1];
- lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [
x + .455 * k, y + .238 * k ] ]).stream(pointStream).point;
- alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x -
.425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ]
]).stream(pointStream).point;
- hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x -
.214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ]
]).stream(pointStream).point;
- return albersUsa;
- };
- return albersUsa.scale(1070);
- };
- var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
- point: d3_noop,
- lineStart: d3_noop,
- lineEnd: d3_noop,
- polygonStart: function() {
- d3_geo_pathAreaPolygon = 0;
- d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
- },
- polygonEnd: function() {
- d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point =
d3_noop;
- d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2);
- }
- };
- function d3_geo_pathAreaRingStart() {
- var x00, y00, x0, y0;
- d3_geo_pathArea.point = function(x, y) {
- d3_geo_pathArea.point = nextPoint;
- x00 = x0 = x, y00 = y0 = y;
- };
- function nextPoint(x, y) {
- d3_geo_pathAreaPolygon += y0 * x - x0 * y;
- x0 = x, y0 = y;
- }
- d3_geo_pathArea.lineEnd = function() {
- nextPoint(x00, y00);
- };
- }
- var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1,
d3_geo_pathBoundsY1;
- var d3_geo_pathBounds = {
- point: d3_geo_pathBoundsPoint,
- lineStart: d3_noop,
- lineEnd: d3_noop,
- polygonStart: d3_noop,
- polygonEnd: d3_noop
- };
- function d3_geo_pathBoundsPoint(x, y) {
- if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
- if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
- if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
- if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
- }
- function d3_geo_pathBuffer() {
- var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = [];
- var stream = {
- point: point,
- lineStart: function() {
- stream.point = pointLineStart;
- },
- lineEnd: lineEnd,
- polygonStart: function() {
- stream.lineEnd = lineEndPolygon;
- },
- polygonEnd: function() {
- stream.lineEnd = lineEnd;
- stream.point = point;
- },
- pointRadius: function(_) {
- pointCircle = d3_geo_pathBufferCircle(_);
- return stream;
- },
- result: function() {
- if (buffer.length) {
- var result = buffer.join("");
- buffer = [];
- return result;
- }
- }
- };
- function point(x, y) {
- buffer.push("M", x, ",", y, pointCircle);
- }
- function pointLineStart(x, y) {
- buffer.push("M", x, ",", y);
- stream.point = pointLine;
- }
- function pointLine(x, y) {
- buffer.push("L", x, ",", y);
- }
- function lineEnd() {
- stream.point = point;
- }
- function lineEndPolygon() {
- buffer.push("Z");
- }
- return stream;
- }
- function d3_geo_pathBufferCircle(radius) {
- return "m0," + radius + "a" + radius + "," + radius +
" 0 1,1 0," + -2 * radius + "a" + radius + "," + radius +
" 0 1,1 0," + 2 * radius + "z";
- }
- var d3_geo_pathCentroid = {
- point: d3_geo_pathCentroidPoint,
- lineStart: d3_geo_pathCentroidLineStart,
- lineEnd: d3_geo_pathCentroidLineEnd,
- polygonStart: function() {
- d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
- },
- polygonEnd: function() {
- d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
- d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
- d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
- }
- };
- function d3_geo_pathCentroidPoint(x, y) {
- d3_geo_centroidX0 += x;
- d3_geo_centroidY0 += y;
- ++d3_geo_centroidZ0;
- }
- function d3_geo_pathCentroidLineStart() {
- var x0, y0;
- d3_geo_pathCentroid.point = function(x, y) {
- d3_geo_pathCentroid.point = nextPoint;
- d3_geo_pathCentroidPoint(x0 = x, y0 = y);
- };
- function nextPoint(x, y) {
- var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
- d3_geo_centroidX1 += z * (x0 + x) / 2;
- d3_geo_centroidY1 += z * (y0 + y) / 2;
- d3_geo_centroidZ1 += z;
- d3_geo_pathCentroidPoint(x0 = x, y0 = y);
- }
- }
- function d3_geo_pathCentroidLineEnd() {
- d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
- }
- function d3_geo_pathCentroidRingStart() {
- var x00, y00, x0, y0;
- d3_geo_pathCentroid.point = function(x, y) {
- d3_geo_pathCentroid.point = nextPoint;
- d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
- };
- function nextPoint(x, y) {
- var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
- d3_geo_centroidX1 += z * (x0 + x) / 2;
- d3_geo_centroidY1 += z * (y0 + y) / 2;
- d3_geo_centroidZ1 += z;
- z = y0 * x - x0 * y;
- d3_geo_centroidX2 += z * (x0 + x);
- d3_geo_centroidY2 += z * (y0 + y);
- d3_geo_centroidZ2 += z * 3;
- d3_geo_pathCentroidPoint(x0 = x, y0 = y);
- }
- d3_geo_pathCentroid.lineEnd = function() {
- nextPoint(x00, y00);
- };
- }
- function d3_geo_pathContext(context) {
- var pointRadius = 4.5;
- var stream = {
- point: point,
- lineStart: function() {
- stream.point = pointLineStart;
- },
- lineEnd: lineEnd,
- polygonStart: function() {
- stream.lineEnd = lineEndPolygon;
- },
- polygonEnd: function() {
- stream.lineEnd = lineEnd;
- stream.point = point;
- },
- pointRadius: function(_) {
- pointRadius = _;
- return stream;
- },
- result: d3_noop
- };
- function point(x, y) {
- context.moveTo(x, y);
- context.arc(x, y, pointRadius, 0, 2 * Ï);
- }
- function pointLineStart(x, y) {
- context.moveTo(x, y);
- stream.point = pointLine;
- }
- function pointLine(x, y) {
- context.lineTo(x, y);
- }
- function lineEnd() {
- stream.point = point;
- }
- function lineEndPolygon() {
- context.closePath();
- }
- return stream;
- }
- function d3_geo_resample(project) {
- var ÎŽ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16;
- function resample(stream) {
- var λ00, Ï00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0;
- var resample = {
- point: point,
- lineStart: lineStart,
- lineEnd: lineEnd,
- polygonStart: function() {
- stream.polygonStart();
- resample.lineStart = ringStart;
- },
- polygonEnd: function() {
- stream.polygonEnd();
- resample.lineStart = lineStart;
- }
- };
- function point(x, y) {
- x = project(x, y);
- stream.point(x[0], x[1]);
- }
- function lineStart() {
- x0 = NaN;
- resample.point = linePoint;
- stream.lineStart();
- }
- function linePoint(λ, Ï) {
- var c = d3_geo_cartesian([ λ, Ï ]), p = project(λ, Ï);
- resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 =
c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
- stream.point(x0, y0);
- }
- function lineEnd() {
- resample.point = point;
- stream.lineEnd();
- }
- function ringStart() {
- lineStart();
- resample.point = ringPoint;
- resample.lineEnd = ringEnd;
- }
- function ringPoint(λ, Ï) {
- linePoint(λ00 = λ, Ï00 = Ï), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 =
c0;
- resample.point = linePoint;
- }
- function ringEnd() {
- resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth,
stream);
- resample.lineEnd = lineEnd;
- lineEnd();
- }
- return resample;
- }
- function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth,
stream) {
- var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
- if (d2 > 4 * ÎŽ2 && depth--) {
- var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c),
Ï2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 :
Math.atan2(b, a), p = project(λ2, Ï2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 -
y0, dz = dy * dx2 - dx * dy2;
- if (dz * dz / d2 > ÎŽ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 ||
a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
- resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth,
stream);
- stream.point(x2, y2);
- resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
- }
- }
- }
- resample.precision = function(_) {
- if (!arguments.length) return Math.sqrt(ÎŽ2);
- maxDepth = (ÎŽ2 = _ * _) > 0 && 16;
- return resample;
- };
- return resample;
- }
- d3.geo.path = function() {
- var pointRadius = 4.5, projection, context, projectStream, contextStream,
cacheStream;
- function path(object) {
- if (object) {
- if (typeof pointRadius === "function")
contextStream.pointRadius(+pointRadius.apply(this, arguments));
- if (!cacheStream || !cacheStream.valid) cacheStream =
projectStream(contextStream);
- d3.geo.stream(object, cacheStream);
- }
- return contextStream.result();
- }
- path.area = function(object) {
- d3_geo_pathAreaSum = 0;
- d3.geo.stream(object, projectStream(d3_geo_pathArea));
- return d3_geo_pathAreaSum;
- };
- path.centroid = function(object) {
- d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 =
d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 =
d3_geo_centroidZ2 = 0;
- d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
- return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2,
d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 /
d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [
d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN,
NaN ];
- };
- path.bounds = function(object) {
- d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 =
d3_geo_pathBoundsY0 = Infinity);
- d3.geo.stream(object, projectStream(d3_geo_pathBounds));
- return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1,
d3_geo_pathBoundsY1 ] ];
- };
- path.projection = function(_) {
- if (!arguments.length) return projection;
- projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) :
d3_identity;
- return reset();
- };
- path.context = function(_) {
- if (!arguments.length) return context;
- contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new
d3_geo_pathContext(_);
- if (typeof pointRadius !== "function")
contextStream.pointRadius(pointRadius);
- return reset();
- };
- path.pointRadius = function(_) {
- if (!arguments.length) return pointRadius;
- pointRadius = typeof _ === "function" ? _ :
(contextStream.pointRadius(+_), +_);
- return path;
- };
- function reset() {
- cacheStream = null;
- return path;
- }
- return path.projection(d3.geo.albersUsa()).context(null);
- };
- function d3_geo_pathProjectStream(project) {
- var resample = d3_geo_resample(function(λ, Ï) {
- return project([ λ * d3_degrees, Ï * d3_degrees ]);
- });
- return function(stream) {
- stream = resample(stream);
- return {
- point: function(λ, Ï) {
- stream.point(λ * d3_radians, Ï * d3_radians);
- },
- sphere: function() {
- stream.sphere();
- },
- lineStart: function() {
- stream.lineStart();
- },
- lineEnd: function() {
- stream.lineEnd();
- },
- polygonStart: function() {
- stream.polygonStart();
- },
- polygonEnd: function() {
- stream.polygonEnd();
- }
- };
- };
- }
- d3.geo.projection = d3_geo_projection;
- d3.geo.projectionMutator = d3_geo_projectionMutator;
- function d3_geo_projection(project) {
- return d3_geo_projectionMutator(function() {
- return project;
- })();
- }
- function d3_geo_projectionMutator(projectAt) {
- var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y)
{
- x = project(x, y);
- return [ x[0] * k + ÎŽx, ÎŽy - x[1] * k ];
- }), k = 150, x = 480, y = 250, λ = 0, Ï = 0, Ύλ = 0, ÎŽÏ = 0, Ύγ = 0, ÎŽx,
ÎŽy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null,
clipExtent = null, stream;
- function projection(point) {
- point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
- return [ point[0] * k + ÎŽx, ÎŽy - point[1] * k ];
- }
- function invert(point) {
- point = projectRotate.invert((point[0] - ÎŽx) / k, (ÎŽy - point[1]) / k);
- return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];
- }
- projection.stream = function(output) {
- if (stream) stream.valid = false;
- stream = d3_geo_projectionRadiansRotate(rotate,
preclip(projectResample(postclip(output))));
- stream.valid = true;
- return stream;
- };
- projection.clipAngle = function(_) {
- if (!arguments.length) return clipAngle;
- preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) :
d3_geo_clipCircle((clipAngle = +_) * d3_radians);
- return invalidate();
- };
- projection.clipExtent = function(_) {
- if (!arguments.length) return clipExtent;
- clipExtent = _;
- postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0],
_[1][1]);
- return invalidate();
- };
- projection.scale = function(_) {
- if (!arguments.length) return k;
- k = +_;
- return reset();
- };
- projection.translate = function(_) {
- if (!arguments.length) return [ x, y ];
- x = +_[0];
- y = +_[1];
- return reset();
- };
- projection.center = function(_) {
- if (!arguments.length) return [ λ * d3_degrees, Ï * d3_degrees ];
- λ = _[0] % 360 * d3_radians;
- Ï = _[1] % 360 * d3_radians;
- return reset();
- };
- projection.rotate = function(_) {
- if (!arguments.length) return [ Ύλ * d3_degrees, ÎŽÏ * d3_degrees, Ύγ *
d3_degrees ];
- Ύλ = _[0] % 360 * d3_radians;
- ÎŽÏ = _[1] % 360 * d3_radians;
- Ύγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
- return reset();
- };
- d3.rebind(projection, projectResample, "precision");
- function reset() {
- projectRotate = d3_geo_compose(rotate = d3_geo_rotation(Ύλ, ÎŽÏ, Ύγ),
project);
- var center = project(λ, Ï);
- ÎŽx = x - center[0] * k;
- ÎŽy = y + center[1] * k;
- return invalidate();
- }
- function invalidate() {
- if (stream) {
- stream.valid = false;
- stream = null;
- }
- return projection;
- }
- return function() {
- project = projectAt.apply(this, arguments);
- projection.invert = project.invert && invert;
- return reset();
- };
- }
- function d3_geo_projectionRadiansRotate(rotate, stream) {
- return {
- point: function(x, y) {
- y = rotate(x * d3_radians, y * d3_radians), x = y[0];
- stream.point(x > Ï ? x - 2 * Ï : x < -Ï ? x + 2 * Ï : x, y[1]);
- },
- sphere: function() {
- stream.sphere();
- },
- lineStart: function() {
- stream.lineStart();
- },
- lineEnd: function() {
- stream.lineEnd();
- },
- polygonStart: function() {
- stream.polygonStart();
- },
- polygonEnd: function() {
- stream.polygonEnd();
- }
- };
- }
- function d3_geo_equirectangular(λ, Ï) {
- return [ λ, Ï ];
- }
- (d3.geo.equirectangular = function() {
- return d3_geo_projection(d3_geo_equirectangular);
- }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
- d3.geo.rotation = function(rotate) {
- rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians,
rotate.length > 2 ? rotate[2] * d3_radians : 0);
- function forward(coordinates) {
- coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
- return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
- }
- forward.invert = function(coordinates) {
- coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] *
d3_radians);
- return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
- };
- return forward;
- };
- function d3_geo_rotation(Ύλ, ÎŽÏ, Ύγ) {
- return Ύλ ? ÎŽÏ || Ύγ ? d3_geo_compose(d3_geo_rotationλ(Ύλ),
d3_geo_rotationÏγ(ÎŽÏ, Ύγ)) : d3_geo_rotationλ(Ύλ) : ÎŽÏ || Ύγ ?
d3_geo_rotationÏγ(ÎŽÏ, Ύγ) : d3_geo_equirectangular;
- }
- function d3_geo_forwardRotationλ(Ύλ) {
- return function(λ, Ï) {
- return λ += Ύλ, [ λ > Ï ? λ - 2 * Ï : λ < -Ï ? λ + 2 * Ï : λ, Ï
];
- };
- }
- function d3_geo_rotationλ(Ύλ) {
- var rotation = d3_geo_forwardRotationλ(Ύλ);
- rotation.invert = d3_geo_forwardRotationλ(-Ύλ);
- return rotation;
- }
- function d3_geo_rotationÏγ(ÎŽÏ, Ύγ) {
- var cosÎŽÏ = Math.cos(ÎŽÏ), sinÎŽÏ = Math.sin(ÎŽÏ), cosΎγ = Math.cos(Ύγ),
sinΎγ = Math.sin(Ύγ);
- function rotation(λ, Ï) {
- var cosÏ = Math.cos(Ï), x = Math.cos(λ) * cosÏ, y = Math.sin(λ) * cosÏ, z =
Math.sin(Ï), k = z * cosÎŽÏ + x * sinÎŽÏ;
- return [ Math.atan2(y * cosΎγ - k * sinΎγ, x * cosÎŽÏ - z * sinÎŽÏ),
d3_asin(k * cosΎγ + y * sinΎγ) ];
- }
- rotation.invert = function(λ, Ï) {
- var cosÏ = Math.cos(Ï), x = Math.cos(λ) * cosÏ, y = Math.sin(λ) * cosÏ, z =
Math.sin(Ï), k = z * cosΎγ - y * sinΎγ;
- return [ Math.atan2(y * cosΎγ + z * sinΎγ, x * cosÎŽÏ + k * sinÎŽÏ),
d3_asin(k * cosÎŽÏ - x * sinÎŽÏ) ];
- };
- return rotation;
- }
- d3.geo.circle = function() {
- var origin = [ 0, 0 ], angle, precision = 6, interpolate;
- function circle() {
- var center = typeof origin === "function" ? origin.apply(this, arguments)
: origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians,
0).invert, ring = [];
- interpolate(null, null, 1, {
- point: function(x, y) {
- ring.push(x = rotate(x, y));
- x[0] *= d3_degrees, x[1] *= d3_degrees;
- }
- });
- return {
- type: "Polygon",
- coordinates: [ ring ]
- };
- }
- circle.origin = function(x) {
- if (!arguments.length) return origin;
- origin = x;
- return circle;
- };
- circle.angle = function(x) {
- if (!arguments.length) return angle;
- interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision *
d3_radians);
- return circle;
- };
- circle.precision = function(_) {
- if (!arguments.length) return precision;
- interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) *
d3_radians);
- return circle;
- };
- return circle.angle(90);
- };
- function d3_geo_circleInterpolate(radius, precision) {
- var cr = Math.cos(radius), sr = Math.sin(radius);
- return function(from, to, direction, listener) {
- if (from != null) {
- from = d3_geo_circleAngle(cr, from);
- to = d3_geo_circleAngle(cr, to);
- if (direction > 0 ? from < to : from > to) from += direction * 2 * Ï;
- } else {
- from = radius + direction * 2 * Ï;
- to = radius;
- }
- var point;
- for (var step = direction * precision, t = from; direction > 0 ? t > to : t
< to; t -= step) {
- listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr *
Math.sin(t) ]))[0], point[1]);
- }
- };
- }
- function d3_geo_circleAngle(cr, point) {
- var a = d3_geo_cartesian(point);
- a[0] -= cr;
- d3_geo_cartesianNormalize(a);
- var angle = d3_acos(-a[1]);
- return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
- }
- d3.geo.distance = function(a, b) {
- var Îλ = (b[0] - a[0]) * d3_radians, Ï0 = a[1] * d3_radians, Ï1 = b[1] *
d3_radians, sinÎλ = Math.sin(Îλ), cosÎλ = Math.cos(Îλ), sinÏ0 = Math.sin(Ï0),
cosÏ0 = Math.cos(Ï0), sinÏ1 = Math.sin(Ï1), cosÏ1 = Math.cos(Ï1), t;
- return Math.atan2(Math.sqrt((t = cosÏ1 * sinÎλ) * t + (t = cosÏ0 * sinÏ1 -
sinÏ0 * cosÏ1 * cosÎλ) * t), sinÏ0 * sinÏ1 + cosÏ0 * cosÏ1 * cosÎλ);
- };
- d3.geo.graticule = function() {
- var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y,
precision = 2.5;
- function graticule() {
- return {
- type: "MultiLineString",
- coordinates: lines()
- };
- }
- function lines() {
- return d3.range(Math.ceil(X0 / DX) * DX, X1,
DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1,
DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) {
- return Math.abs(x % DX) > ε;
- }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) {
- return Math.abs(y % DY) > ε;
- }).map(y));
- }
- graticule.lines = function() {
- return lines().map(function(coordinates) {
- return {
- type: "LineString",
- coordinates: coordinates
- };
- });
- };
- graticule.outline = function() {
- return {
- type: "Polygon",
- coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1),
Y(Y0).reverse().slice(1)) ]
- };
- };
- graticule.extent = function(_) {
- if (!arguments.length) return graticule.minorExtent();
- return graticule.majorExtent(_).minorExtent(_);
- };
- graticule.majorExtent = function(_) {
- if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ];
- X0 = +_[0][0], X1 = +_[1][0];
- Y0 = +_[0][1], Y1 = +_[1][1];
- if (X0 > X1) _ = X0, X0 = X1, X1 = _;
- if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
- return graticule.precision(precision);
- };
- graticule.minorExtent = function(_) {
- if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
- x0 = +_[0][0], x1 = +_[1][0];
- y0 = +_[0][1], y1 = +_[1][1];
- if (x0 > x1) _ = x0, x0 = x1, x1 = _;
- if (y0 > y1) _ = y0, y0 = y1, y1 = _;
- return graticule.precision(precision);
- };
- graticule.step = function(_) {
- if (!arguments.length) return graticule.minorStep();
- return graticule.majorStep(_).minorStep(_);
- };
- graticule.majorStep = function(_) {
- if (!arguments.length) return [ DX, DY ];
- DX = +_[0], DY = +_[1];
- return graticule;
- };
- graticule.minorStep = function(_) {
- if (!arguments.length) return [ dx, dy ];
- dx = +_[0], dy = +_[1];
- return graticule;
- };
- graticule.precision = function(_) {
- if (!arguments.length) return precision;
- precision = +_;
- x = d3_geo_graticuleX(y0, y1, 90);
- y = d3_geo_graticuleY(x0, x1, precision);
- X = d3_geo_graticuleX(Y0, Y1, 90);
- Y = d3_geo_graticuleY(X0, X1, precision);
- return graticule;
- };
- return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([
[ -180, -80 - ε ], [ 180, 80 + ε ] ]);
- };
- function d3_geo_graticuleX(y0, y1, dy) {
- var y = d3.range(y0, y1 - ε, dy).concat(y1);
- return function(x) {
- return y.map(function(y) {
- return [ x, y ];
- });
- };
- }
- function d3_geo_graticuleY(x0, x1, dx) {
- var x = d3.range(x0, x1 - ε, dx).concat(x1);
- return function(y) {
- return x.map(function(x) {
- return [ x, y ];
- });
- };
- }
- function d3_source(d) {
- return d.source;
- }
- function d3_target(d) {
- return d.target;
- }
- d3.geo.greatArc = function() {
- var source = d3_source, source_, target = d3_target, target_;
- function greatArc() {
- return {
- type: "LineString",
- coordinates: [ source_ || source.apply(this, arguments), target_ ||
target.apply(this, arguments) ]
- };
- }
- greatArc.distance = function() {
- return d3.geo.distance(source_ || source.apply(this, arguments), target_ ||
target.apply(this, arguments));
- };
- greatArc.source = function(_) {
- if (!arguments.length) return source;
- source = _, source_ = typeof _ === "function" ? null : _;
- return greatArc;
- };
- greatArc.target = function(_) {
- if (!arguments.length) return target;
- target = _, target_ = typeof _ === "function" ? null : _;
- return greatArc;
- };
- greatArc.precision = function() {
- return arguments.length ? greatArc : 0;
- };
- return greatArc;
- };
- d3.geo.interpolate = function(source, target) {
- return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] *
d3_radians, target[1] * d3_radians);
- };
- function d3_geo_interpolate(x0, y0, x1, y1) {
- var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1),
kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 *
Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 *
d3_haversin(x1 - x0))), k = 1 / Math.sin(d);
- var interpolate = d ? function(t) {
- var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A
* ky0 + B * ky1, z = A * sy0 + B * sy1;
- return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) *
d3_degrees ];
- } : function() {
- return [ x0 * d3_degrees, y0 * d3_degrees ];
- };
- interpolate.distance = d;
- return interpolate;
- }
- d3.geo.length = function(object) {
- d3_geo_lengthSum = 0;
- d3.geo.stream(object, d3_geo_length);
- return d3_geo_lengthSum;
- };
- var d3_geo_lengthSum;
- var d3_geo_length = {
- sphere: d3_noop,
- point: d3_noop,
- lineStart: d3_geo_lengthLineStart,
- lineEnd: d3_noop,
- polygonStart: d3_noop,
- polygonEnd: d3_noop
- };
- function d3_geo_lengthLineStart() {
- var λ0, sinÏ0, cosÏ0;
- d3_geo_length.point = function(λ, Ï) {
- λ0 = λ * d3_radians, sinÏ0 = Math.sin(Ï *= d3_radians), cosÏ0 = Math.cos(Ï);
- d3_geo_length.point = nextPoint;
- };
- d3_geo_length.lineEnd = function() {
- d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
- };
- function nextPoint(λ, Ï) {
- var sinÏ = Math.sin(Ï *= d3_radians), cosÏ = Math.cos(Ï), t = Math.abs((λ *=
d3_radians) - λ0), cosÎλ = Math.cos(t);
- d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosÏ * Math.sin(t)) * t + (t =
cosÏ0 * sinÏ - sinÏ0 * cosÏ * cosÎλ) * t), sinÏ0 * sinÏ + cosÏ0 * cosÏ *
cosÎλ);
- λ0 = λ, sinÏ0 = sinÏ, cosÏ0 = cosÏ;
- }
- }
- function d3_geo_azimuthal(scale, angle) {
- function azimuthal(λ, Ï) {
- var cosλ = Math.cos(λ), cosÏ = Math.cos(Ï), k = scale(cosλ * cosÏ);
- return [ k * cosÏ * Math.sin(λ), k * Math.sin(Ï) ];
- }
- azimuthal.invert = function(x, y) {
- var Ï = Math.sqrt(x * x + y * y), c = angle(Ï), sinc = Math.sin(c), cosc =
Math.cos(c);
- return [ Math.atan2(x * sinc, Ï * cosc), Math.asin(Ï && y * sinc / Ï)
];
- };
- return azimuthal;
- }
- var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosÏ) {
- return Math.sqrt(2 / (1 + cosλcosÏ));
- }, function(Ï) {
- return 2 * Math.asin(Ï / 2);
- });
- (d3.geo.azimuthalEqualArea = function() {
- return d3_geo_projection(d3_geo_azimuthalEqualArea);
- }).raw = d3_geo_azimuthalEqualArea;
- var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosÏ) {
- var c = Math.acos(cosλcosÏ);
- return c && c / Math.sin(c);
- }, d3_identity);
- (d3.geo.azimuthalEquidistant = function() {
- return d3_geo_projection(d3_geo_azimuthalEquidistant);
- }).raw = d3_geo_azimuthalEquidistant;
- function d3_geo_conicConformal(Ï0, Ï1) {
- var cosÏ0 = Math.cos(Ï0), t = function(Ï) {
- return Math.tan(Ï / 4 + Ï / 2);
- }, n = Ï0 === Ï1 ? Math.sin(Ï0) : Math.log(cosÏ0 / Math.cos(Ï1)) /
Math.log(t(Ï1) / t(Ï0)), F = cosÏ0 * Math.pow(t(Ï0), n) / n;
- if (!n) return d3_geo_mercator;
- function forward(λ, Ï) {
- var Ï = Math.abs(Math.abs(Ï) - Ï / 2) < ε ? 0 : F / Math.pow(t(Ï), n);
- return [ Ï * Math.sin(n * λ), F - Ï * Math.cos(n * λ) ];
- }
- forward.invert = function(x, y) {
- var Ï0_y = F - y, Ï = d3_sgn(n) * Math.sqrt(x * x + Ï0_y * Ï0_y);
- return [ Math.atan2(x, Ï0_y) / n, 2 * Math.atan(Math.pow(F / Ï, 1 / n)) - Ï / 2
];
- };
- return forward;
- }
- (d3.geo.conicConformal = function() {
- return d3_geo_conic(d3_geo_conicConformal);
- }).raw = d3_geo_conicConformal;
- function d3_geo_conicEquidistant(Ï0, Ï1) {
- var cosÏ0 = Math.cos(Ï0), n = Ï0 === Ï1 ? Math.sin(Ï0) : (cosÏ0 -
Math.cos(Ï1)) / (Ï1 - Ï0), G = cosÏ0 / n + Ï0;
- if (Math.abs(n) < ε) return d3_geo_equirectangular;
- function forward(λ, Ï) {
- var Ï = G - Ï;
- return [ Ï * Math.sin(n * λ), G - Ï * Math.cos(n * λ) ];
- }
- forward.invert = function(x, y) {
- var Ï0_y = G - y;
- return [ Math.atan2(x, Ï0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + Ï0_y * Ï0_y)
];
- };
- return forward;
- }
- (d3.geo.conicEquidistant = function() {
- return d3_geo_conic(d3_geo_conicEquidistant);
- }).raw = d3_geo_conicEquidistant;
- var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosÏ) {
- return 1 / cosλcosÏ;
- }, Math.atan);
- (d3.geo.gnomonic = function() {
- return d3_geo_projection(d3_geo_gnomonic);
- }).raw = d3_geo_gnomonic;
- function d3_geo_mercator(λ, Ï) {
- return [ λ, Math.log(Math.tan(Ï / 4 + Ï / 2)) ];
- }
- d3_geo_mercator.invert = function(x, y) {
- return [ x, 2 * Math.atan(Math.exp(y)) - Ï / 2 ];
- };
- function d3_geo_mercatorProjection(project) {
- var m = d3_geo_projection(project), scale = m.scale, translate = m.translate,
clipExtent = m.clipExtent, clipAuto;
- m.scale = function() {
- var v = scale.apply(m, arguments);
- return v === m ? clipAuto ? m.clipExtent(null) : m : v;
- };
- m.translate = function() {
- var v = translate.apply(m, arguments);
- return v === m ? clipAuto ? m.clipExtent(null) : m : v;
- };
- m.clipExtent = function(_) {
- var v = clipExtent.apply(m, arguments);
- if (v === m) {
- if (clipAuto = _ == null) {
- var k = Ï * scale(), t = translate();
- clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]);
- }
- } else if (clipAuto) {
- v = null;
- }
- return v;
- };
- return m.clipExtent(null);
- }
- (d3.geo.mercator = function() {
- return d3_geo_mercatorProjection(d3_geo_mercator);
- }).raw = d3_geo_mercator;
- var d3_geo_orthographic = d3_geo_azimuthal(function() {
- return 1;
- }, Math.asin);
- (d3.geo.orthographic = function() {
- return d3_geo_projection(d3_geo_orthographic);
- }).raw = d3_geo_orthographic;
- var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosÏ) {
- return 1 / (1 + cosλcosÏ);
- }, function(Ï) {
- return 2 * Math.atan(Ï);
- });
- (d3.geo.stereographic = function() {
- return d3_geo_projection(d3_geo_stereographic);
- }).raw = d3_geo_stereographic;
- function d3_geo_transverseMercator(λ, Ï) {
- var B = Math.cos(Ï) * Math.sin(λ);
- return [ Math.log((1 + B) / (1 - B)) / 2, Math.atan2(Math.tan(Ï), Math.cos(λ)) ];
- }
- d3_geo_transverseMercator.invert = function(x, y) {
- return [ Math.atan2(d3_sinh(x), Math.cos(y)), d3_asin(Math.sin(y) / d3_cosh(x)) ];
- };
- (d3.geo.transverseMercator = function() {
- return d3_geo_mercatorProjection(d3_geo_transverseMercator);
- }).raw = d3_geo_transverseMercator;
- d3.geom = {};
- d3.svg = {};
- function d3_svg_line(projection) {
- var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate =
d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
- function line(data) {
- var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy
= d3_functor(y);
- function segment() {
- segments.push("M", interpolate(projection(points), tension));
- }
- while (++i < n) {
- if (defined.call(this, d = data[i], i)) {
- points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
- } else if (points.length) {
- segment();
- points = [];
- }
- }
- if (points.length) segment();
- return segments.length ? segments.join("") : null;
- }
- line.x = function(_) {
- if (!arguments.length) return x;
- x = _;
- return line;
- };
- line.y = function(_) {
- if (!arguments.length) return y;
- y = _;
- return line;
- };
- line.defined = function(_) {
- if (!arguments.length) return defined;
- defined = _;
- return line;
- };
- line.interpolate = function(_) {
- if (!arguments.length) return interpolateKey;
- if (typeof _ === "function") interpolateKey = interpolate = _; else
interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) ||
d3_svg_lineLinear).key;
- return line;
- };
- line.tension = function(_) {
- if (!arguments.length) return tension;
- tension = _;
- return line;
- };
- return line;
- }
- d3.svg.line = function() {
- return d3_svg_line(d3_identity);
- };
- function d3_svg_lineX(d) {
- return d[0];
- }
- function d3_svg_lineY(d) {
- return d[1];
- }
- var d3_svg_lineInterpolators = d3.map({
- linear: d3_svg_lineLinear,
- "linear-closed": d3_svg_lineLinearClosed,
- step: d3_svg_lineStep,
- "step-before": d3_svg_lineStepBefore,
- "step-after": d3_svg_lineStepAfter,
- basis: d3_svg_lineBasis,
- "basis-open": d3_svg_lineBasisOpen,
- "basis-closed": d3_svg_lineBasisClosed,
- bundle: d3_svg_lineBundle,
- cardinal: d3_svg_lineCardinal,
- "cardinal-open": d3_svg_lineCardinalOpen,
- "cardinal-closed": d3_svg_lineCardinalClosed,
- monotone: d3_svg_lineMonotone
- });
- d3_svg_lineInterpolators.forEach(function(key, value) {
- value.key = key;
- value.closed = /-closed$/.test(key);
- });
- function d3_svg_lineLinear(points) {
- return points.join("L");
- }
- function d3_svg_lineLinearClosed(points) {
- return d3_svg_lineLinear(points) + "Z";
- }
- function d3_svg_lineStep(points) {
- var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
- while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2,
"V", p[1]);
- if (n > 1) path.push("H", p[0]);
- return path.join("");
- }
- function d3_svg_lineStepBefore(points) {
- var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
- while (++i < n) path.push("V", (p = points[i])[1], "H",
p[0]);
- return path.join("");
- }
- function d3_svg_lineStepAfter(points) {
- var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
- while (++i < n) path.push("H", (p = points[i])[0], "V",
p[1]);
- return path.join("");
- }
- function d3_svg_lineCardinalOpen(points, tension) {
- return points.length < 4 ? d3_svg_lineLinear(points) : points[1] +
d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points,
tension));
- }
- function d3_svg_lineCardinalClosed(points, tension) {
- return points.length < 3 ? d3_svg_lineLinear(points) : points[0] +
d3_svg_lineHermite((points.push(points[0]),
- points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [
points[1] ]), tension));
- }
- function d3_svg_lineCardinal(points, tension) {
- return points.length < 3 ? d3_svg_lineLinear(points) : points[0] +
d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
- }
- function d3_svg_lineHermite(points, tangents) {
- if (tangents.length < 1 || points.length != tangents.length &&
points.length != tangents.length + 2) {
- return d3_svg_lineLinear(points);
- }
- var quad = points.length != tangents.length, path = "", p0 = points[0], p =
points[1], t0 = tangents[0], t = t0, pi = 1;
- if (quad) {
- path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2
/ 3) + "," + p[0] + "," + p[1];
- p0 = points[1];
- pi = 2;
- }
- if (tangents.length > 1) {
- t = tangents[1];
- p = points[pi];
- pi++;
- path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) +
"," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] +
"," + p[1];
- for (var i = 2; i < tangents.length; i++, pi++) {
- p = points[pi];
- t = tangents[i];
- path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) +
"," + p[0] + "," + p[1];
- }
- }
- if (quad) {
- var lp = points[pi];
- path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 /
3) + "," + lp[0] + "," + lp[1];
- }
- return path;
- }
- function d3_svg_lineCardinalTangents(points, tension) {
- var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1,
n = points.length;
- while (++i < n) {
- p0 = p1;
- p1 = p2;
- p2 = points[i];
- tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
- }
- return tangents;
- }
- function d3_svg_lineBasis(points) {
- if (points.length < 3) return d3_svg_lineLinear(points);
- var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0,
x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0 ];
- d3_svg_lineBasisBezier(path, px, py);
- while (++i < n) {
- pi = points[i];
- px.shift();
- px.push(pi[0]);
- py.shift();
- py.push(pi[1]);
- d3_svg_lineBasisBezier(path, px, py);
- }
- i = -1;
- while (++i < 2) {
- px.shift();
- px.push(pi[0]);
- py.shift();
- py.push(pi[1]);
- d3_svg_lineBasisBezier(path, px, py);
- }
- return path.join("");
- }
- function d3_svg_lineBasisOpen(points) {
- if (points.length < 4) return d3_svg_lineLinear(points);
- var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
- while (++i < 3) {
- pi = points[i];
- px.push(pi[0]);
- py.push(pi[1]);
- }
- path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," +
d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
- --i;
- while (++i < n) {
- pi = points[i];
- px.shift();
- px.push(pi[0]);
- py.shift();
- py.push(pi[1]);
- d3_svg_lineBasisBezier(path, px, py);
- }
- return path.join("");
- }
- function d3_svg_lineBasisClosed(points) {
- var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
- while (++i < 4) {
- pi = points[i % n];
- px.push(pi[0]);
- py.push(pi[1]);
- }
- path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
- --i;
- while (++i < m) {
- pi = points[i % n];
- px.shift();
- px.push(pi[0]);
- py.shift();
- py.push(pi[1]);
- d3_svg_lineBasisBezier(path, px, py);
- }
- return path.join("");
- }
- function d3_svg_lineBundle(points, tension) {
- var n = points.length - 1;
- if (n) {
- var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1]
- y0, i = -1, p, t;
- while (++i <= n) {
- p = points[i];
- t = i / n;
- p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
- p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
- }
- }
- return d3_svg_lineBasis(points);
- }
- function d3_svg_lineDot4(a, b) {
- return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
- }
- var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1
/ 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];
- function d3_svg_lineBasisBezier(path, x, y) {
- path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",",
d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
- }
- function d3_svg_lineSlope(p0, p1) {
- return (p1[1] - p0[1]) / (p1[0] - p0[0]);
- }
- function d3_svg_lineFiniteDifferences(points) {
- var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] =
d3_svg_lineSlope(p0, p1);
- while (++i < j) {
- m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
- }
- m[i] = d;
- return m;
- }
- function d3_svg_lineMonotoneTangents(points) {
- var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j =
points.length - 1;
- while (++i < j) {
- d = d3_svg_lineSlope(points[i], points[i + 1]);
- if (Math.abs(d) < 1e-6) {
- m[i] = m[i + 1] = 0;
- } else {
- a = m[i] / d;
- b = m[i + 1] / d;
- s = a * a + b * b;
- if (s > 9) {
- s = d * 3 / Math.sqrt(s);
- m[i] = s * a;
- m[i + 1] = s * b;
- }
- }
- }
- i = -1;
- while (++i <= j) {
- s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 +
m[i] * m[i]));
- tangents.push([ s || 0, m[i] * s || 0 ]);
- }
- return tangents;
- }
- function d3_svg_lineMonotone(points) {
- return points.length < 3 ? d3_svg_lineLinear(points) : points[0] +
d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
- }
- d3.geom.hull = function(vertices) {
- var x = d3_svg_lineX, y = d3_svg_lineY;
- if (arguments.length) return hull(vertices);
- function hull(data) {
- if (data.length < 3) return [];
- var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n -
1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;
- if (fx === d3_svg_lineX && y === d3_svg_lineY) vertices = data; else for (i
= 0,
- vertices = []; i < n; ++i) {
- vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]);
- }
- for (i = 1; i < n; ++i) {
- if (vertices[i][1] < vertices[h][1] || vertices[i][1] == vertices[h][1]
&& vertices[i][0] < vertices[h][0]) h = i;
- }
- for (i = 0; i < n; ++i) {
- if (i === h) continue;
- y1 = vertices[i][1] - vertices[h][1];
- x1 = vertices[i][0] - vertices[h][0];
- points.push({
- angle: Math.atan2(y1, x1),
- index: i
- });
- }
- points.sort(function(a, b) {
- return a.angle - b.angle;
- });
- a = points[0].angle;
- v = points[0].index;
- u = 0;
- for (i = 1; i < plen; ++i) {
- j = points[i].index;
- if (a == points[i].angle) {
- x1 = vertices[v][0] - vertices[h][0];
- y1 = vertices[v][1] - vertices[h][1];
- x2 = vertices[j][0] - vertices[h][0];
- y2 = vertices[j][1] - vertices[h][1];
- if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) {
- points[i].index = -1;
- continue;
- } else {
- points[u].index = -1;
- }
- }
- a = points[i].angle;
- u = i;
- v = j;
- }
- stack.push(h);
- for (i = 0, j = 0; i < 2; ++j) {
- if (points[j].index > -1) {
- stack.push(points[j].index);
- i++;
- }
- }
- sp = stack.length;
- for (;j < plen; ++j) {
- if (points[j].index < 0) continue;
- while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices))
{
- --sp;
- }
- stack[sp++] = points[j].index;
- }
- var poly = [];
- for (i = sp - 1; i >= 0; --i) poly.push(data[stack[i]]);
- return poly;
- }
- hull.x = function(_) {
- return arguments.length ? (x = _, hull) : x;
- };
- hull.y = function(_) {
- return arguments.length ? (y = _, hull) : y;
- };
- return hull;
- };
- function d3_geom_hullCCW(i1, i2, i3, v) {
- var t, a, b, c, d, e, f;
- t = v[i1];
- a = t[0];
- b = t[1];
- t = v[i2];
- c = t[0];
- d = t[1];
- t = v[i3];
- e = t[0];
- f = t[1];
- return (f - b) * (c - a) - (d - b) * (e - a) > 0;
- }
- d3.geom.polygon = function(coordinates) {
- coordinates.area = function() {
- var i = 0, n = coordinates.length, area = coordinates[n - 1][1] * coordinates[0][0]
- coordinates[n - 1][0] * coordinates[0][1];
- while (++i < n) {
- area += coordinates[i - 1][1] * coordinates[i][0] - coordinates[i - 1][0] *
coordinates[i][1];
- }
- return area * .5;
- };
- coordinates.centroid = function(k) {
- var i = -1, n = coordinates.length, x = 0, y = 0, a, b = coordinates[n - 1], c;
- if (!arguments.length) k = -1 / (6 * coordinates.area());
- while (++i < n) {
- a = b;
- b = coordinates[i];
- c = a[0] * b[1] - b[0] * a[1];
- x += (a[0] + b[0]) * c;
- y += (a[1] + b[1]) * c;
- }
- return [ x * k, y * k ];
- };
- coordinates.clip = function(subject) {
- var input, i = -1, n = coordinates.length, j, m, a = coordinates[n - 1], b, c, d;
- while (++i < n) {
- input = subject.slice();
- subject.length = 0;
- b = coordinates[i];
- c = input[(m = input.length) - 1];
- j = -1;
- while (++j < m) {
- d = input[j];
- if (d3_geom_polygonInside(d, a, b)) {
- if (!d3_geom_polygonInside(c, a, b)) {
- subject.push(d3_geom_polygonIntersect(c, d, a, b));
- }
- subject.push(d);
- } else if (d3_geom_polygonInside(c, a, b)) {
- subject.push(d3_geom_polygonIntersect(c, d, a, b));
- }
- c = d;
- }
- a = b;
- }
- return subject;
- };
- return coordinates;
- };
- function d3_geom_polygonInside(p, a, b) {
- return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
- }
- function d3_geom_polygonIntersect(c, d, a, b) {
- var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21
= d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43
* y21);
- return [ x1 + ua * x21, y1 + ua * y21 ];
- }
- d3.geom.delaunay = function(vertices) {
- var edges = vertices.map(function() {
- return [];
- }), triangles = [];
- d3_geom_voronoiTessellate(vertices, function(e) {
- edges[e.region.l.index].push(vertices[e.region.r.index]);
- });
- edges.forEach(function(edge, i) {
- var v = vertices[i], cx = v[0], cy = v[1];
- edge.forEach(function(v) {
- v.angle = Math.atan2(v[0] - cx, v[1] - cy);
- });
- edge.sort(function(a, b) {
- return a.angle - b.angle;
- });
- for (var j = 0, m = edge.length - 1; j < m; j++) {
- triangles.push([ v, edge[j], edge[j + 1] ]);
- }
- });
- return triangles;
- };
- d3.geom.voronoi = function(points) {
- var x = d3_svg_lineX, y = d3_svg_lineY, clipPolygon = null;
- if (arguments.length) return voronoi(points);
- function voronoi(data) {
- var points, polygons = data.map(function() {
- return [];
- }), fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length, Z = 1e6;
- if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for
(points = new Array(n),
- i = 0; i < n; ++i) {
- points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ];
- }
- d3_geom_voronoiTessellate(points, function(e) {
- var s1, s2, x1, x2, y1, y2;
- if (e.a === 1 && e.b >= 0) {
- s1 = e.ep.r;
- s2 = e.ep.l;
- } else {
- s1 = e.ep.l;
- s2 = e.ep.r;
- }
- if (e.a === 1) {
- y1 = s1 ? s1.y : -Z;
- x1 = e.c - e.b * y1;
- y2 = s2 ? s2.y : Z;
- x2 = e.c - e.b * y2;
- } else {
- x1 = s1 ? s1.x : -Z;
- y1 = e.c - e.a * x1;
- x2 = s2 ? s2.x : Z;
- y2 = e.c - e.a * x2;
- }
- var v1 = [ x1, y1 ], v2 = [ x2, y2 ];
- polygons[e.region.l.index].push(v1, v2);
- polygons[e.region.r.index].push(v1, v2);
- });
- polygons = polygons.map(function(polygon, i) {
- var cx = points[i][0], cy = points[i][1], angle = polygon.map(function(v) {
- return Math.atan2(v[0] - cx, v[1] - cy);
- }), order = d3.range(polygon.length).sort(function(a, b) {
- return angle[a] - angle[b];
- });
- return order.filter(function(d, i) {
- return !i || angle[d] - angle[order[i - 1]] > ε;
- }).map(function(d) {
- return polygon[d];
- });
- });
- polygons.forEach(function(polygon, i) {
- var n = polygon.length;
- if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]);
- if (n > 2) return;
- var p0 = points[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1
= p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1;
- if (Math.abs(dy) < ε) {
- var y = y0 < y1 ? -Z : Z;
- polygon.push([ -Z, y ], [ Z, y ]);
- } else if (dx < ε) {
- var x = x0 < x1 ? -Z : Z;
- polygon.push([ x, -Z ], [ x, Z ]);
- } else {
- var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z =
Math.abs(dy) - dx;
- if (Math.abs(z) < ε) {
- polygon.push([ dy < 0 ? y : -y, y ]);
- } else {
- if (z > 0) y *= -1;
- polygon.push([ -Z, y ], [ Z, y ]);
- }
- }
- });
- if (clipPolygon) for (i = 0; i < n; ++i) clipPolygon.clip(polygons[i]);
- for (i = 0; i < n; ++i) polygons[i].point = data[i];
- return polygons;
- }
- voronoi.x = function(_) {
- return arguments.length ? (x = _, voronoi) : x;
- };
- voronoi.y = function(_) {
- return arguments.length ? (y = _, voronoi) : y;
- };
- voronoi.clipExtent = function(_) {
- if (!arguments.length) return clipPolygon && [ clipPolygon[0],
clipPolygon[2] ];
- if (_ == null) clipPolygon = null; else {
- var x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1];
- clipPolygon = d3.geom.polygon([ [ x1, y1 ], [ x1, y2 ], [ x2, y2 ], [ x2, y1 ]
]);
- }
- return voronoi;
- };
- voronoi.size = function(_) {
- if (!arguments.length) return clipPolygon && clipPolygon[2];
- return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]);
- };
- voronoi.links = function(data) {
- var points, graph = data.map(function() {
- return [];
- }), links = [], fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length;
- if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for
(points = new Array(n),
- i = 0; i < n; ++i) {
- points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ];
- }
- d3_geom_voronoiTessellate(points, function(e) {
- var l = e.region.l.index, r = e.region.r.index;
- if (graph[l][r]) return;
- graph[l][r] = graph[r][l] = true;
- links.push({
- source: data[l],
- target: data[r]
- });
- });
- return links;
- };
- voronoi.triangles = function(data) {
- if (x === d3_svg_lineX && y === d3_svg_lineY) return
d3.geom.delaunay(data);
- var points = new Array(n), fx = d3_functor(x), fy = d3_functor(y), d, i = -1, n =
data.length;
- while (++i < n) {
- (points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]).data = d;
- }
- return d3.geom.delaunay(points).map(function(triangle) {
- return triangle.map(function(point) {
- return point.data;
- });
- });
- };
- return voronoi;
- };
- var d3_geom_voronoiOpposite = {
- l: "r",
- r: "l"
- };
- function d3_geom_voronoiTessellate(points, callback) {
- var Sites = {
- list: points.map(function(v, i) {
- return {
- index: i,
- x: v[0],
- y: v[1]
- };
- }).sort(function(a, b) {
- return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ?
1 : 0;
- }),
- bottomSite: null
- };
- var EdgeList = {
- list: [],
- leftEnd: null,
- rightEnd: null,
- init: function() {
- EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l");
- EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l");
- EdgeList.leftEnd.r = EdgeList.rightEnd;
- EdgeList.rightEnd.l = EdgeList.leftEnd;
- EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd);
- },
- createHalfEdge: function(edge, side) {
- return {
- edge: edge,
- side: side,
- vertex: null,
- l: null,
- r: null
- };
- },
- insert: function(lb, he) {
- he.l = lb;
- he.r = lb.r;
- lb.r.l = he;
- lb.r = he;
- },
- leftBound: function(p) {
- var he = EdgeList.leftEnd;
- do {
- he = he.r;
- } while (he != EdgeList.rightEnd && Geom.rightOf(he, p));
- he = he.l;
- return he;
- },
- del: function(he) {
- he.l.r = he.r;
- he.r.l = he.l;
- he.edge = null;
- },
- right: function(he) {
- return he.r;
- },
- left: function(he) {
- return he.l;
- },
- leftRegion: function(he) {
- return he.edge == null ? Sites.bottomSite : he.edge.region[he.side];
- },
- rightRegion: function(he) {
- return he.edge == null ? Sites.bottomSite :
he.edge.region[d3_geom_voronoiOpposite[he.side]];
- }
- };
- var Geom = {
- bisect: function(s1, s2) {
- var newEdge = {
- region: {
- l: s1,
- r: s2
- },
- ep: {
- l: null,
- r: null
- }
- };
- var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy >
0 ? dy : -dy;
- newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5;
- if (adx > ady) {
- newEdge.a = 1;
- newEdge.b = dy / dx;
- newEdge.c /= dx;
- } else {
- newEdge.b = 1;
- newEdge.a = dx / dy;
- newEdge.c /= dy;
- }
- return newEdge;
- },
- intersect: function(el1, el2) {
- var e1 = el1.edge, e2 = el2.edge;
- if (!e1 || !e2 || e1.region.r == e2.region.r) {
- return null;
- }
- var d = e1.a * e2.b - e1.b * e2.a;
- if (Math.abs(d) < 1e-10) {
- return null;
- }
- var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) /
d, e1r = e1.region.r, e2r = e2.region.r, el, e;
- if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) {
- el = el1;
- e = e1;
- } else {
- el = el2;
- e = e2;
- }
- var rightOfSite = xint >= e.region.r.x;
- if (rightOfSite && el.side === "l" || !rightOfSite &&
el.side === "r") {
- return null;
- }
- return {
- x: xint,
- y: yint
- };
- },
- rightOf: function(he, p) {
- var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x;
- if (rightOfSite && he.side === "l") {
- return 1;
- }
- if (!rightOfSite && he.side === "r") {
- return 0;
- }
- if (e.a === 1) {
- var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0;
- if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0)
{
- above = fast = dyp >= e.b * dxp;
- } else {
- above = p.x + p.y * e.b > e.c;
- if (e.b < 0) {
- above = !above;
- }
- if (!above) {
- fast = 1;
- }
- }
- if (!fast) {
- var dxs = topsite.x - e.region.l.x;
- above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs +
e.b * e.b);
- if (e.b < 0) {
- above = !above;
- }
- }
- } else {
- var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl -
topsite.y;
- above = t1 * t1 > t2 * t2 + t3 * t3;
- }
- return he.side === "l" ? above : !above;
- },
- endPoint: function(edge, side, site) {
- edge.ep[side] = site;
- if (!edge.ep[d3_geom_voronoiOpposite[side]]) return;
- callback(edge);
- },
- distance: function(s, t) {
- var dx = s.x - t.x, dy = s.y - t.y;
- return Math.sqrt(dx * dx + dy * dy);
- }
- };
- var EventQueue = {
- list: [],
- insert: function(he, site, offset) {
- he.vertex = site;
- he.ystar = site.y + offset;
- for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) {
- var next = list[i];
- if (he.ystar > next.ystar || he.ystar == next.ystar && site.x >
next.vertex.x) {
- continue;
- } else {
- break;
- }
- }
- list.splice(i, 0, he);
- },
- del: function(he) {
- for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] !=
he; ++i) {}
- ls.splice(i, 1);
- },
- empty: function() {
- return EventQueue.list.length === 0;
- },
- nextEvent: function(he) {
- for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) {
- if (ls[i] == he) return ls[i + 1];
- }
- return null;
- },
- min: function() {
- var elem = EventQueue.list[0];
- return {
- x: elem.vertex.x,
- y: elem.ystar
- };
- },
- extractMin: function() {
- return EventQueue.list.shift();
- }
- };
- EdgeList.init();
- Sites.bottomSite = Sites.list.shift();
- var newSite = Sites.list.shift(), newIntStar;
- var lbnd, rbnd, llbnd, rrbnd, bisector;
- var bot, top, temp, p, v;
- var e, pm;
- while (true) {
- if (!EventQueue.empty()) {
- newIntStar = EventQueue.min();
- }
- if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y ||
newSite.y == newIntStar.y && newSite.x < newIntStar.x)) {
- lbnd = EdgeList.leftBound(newSite);
- rbnd = EdgeList.right(lbnd);
- bot = EdgeList.rightRegion(lbnd);
- e = Geom.bisect(bot, newSite);
- bisector = EdgeList.createHalfEdge(e, "l");
- EdgeList.insert(lbnd, bisector);
- p = Geom.intersect(lbnd, bisector);
- if (p) {
- EventQueue.del(lbnd);
- EventQueue.insert(lbnd, p, Geom.distance(p, newSite));
- }
- lbnd = bisector;
- bisector = EdgeList.createHalfEdge(e, "r");
- EdgeList.insert(lbnd, bisector);
- p = Geom.intersect(bisector, rbnd);
- if (p) {
- EventQueue.insert(bisector, p, Geom.distance(p, newSite));
- }
- newSite = Sites.list.shift();
- } else if (!EventQueue.empty()) {
- lbnd = EventQueue.extractMin();
- llbnd = EdgeList.left(lbnd);
- rbnd = EdgeList.right(lbnd);
- rrbnd = EdgeList.right(rbnd);
- bot = EdgeList.leftRegion(lbnd);
- top = EdgeList.rightRegion(rbnd);
- v = lbnd.vertex;
- Geom.endPoint(lbnd.edge, lbnd.side, v);
- Geom.endPoint(rbnd.edge, rbnd.side, v);
- EdgeList.del(lbnd);
- EventQueue.del(rbnd);
- EdgeList.del(rbnd);
- pm = "l";
- if (bot.y > top.y) {
- temp = bot;
- bot = top;
- top = temp;
- pm = "r";
- }
- e = Geom.bisect(bot, top);
- bisector = EdgeList.createHalfEdge(e, pm);
- EdgeList.insert(llbnd, bisector);
- Geom.endPoint(e, d3_geom_voronoiOpposite[pm], v);
- p = Geom.intersect(llbnd, bisector);
- if (p) {
- EventQueue.del(llbnd);
- EventQueue.insert(llbnd, p, Geom.distance(p, bot));
- }
- p = Geom.intersect(bisector, rrbnd);
- if (p) {
- EventQueue.insert(bisector, p, Geom.distance(p, bot));
- }
- } else {
- break;
- }
- }
- for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd =
EdgeList.right(lbnd)) {
- callback(lbnd.edge);
- }
- }
- d3.geom.quadtree = function(points, x1, y1, x2, y2) {
- var x = d3_svg_lineX, y = d3_svg_lineY, compat;
- if (compat = arguments.length) {
- x = d3_geom_quadtreeCompatX;
- y = d3_geom_quadtreeCompatY;
- if (compat === 3) {
- y2 = y1;
- x2 = x1;
- y1 = x1 = 0;
- }
- return quadtree(points);
- }
- function quadtree(data) {
- var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_;
- if (x1 != null) {
- x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2;
- } else {
- x2_ = y2_ = -(x1_ = y1_ = Infinity);
- xs = [], ys = [];
- n = data.length;
- if (compat) for (i = 0; i < n; ++i) {
- d = data[i];
- if (d.x < x1_) x1_ = d.x;
- if (d.y < y1_) y1_ = d.y;
- if (d.x > x2_) x2_ = d.x;
- if (d.y > y2_) y2_ = d.y;
- xs.push(d.x);
- ys.push(d.y);
- } else for (i = 0; i < n; ++i) {
- var x_ = +fx(d = data[i], i), y_ = +fy(d, i);
- if (x_ < x1_) x1_ = x_;
- if (y_ < y1_) y1_ = y_;
- if (x_ > x2_) x2_ = x_;
- if (y_ > y2_) y2_ = y_;
- xs.push(x_);
- ys.push(y_);
- }
- }
- var dx = x2_ - x1_, dy = y2_ - y1_;
- if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy;
- function insert(n, d, x, y, x1, y1, x2, y2) {
- if (isNaN(x) || isNaN(y)) return;
- if (n.leaf) {
- var nx = n.x, ny = n.y;
- if (nx != null) {
- if (Math.abs(nx - x) + Math.abs(ny - y) < .01) {
- insertChild(n, d, x, y, x1, y1, x2, y2);
- } else {
- var nPoint = n.point;
- n.x = n.y = n.point = null;
- insertChild(n, nPoint, nx, ny, x1, y1, x2, y2);
- insertChild(n, d, x, y, x1, y1, x2, y2);
- }
- } else {
- n.x = x, n.y = y, n.point = d;
- }
- } else {
- insertChild(n, d, x, y, x1, y1, x2, y2);
- }
- }
- function insertChild(n, d, x, y, x1, y1, x2, y2) {
- var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y
>= sy, i = (bottom << 1) + right;
- n.leaf = false;
- n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
- if (right) x1 = sx; else x2 = sx;
- if (bottom) y1 = sy; else y2 = sy;
- insert(n, d, x, y, x1, y1, x2, y2);
- }
- var root = d3_geom_quadtreeNode();
- root.add = function(d) {
- insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_);
- };
- root.visit = function(f) {
- d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_);
- };
- i = -1;
- if (x1 == null) {
- while (++i < n) {
- insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_);
- }
- --i;
- } else data.forEach(root.add);
- xs = ys = data = d = null;
- return root;
- }
- quadtree.x = function(_) {
- return arguments.length ? (x = _, quadtree) : x;
- };
- quadtree.y = function(_) {
- return arguments.length ? (y = _, quadtree) : y;
- };
- quadtree.extent = function(_) {
- if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ];
- if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 =
+_[1][0],
- y2 = +_[1][1];
- return quadtree;
- };
- quadtree.size = function(_) {
- if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ];
- if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1];
- return quadtree;
- };
- return quadtree;
- };
- function d3_geom_quadtreeCompatX(d) {
- return d.x;
- }
- function d3_geom_quadtreeCompatY(d) {
- return d.y;
- }
- function d3_geom_quadtreeNode() {
- return {
- leaf: true,
- nodes: [],
- point: null,
- x: null,
- y: null
- };
- }
- function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
- if (!f(node, x1, y1, x2, y2)) {
- var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;
- if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
- if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
- if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
- if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
- }
- }
- d3.interpolateRgb = d3_interpolateRgb;
- function d3_interpolateRgb(a, b) {
- a = d3.rgb(a);
- b = d3.rgb(b);
- var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
- return function(t) {
- return "#" + d3_rgb_hex(Math.round(ar + br * t)) +
d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));
- };
- }
- d3.transform = function(string) {
- var g = d3_document.createElementNS(d3.ns.prefix.svg, "g");
- return (d3.transform = function(string) {
- if (string != null) {
- g.setAttribute("transform", string);
- var t = g.transform.baseVal.consolidate();
- }
- return new d3_transform(t ? t.matrix : d3_transformIdentity);
- })(string);
- };
- function d3_transform(m) {
- var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz =
d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) ||
0;
- if (r0[0] * r1[1] < r1[0] * r0[1]) {
- r0[0] *= -1;
- r0[1] *= -1;
- kx *= -1;
- kz *= -1;
- }
- this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) *
d3_degrees;
- this.translate = [ m.e, m.f ];
- this.scale = [ kx, ky ];
- this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
- }
- d3_transform.prototype.toString = function() {
- return "translate(" + this.translate + ")rotate(" + this.rotate +
")skewX(" + this.skew + ")scale(" + this.scale + ")";
- };
- function d3_transformDot(a, b) {
- return a[0] * b[0] + a[1] * b[1];
- }
- function d3_transformNormalize(a) {
- var k = Math.sqrt(d3_transformDot(a, a));
- if (k) {
- a[0] /= k;
- a[1] /= k;
- }
- return k;
- }
- function d3_transformCombine(a, b, k) {
- a[0] += k * b[0];
- a[1] += k * b[1];
- return a;
- }
- var d3_transformIdentity = {
- a: 1,
- b: 0,
- c: 0,
- d: 1,
- e: 0,
- f: 0
- };
- d3.interpolateNumber = d3_interpolateNumber;
- function d3_interpolateNumber(a, b) {
- b -= a = +a;
- return function(t) {
- return a + b * t;
- };
- }
- d3.interpolateTransform = d3_interpolateTransform;
- function d3_interpolateTransform(a, b) {
- var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb
= B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb =
B.scale;
- if (ta[0] != tb[0] || ta[1] != tb[1]) {
- s.push("translate(", null, ",", null, ")");
- q.push({
- i: 1,
- x: d3_interpolateNumber(ta[0], tb[0])
- }, {
- i: 3,
- x: d3_interpolateNumber(ta[1], tb[1])
- });
- } else if (tb[0] || tb[1]) {
- s.push("translate(" + tb + ")");
- } else {
- s.push("");
- }
- if (ra != rb) {
- if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
- q.push({
- i: s.push(s.pop() + "rotate(", null, ")") - 2,
- x: d3_interpolateNumber(ra, rb)
- });
- } else if (rb) {
- s.push(s.pop() + "rotate(" + rb + ")");
- }
- if (wa != wb) {
- q.push({
- i: s.push(s.pop() + "skewX(", null, ")") - 2,
- x: d3_interpolateNumber(wa, wb)
- });
- } else if (wb) {
- s.push(s.pop() + "skewX(" + wb + ")");
- }
- if (ka[0] != kb[0] || ka[1] != kb[1]) {
- n = s.push(s.pop() + "scale(", null, ",", null,
")");
- q.push({
- i: n - 4,
- x: d3_interpolateNumber(ka[0], kb[0])
- }, {
- i: n - 2,
- x: d3_interpolateNumber(ka[1], kb[1])
- });
- } else if (kb[0] != 1 || kb[1] != 1) {
- s.push(s.pop() + "scale(" + kb + ")");
- }
- n = q.length;
- return function(t) {
- var i = -1, o;
- while (++i < n) s[(o = q[i]).i] = o.x(t);
- return s.join("");
- };
- }
- d3.interpolateObject = d3_interpolateObject;
- function d3_interpolateObject(a, b) {
- var i = {}, c = {}, k;
- for (k in a) {
- if (k in b) {
- i[k] = d3_interpolateByName(k)(a[k], b[k]);
- } else {
- c[k] = a[k];
- }
- }
- for (k in b) {
- if (!(k in a)) {
- c[k] = b[k];
- }
- }
- return function(t) {
- for (k in i) c[k] = i[k](t);
- return c;
- };
- }
- d3.interpolateString = d3_interpolateString;
- function d3_interpolateString(a, b) {
- var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;
- a = a + "", b = b + "";
- d3_interpolate_number.lastIndex = 0;
- for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
- if (m.index) s.push(b.substring(s0, s1 = m.index));
- q.push({
- i: s.length,
- x: m[0]
- });
- s.push(null);
- s0 = d3_interpolate_number.lastIndex;
- }
- if (s0 < b.length) s.push(b.substring(s0));
- for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n;
++i) {
- o = q[i];
- if (o.x == m[0]) {
- if (o.i) {
- if (s[o.i + 1] == null) {
- s[o.i - 1] += o.x;
- s.splice(o.i, 1);
- for (j = i + 1; j < n; ++j) q[j].i--;
- } else {
- s[o.i - 1] += o.x + s[o.i + 1];
- s.splice(o.i, 2);
- for (j = i + 1; j < n; ++j) q[j].i -= 2;
- }
- } else {
- if (s[o.i + 1] == null) {
- s[o.i] = o.x;
- } else {
- s[o.i] = o.x + s[o.i + 1];
- s.splice(o.i + 1, 1);
- for (j = i + 1; j < n; ++j) q[j].i--;
- }
- }
- q.splice(i, 1);
- n--;
- i--;
- } else {
- o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
- }
- }
- while (i < n) {
- o = q.pop();
- if (s[o.i + 1] == null) {
- s[o.i] = o.x;
- } else {
- s[o.i] = o.x + s[o.i + 1];
- s.splice(o.i + 1, 1);
- }
- n--;
- }
- if (s.length === 1) {
- return s[0] == null ? (o = q[0].x, function(t) {
- return o(t) + "";
- }) : function() {
- return b;
- };
- }
- return function(t) {
- for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
- return s.join("");
- };
- }
- var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
- d3.interpolate = d3_interpolate;
- function d3_interpolate(a, b) {
- var i = d3.interpolators.length, f;
- while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
- return f;
- }
- function d3_interpolateByName(name) {
- return name == "transform" ? d3_interpolateTransform : d3_interpolate;
- }
- d3.interpolators = [ function(a, b) {
- var t = typeof b;
- return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b)
? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : t
=== "object" ? Array.isArray(b) ? d3_interpolateArray : d3_interpolateObject :
d3_interpolateNumber)(a, b);
- } ];
- d3.interpolateArray = d3_interpolateArray;
- function d3_interpolateArray(a, b) {
- var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length),
i;
- for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i]));
- for (;i < na; ++i) c[i] = a[i];
- for (;i < nb; ++i) c[i] = b[i];
- return function(t) {
- for (i = 0; i < n0; ++i) c[i] = x[i](t);
- return c;
- };
- }
- var d3_ease_default = function() {
- return d3_identity;
- };
- var d3_ease = d3.map({
- linear: d3_ease_default,
- poly: d3_ease_poly,
- quad: function() {
- return d3_ease_quad;
- },
- cubic: function() {
- return d3_ease_cubic;
- },
- sin: function() {
- return d3_ease_sin;
- },
- exp: function() {
- return d3_ease_exp;
- },
- circle: function() {
- return d3_ease_circle;
- },
- elastic: d3_ease_elastic,
- back: d3_ease_back,
- bounce: function() {
- return d3_ease_bounce;
- }
- });
- var d3_ease_mode = d3.map({
- "in": d3_identity,
- out: d3_ease_reverse,
- "in-out": d3_ease_reflect,
- "out-in": function(f) {
- return d3_ease_reflect(d3_ease_reverse(f));
- }
- });
- d3.ease = function(name) {
- var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m =
i >= 0 ? name.substring(i + 1) : "in";
- t = d3_ease.get(t) || d3_ease_default;
- m = d3_ease_mode.get(m) || d3_identity;
- return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1))));
- };
- function d3_ease_clamp(f) {
- return function(t) {
- return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
- };
- }
- function d3_ease_reverse(f) {
- return function(t) {
- return 1 - f(1 - t);
- };
- }
- function d3_ease_reflect(f) {
- return function(t) {
- return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
- };
- }
- function d3_ease_quad(t) {
- return t * t;
- }
- function d3_ease_cubic(t) {
- return t * t * t;
- }
- function d3_ease_cubicInOut(t) {
- if (t <= 0) return 0;
- if (t >= 1) return 1;
- var t2 = t * t, t3 = t2 * t;
- return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
- }
- function d3_ease_poly(e) {
- return function(t) {
- return Math.pow(t, e);
- };
- }
- function d3_ease_sin(t) {
- return 1 - Math.cos(t * Ï / 2);
- }
- function d3_ease_exp(t) {
- return Math.pow(2, 10 * (t - 1));
- }
- function d3_ease_circle(t) {
- return 1 - Math.sqrt(1 - t * t);
- }
- function d3_ease_elastic(a, p) {
- var s;
- if (arguments.length < 2) p = .45;
- if (arguments.length) s = p / (2 * Ï) * Math.asin(1 / a); else a = 1, s = p / 4;
- return function(t) {
- return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * Ï / p);
- };
- }
- function d3_ease_back(s) {
- if (!s) s = 1.70158;
- return function(t) {
- return t * t * ((s + 1) * t - s);
- };
- }
- function d3_ease_bounce(t) {
- return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 /
2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 *
(t -= 2.625 / 2.75) * t + .984375;
- }
- d3.interpolateHcl = d3_interpolateHcl;
- function d3_interpolateHcl(a, b) {
- a = d3.hcl(a);
- b = d3.hcl(b);
- var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;
- if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac;
- if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360;
else if (bh < -180) bh += 360;
- return function(t) {
- return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
- };
- }
- d3.interpolateHsl = d3_interpolateHsl;
- function d3_interpolateHsl(a, b) {
- a = d3.hsl(a);
- b = d3.hsl(b);
- var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al;
- if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as;
- if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360;
else if (bh < -180) bh += 360;
- return function(t) {
- return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + "";
- };
- }
- d3.interpolateLab = d3_interpolateLab;
- function d3_interpolateLab(a, b) {
- a = d3.lab(a);
- b = d3.lab(b);
- var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;
- return function(t) {
- return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
- };
- }
- d3.interpolateRound = d3_interpolateRound;
- function d3_interpolateRound(a, b) {
- b -= a;
- return function(t) {
- return Math.round(a + b * t);
- };
- }
- function d3_uninterpolateNumber(a, b) {
- b = b - (a = +a) ? 1 / (b - a) : 0;
- return function(x) {
- return (x - a) * b;
- };
- }
- function d3_uninterpolateClamp(a, b) {
- b = b - (a = +a) ? 1 / (b - a) : 0;
- return function(x) {
- return Math.max(0, Math.min(1, (x - a) * b));
- };
- }
- d3.layout = {};
- d3.layout.bundle = function() {
- return function(links) {
- var paths = [], i = -1, n = links.length;
- while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
- return paths;
- };
- };
- function d3_layout_bundlePath(link) {
- var start = link.source, end = link.target, lca =
d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
- while (start !== lca) {
- start = start.parent;
- points.push(start);
- }
- var k = points.length;
- while (end !== lca) {
- points.splice(k, 0, end);
- end = end.parent;
- }
- return points;
- }
- function d3_layout_bundleAncestors(node) {
- var ancestors = [], parent = node.parent;
- while (parent != null) {
- ancestors.push(node);
- node = parent;
- parent = parent.parent;
- }
- ancestors.push(node);
- return ancestors;
- }
- function d3_layout_bundleLeastCommonAncestor(a, b) {
- if (a === b) return a;
- var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b),
aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
- while (aNode === bNode) {
- sharedNode = aNode;
- aNode = aNodes.pop();
- bNode = bNodes.pop();
- }
- return sharedNode;
- }
- d3.layout.chord = function() {
- var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups,
sortChords;
- function relayout() {
- var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [],
k, x, x0, i, j;
- chords = [];
- groups = [];
- k = 0, i = -1;
- while (++i < n) {
- x = 0, j = -1;
- while (++j < n) {
- x += matrix[i][j];
- }
- groupSums.push(x);
- subgroupIndex.push(d3.range(n));
- k += x;
- }
- if (sortGroups) {
- groupIndex.sort(function(a, b) {
- return sortGroups(groupSums[a], groupSums[b]);
- });
- }
- if (sortSubgroups) {
- subgroupIndex.forEach(function(d, i) {
- d.sort(function(a, b) {
- return sortSubgroups(matrix[i][a], matrix[i][b]);
- });
- });
- }
- k = (2 * Ï - padding * n) / k;
- x = 0, i = -1;
- while (++i < n) {
- x0 = x, j = -1;
- while (++j < n) {
- var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x,
a1 = x += v * k;
- subgroups[di + "-" + dj] = {
- index: di,
- subindex: dj,
- startAngle: a0,
- endAngle: a1,
- value: v
- };
- }
- groups[di] = {
- index: di,
- startAngle: x0,
- endAngle: x,
- value: (x - x0) / k
- };
- x += padding;
- }
- i = -1;
- while (++i < n) {
- j = i - 1;
- while (++j < n) {
- var source = subgroups[i + "-" + j], target = subgroups[j +
"-" + i];
- if (source.value || target.value) {
- chords.push(source.value < target.value ? {
- source: target,
- target: source
- } : {
- source: source,
- target: target
- });
- }
- }
- }
- if (sortChords) resort();
- }
- function resort() {
- chords.sort(function(a, b) {
- return sortChords((a.source.value + a.target.value) / 2, (b.source.value +
b.target.value) / 2);
- });
- }
- chord.matrix = function(x) {
- if (!arguments.length) return matrix;
- n = (matrix = x) && matrix.length;
- chords = groups = null;
- return chord;
- };
- chord.padding = function(x) {
- if (!arguments.length) return padding;
- padding = x;
- chords = groups = null;
- return chord;
- };
- chord.sortGroups = function(x) {
- if (!arguments.length) return sortGroups;
- sortGroups = x;
- chords = groups = null;
- return chord;
- };
- chord.sortSubgroups = function(x) {
- if (!arguments.length) return sortSubgroups;
- sortSubgroups = x;
- chords = null;
- return chord;
- };
- chord.sortChords = function(x) {
- if (!arguments.length) return sortChords;
- sortChords = x;
- if (chords) resort();
- return chord;
- };
- chord.chords = function() {
- if (!chords) relayout();
- return chords;
- };
- chord.groups = function() {
- if (!groups) relayout();
- return groups;
- };
- return chord;
- };
- d3.layout.force = function() {
- var force = {}, event = d3.dispatch("start", "tick",
"end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance =
d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30,
gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges;
- function repulse(node) {
- return function(quad, x1, _, x2) {
- if (quad.point !== node) {
- var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx +
dy * dy);
- if ((x2 - x1) * dn < theta) {
- var k = quad.charge * dn * dn;
- node.px -= dx * k;
- node.py -= dy * k;
- return true;
- }
- if (quad.point && isFinite(dn)) {
- var k = quad.pointCharge * dn * dn;
- node.px -= dx * k;
- node.py -= dy * k;
- }
- }
- return !quad.charge;
- };
- }
- force.tick = function() {
- if ((alpha *= .99) < .005) {
- event.end({
- type: "end",
- alpha: alpha = 0
- });
- return true;
- }
- var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
- for (i = 0; i < m; ++i) {
- o = links[i];
- s = o.source;
- t = o.target;
- x = t.x - s.x;
- y = t.y - s.y;
- if (l = x * x + y * y) {
- l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
- x *= l;
- y *= l;
- t.x -= x * (k = s.weight / (t.weight + s.weight));
- t.y -= y * k;
- s.x += x * (k = 1 - k);
- s.y += y * k;
- }
- }
- if (k = alpha * gravity) {
- x = size[0] / 2;
- y = size[1] / 2;
- i = -1;
- if (k) while (++i < n) {
- o = nodes[i];
- o.x += (x - o.x) * k;
- o.y += (y - o.y) * k;
- }
- }
- if (charge) {
- d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
- i = -1;
- while (++i < n) {
- if (!(o = nodes[i]).fixed) {
- q.visit(repulse(o));
- }
- }
- }
- i = -1;
- while (++i < n) {
- o = nodes[i];
- if (o.fixed) {
- o.x = o.px;
- o.y = o.py;
- } else {
- o.x -= (o.px - (o.px = o.x)) * friction;
- o.y -= (o.py - (o.py = o.y)) * friction;
- }
- }
- event.tick({
- type: "tick",
- alpha: alpha
- });
- };
- force.nodes = function(x) {
- if (!arguments.length) return nodes;
- nodes = x;
- return force;
- };
- force.links = function(x) {
- if (!arguments.length) return links;
- links = x;
- return force;
- };
- force.size = function(x) {
- if (!arguments.length) return size;
- size = x;
- return force;
- };
- force.linkDistance = function(x) {
- if (!arguments.length) return linkDistance;
- linkDistance = typeof x === "function" ? x : +x;
- return force;
- };
- force.distance = force.linkDistance;
- force.linkStrength = function(x) {
- if (!arguments.length) return linkStrength;
- linkStrength = typeof x === "function" ? x : +x;
- return force;
- };
- force.friction = function(x) {
- if (!arguments.length) return friction;
- friction = +x;
- return force;
- };
- force.charge = function(x) {
- if (!arguments.length) return charge;
- charge = typeof x === "function" ? x : +x;
- return force;
- };
- force.gravity = function(x) {
- if (!arguments.length) return gravity;
- gravity = +x;
- return force;
- };
- force.theta = function(x) {
- if (!arguments.length) return theta;
- theta = +x;
- return force;
- };
- force.alpha = function(x) {
- if (!arguments.length) return alpha;
- x = +x;
- if (alpha) {
- if (x > 0) alpha = x; else alpha = 0;
- } else if (x > 0) {
- event.start({
- type: "start",
- alpha: alpha = x
- });
- d3.timer(force.tick);
- }
- return force;
- };
- force.start = function() {
- var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors,
o;
- for (i = 0; i < n; ++i) {
- (o = nodes[i]).index = i;
- o.weight = 0;
- }
- for (i = 0; i < m; ++i) {
- o = links[i];
- if (typeof o.source == "number") o.source = nodes[o.source];
- if (typeof o.target == "number") o.target = nodes[o.target];
- ++o.source.weight;
- ++o.target.weight;
- }
- for (i = 0; i < n; ++i) {
- o = nodes[i];
- if (isNaN(o.x)) o.x = position("x", w);
- if (isNaN(o.y)) o.y = position("y", h);
- if (isNaN(o.px)) o.px = o.x;
- if (isNaN(o.py)) o.py = o.y;
- }
- distances = [];
- if (typeof linkDistance === "function") for (i = 0; i < m; ++i)
distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i)
distances[i] = linkDistance;
- strengths = [];
- if (typeof linkStrength === "function") for (i = 0; i < m; ++i)
strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i)
strengths[i] = linkStrength;
- charges = [];
- if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] =
+charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge;
- function position(dimension, size) {
- var neighbors = neighbor(i), j = -1, m = neighbors.length, x;
- while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x;
- return Math.random() * size;
- }
- function neighbor() {
- if (!neighbors) {
- neighbors = [];
- for (j = 0; j < n; ++j) {
- neighbors[j] = [];
- }
- for (j = 0; j < m; ++j) {
- var o = links[j];
- neighbors[o.source.index].push(o.target);
- neighbors[o.target.index].push(o.source);
- }
- }
- return neighbors[i];
- }
- return force.resume();
- };
- force.resume = function() {
- return force.alpha(.1);
- };
- force.stop = function() {
- return force.alpha(0);
- };
- force.drag = function() {
- if (!drag) drag =
d3.behavior.drag().origin(d3_identity).on("dragstart.force",
d3_layout_forceDragstart).on("drag.force",
dragmove).on("dragend.force", d3_layout_forceDragend);
- if (!arguments.length) return drag;
- this.on("mouseover.force",
d3_layout_forceMouseover).on("mouseout.force",
d3_layout_forceMouseout).call(drag);
- };
- function dragmove(d) {
- d.px = d3.event.x, d.py = d3.event.y;
- force.resume();
- }
- return d3.rebind(force, event, "on");
- };
- function d3_layout_forceDragstart(d) {
- d.fixed |= 2;
- }
- function d3_layout_forceDragend(d) {
- d.fixed &= ~6;
- }
- function d3_layout_forceMouseover(d) {
- d.fixed |= 4;
- d.px = d.x, d.py = d.y;
- }
- function d3_layout_forceMouseout(d) {
- d.fixed &= ~4;
- }
- function d3_layout_forceAccumulate(quad, alpha, charges) {
- var cx = 0, cy = 0;
- quad.charge = 0;
- if (!quad.leaf) {
- var nodes = quad.nodes, n = nodes.length, i = -1, c;
- while (++i < n) {
- c = nodes[i];
- if (c == null) continue;
- d3_layout_forceAccumulate(c, alpha, charges);
- quad.charge += c.charge;
- cx += c.charge * c.cx;
- cy += c.charge * c.cy;
- }
- }
- if (quad.point) {
- if (!quad.leaf) {
- quad.point.x += Math.random() - .5;
- quad.point.y += Math.random() - .5;
- }
- var k = alpha * charges[quad.point.index];
- quad.charge += quad.pointCharge = k;
- cx += k * quad.point.x;
- cy += k * quad.point.y;
- }
- quad.cx = cx / quad.charge;
- quad.cy = cy / quad.charge;
- }
- var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1;
- d3.layout.hierarchy = function() {
- var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value =
d3_layout_hierarchyValue;
- function recurse(node, depth, nodes) {
- var childs = children.call(hierarchy, node, depth);
- node.depth = depth;
- nodes.push(node);
- if (childs && (n = childs.length)) {
- var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d;
- while (++i < n) {
- d = recurse(childs[i], j, nodes);
- d.parent = node;
- c.push(d);
- v += d.value;
- }
- if (sort) c.sort(sort);
- if (value) node.value = v;
- } else if (value) {
- node.value = +value.call(hierarchy, node, depth) || 0;
- }
- return node;
- }
- function revalue(node, depth) {
- var children = node.children, v = 0;
- if (children && (n = children.length)) {
- var i = -1, n, j = depth + 1;
- while (++i < n) v += revalue(children[i], j);
- } else if (value) {
- v = +value.call(hierarchy, node, depth) || 0;
- }
- if (value) node.value = v;
- return v;
- }
- function hierarchy(d) {
- var nodes = [];
- recurse(d, 0, nodes);
- return nodes;
- }
- hierarchy.sort = function(x) {
- if (!arguments.length) return sort;
- sort = x;
- return hierarchy;
- };
- hierarchy.children = function(x) {
- if (!arguments.length) return children;
- children = x;
- return hierarchy;
- };
- hierarchy.value = function(x) {
- if (!arguments.length) return value;
- value = x;
- return hierarchy;
- };
- hierarchy.revalue = function(root) {
- revalue(root, 0);
- return root;
- };
- return hierarchy;
- };
- function d3_layout_hierarchyRebind(object, hierarchy) {
- d3.rebind(object, hierarchy, "sort", "children",
"value");
- object.nodes = object;
- object.links = d3_layout_hierarchyLinks;
- return object;
- }
- function d3_layout_hierarchyChildren(d) {
- return d.children;
- }
- function d3_layout_hierarchyValue(d) {
- return d.value;
- }
- function d3_layout_hierarchySort(a, b) {
- return b.value - a.value;
- }
- function d3_layout_hierarchyLinks(nodes) {
- return d3.merge(nodes.map(function(parent) {
- return (parent.children || []).map(function(child) {
- return {
- source: parent,
- target: child
- };
- });
- }));
- }
- d3.layout.partition = function() {
- var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
- function position(node, x, dx, dy) {
- var children = node.children;
- node.x = x;
- node.y = node.depth * dy;
- node.dx = dx;
- node.dy = dy;
- if (children && (n = children.length)) {
- var i = -1, n, c, d;
- dx = node.value ? dx / node.value : 0;
- while (++i < n) {
- position(c = children[i], x, d = c.value * dx, dy);
- x += d;
- }
- }
- }
- function depth(node) {
- var children = node.children, d = 0;
- if (children && (n = children.length)) {
- var i = -1, n;
- while (++i < n) d = Math.max(d, depth(children[i]));
- }
- return 1 + d;
- }
- function partition(d, i) {
- var nodes = hierarchy.call(this, d, i);
- position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
- return nodes;
- }
- partition.size = function(x) {
- if (!arguments.length) return size;
- size = x;
- return partition;
- };
- return d3_layout_hierarchyRebind(partition, hierarchy);
- };
- d3.layout.pie = function() {
- var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 *
Ï;
- function pie(data) {
- var values = data.map(function(d, i) {
- return +value.call(pie, d, i);
- });
- var a = +(typeof startAngle === "function" ? startAngle.apply(this,
arguments) : startAngle);
- var k = ((typeof endAngle === "function" ? endAngle.apply(this,
arguments) : endAngle) - a) / d3.sum(values);
- var index = d3.range(data.length);
- if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
- return values[j] - values[i];
- } : function(i, j) {
- return sort(data[i], data[j]);
- });
- var arcs = [];
- index.forEach(function(i) {
- var d;
- arcs[i] = {
- data: data[i],
- value: d = values[i],
- startAngle: a,
- endAngle: a += d * k
- };
- });
- return arcs;
- }
- pie.value = function(x) {
- if (!arguments.length) return value;
- value = x;
- return pie;
- };
- pie.sort = function(x) {
- if (!arguments.length) return sort;
- sort = x;
- return pie;
- };
- pie.startAngle = function(x) {
- if (!arguments.length) return startAngle;
- startAngle = x;
- return pie;
- };
- pie.endAngle = function(x) {
- if (!arguments.length) return endAngle;
- endAngle = x;
- return pie;
- };
- return pie;
- };
- var d3_layout_pieSortByValue = {};
- d3.layout.stack = function() {
- var values = d3_identity, order = d3_layout_stackOrderDefault, offset =
d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y =
d3_layout_stackY;
- function stack(data, index) {
- var series = data.map(function(d, i) {
- return values.call(stack, d, i);
- });
- var points = series.map(function(d) {
- return d.map(function(v, i) {
- return [ x.call(stack, v, i), y.call(stack, v, i) ];
- });
- });
- var orders = order.call(stack, points, index);
- series = d3.permute(series, orders);
- points = d3.permute(points, orders);
- var offsets = offset.call(stack, points, index);
- var n = series.length, m = series[0].length, i, j, o;
- for (j = 0; j < m; ++j) {
- out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
- for (i = 1; i < n; ++i) {
- out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
- }
- }
- return data;
- }
- stack.values = function(x) {
- if (!arguments.length) return values;
- values = x;
- return stack;
- };
- stack.order = function(x) {
- if (!arguments.length) return order;
- order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) ||
d3_layout_stackOrderDefault;
- return stack;
- };
- stack.offset = function(x) {
- if (!arguments.length) return offset;
- offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) ||
d3_layout_stackOffsetZero;
- return stack;
- };
- stack.x = function(z) {
- if (!arguments.length) return x;
- x = z;
- return stack;
- };
- stack.y = function(z) {
- if (!arguments.length) return y;
- y = z;
- return stack;
- };
- stack.out = function(z) {
- if (!arguments.length) return out;
- out = z;
- return stack;
- };
- return stack;
- };
- function d3_layout_stackX(d) {
- return d.x;
- }
- function d3_layout_stackY(d) {
- return d.y;
- }
- function d3_layout_stackOut(d, y0, y) {
- d.y0 = y0;
- d.y = y;
- }
- var d3_layout_stackOrders = d3.map({
- "inside-out": function(data) {
- var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums =
data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {
- return max[a] - max[b];
- }), top = 0, bottom = 0, tops = [], bottoms = [];
- for (i = 0; i < n; ++i) {
- j = index[i];
- if (top < bottom) {
- top += sums[j];
- tops.push(j);
- } else {
- bottom += sums[j];
- bottoms.push(j);
- }
- }
- return bottoms.reverse().concat(tops);
- },
- reverse: function(data) {
- return d3.range(data.length).reverse();
- },
- "default": d3_layout_stackOrderDefault
- });
- var d3_layout_stackOffsets = d3.map({
- silhouette: function(data) {
- var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
- for (j = 0; j < m; ++j) {
- for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
- if (o > max) max = o;
- sums.push(o);
- }
- for (j = 0; j < m; ++j) {
- y0[j] = (max - sums[j]) / 2;
- }
- return y0;
- },
- wiggle: function(data) {
- var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0
= [];
- y0[0] = o = o0 = 0;
- for (j = 1; j < m; ++j) {
- for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
- for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
- for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k)
{
- s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
- }
- s2 += s3 * data[i][j][1];
- }
- y0[j] = o -= s1 ? s2 / s1 * dx : 0;
- if (o < o0) o0 = o;
- }
- for (j = 0; j < m; ++j) y0[j] -= o0;
- return y0;
- },
- expand: function(data) {
- var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
- for (j = 0; j < m; ++j) {
- for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
- if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n;
i++) data[i][j][1] = k;
- }
- for (j = 0; j < m; ++j) y0[j] = 0;
- return y0;
- },
- zero: d3_layout_stackOffsetZero
- });
- function d3_layout_stackOrderDefault(data) {
- return d3.range(data.length);
- }
- function d3_layout_stackOffsetZero(data) {
- var j = -1, m = data[0].length, y0 = [];
- while (++j < m) y0[j] = 0;
- return y0;
- }
- function d3_layout_stackMaxIndex(array) {
- var i = 1, j = 0, v = array[0][1], k, n = array.length;
- for (;i < n; ++i) {
- if ((k = array[i][1]) > v) {
- j = i;
- v = k;
- }
- }
- return j;
- }
- function d3_layout_stackReduceSum(d) {
- return d.reduce(d3_layout_stackSum, 0);
- }
- function d3_layout_stackSum(p, d) {
- return p + d[1];
- }
- d3.layout.histogram = function() {
- var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner =
d3_layout_histogramBinSturges;
- function histogram(data, i) {
- var bins = [], values = data.map(valuer, this), range = ranger.call(this, values,
i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m =
thresholds.length - 1, k = frequency ? 1 : 1 / n, x;
- while (++i < m) {
- bin = bins[i] = [];
- bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
- bin.y = 0;
- }
- if (m > 0) {
- i = -1;
- while (++i < n) {
- x = values[i];
- if (x >= range[0] && x <= range[1]) {
- bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
- bin.y += k;
- bin.push(data[i]);
- }
- }
- }
- return bins;
- }
- histogram.value = function(x) {
- if (!arguments.length) return valuer;
- valuer = x;
- return histogram;
- };
- histogram.range = function(x) {
- if (!arguments.length) return ranger;
- ranger = d3_functor(x);
- return histogram;
- };
- histogram.bins = function(x) {
- if (!arguments.length) return binner;
- binner = typeof x === "number" ? function(range) {
- return d3_layout_histogramBinFixed(range, x);
- } : d3_functor(x);
- return histogram;
- };
- histogram.frequency = function(x) {
- if (!arguments.length) return frequency;
- frequency = !!x;
- return histogram;
- };
- return histogram;
- };
- function d3_layout_histogramBinSturges(range, values) {
- return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) /
Math.LN2 + 1));
- }
- function d3_layout_histogramBinFixed(range, n) {
- var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
- while (++x <= n) f[x] = m * x + b;
- return f;
- }
- function d3_layout_histogramRange(values) {
- return [ d3.min(values), d3.max(values) ];
- }
- d3.layout.tree = function() {
- var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation =
d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
- function tree(d, i) {
- var nodes = hierarchy.call(this, d, i), root = nodes[0];
- function firstWalk(node, previousSibling) {
- var children = node.children, layout = node._tree;
- if (children && (n = children.length)) {
- var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i
= -1;
- while (++i < n) {
- child = children[i];
- firstWalk(child, previousChild);
- ancestor = apportion(child, previousChild, ancestor);
- previousChild = child;
- }
- d3_layout_treeShift(node);
- var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
- if (previousSibling) {
- layout.prelim = previousSibling._tree.prelim + separation(node,
previousSibling);
- layout.mod = layout.prelim - midpoint;
- } else {
- layout.prelim = midpoint;
- }
- } else {
- if (previousSibling) {
- layout.prelim = previousSibling._tree.prelim + separation(node,
previousSibling);
- }
- }
- }
- function secondWalk(node, x) {
- node.x = node._tree.prelim + x;
- var children = node.children;
- if (children && (n = children.length)) {
- var i = -1, n;
- x += node._tree.mod;
- while (++i < n) {
- secondWalk(children[i], x);
- }
- }
- }
- function apportion(node, previousSibling, ancestor) {
- if (previousSibling) {
- var vip = node, vop = node, vim = previousSibling, vom =
node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod,
som = vom._tree.mod, shift;
- while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim
&& vip) {
- vom = d3_layout_treeLeft(vom);
- vop = d3_layout_treeRight(vop);
- vop._tree.ancestor = node;
- shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim,
vip);
- if (shift > 0) {
- d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node,
shift);
- sip += shift;
- sop += shift;
- }
- sim += vim._tree.mod;
- sip += vip._tree.mod;
- som += vom._tree.mod;
- sop += vop._tree.mod;
- }
- if (vim && !d3_layout_treeRight(vop)) {
- vop._tree.thread = vim;
- vop._tree.mod += sim - sop;
- }
- if (vip && !d3_layout_treeLeft(vom)) {
- vom._tree.thread = vip;
- vom._tree.mod += sip - som;
- ancestor = node;
- }
- }
- return ancestor;
- }
- d3_layout_treeVisitAfter(root, function(node, previousSibling) {
- node._tree = {
- ancestor: node,
- prelim: 0,
- mod: 0,
- change: 0,
- shift: 0,
- number: previousSibling ? previousSibling._tree.number + 1 : 0
- };
- });
- firstWalk(root);
- secondWalk(root, -root._tree.prelim);
- var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right =
d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root,
d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x +
separation(right, left) / 2, y1 = deep.depth || 1;
- d3_layout_treeVisitAfter(root, nodeSize ? function(node) {
- node.x *= size[0];
- node.y = node.depth * size[1];
- delete node._tree;
- } : function(node) {
- node.x = (node.x - x0) / (x1 - x0) * size[0];
- node.y = node.depth / y1 * size[1];
- delete node._tree;
- });
- return nodes;
- }
- tree.separation = function(x) {
- if (!arguments.length) return separation;
- separation = x;
- return tree;
- };
- tree.size = function(x) {
- if (!arguments.length) return nodeSize ? null : size;
- nodeSize = (size = x) == null;
- return tree;
- };
- tree.nodeSize = function(x) {
- if (!arguments.length) return nodeSize ? size : null;
- nodeSize = (size = x) != null;
- return tree;
- };
- return d3_layout_hierarchyRebind(tree, hierarchy);
- };
- function d3_layout_treeSeparation(a, b) {
- return a.parent == b.parent ? 1 : 2;
- }
- function d3_layout_treeLeft(node) {
- var children = node.children;
- return children && children.length ? children[0] : node._tree.thread;
- }
- function d3_layout_treeRight(node) {
- var children = node.children, n;
- return children && (n = children.length) ? children[n - 1] :
node._tree.thread;
- }
- function d3_layout_treeSearch(node, compare) {
- var children = node.children;
- if (children && (n = children.length)) {
- var child, n, i = -1;
- while (++i < n) {
- if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
- node = child;
- }
- }
- }
- return node;
- }
- function d3_layout_treeRightmost(a, b) {
- return a.x - b.x;
- }
- function d3_layout_treeLeftmost(a, b) {
- return b.x - a.x;
- }
- function d3_layout_treeDeepest(a, b) {
- return a.depth - b.depth;
- }
- function d3_layout_treeVisitAfter(node, callback) {
- function visit(node, previousSibling) {
- var children = node.children;
- if (children && (n = children.length)) {
- var child, previousChild = null, i = -1, n;
- while (++i < n) {
- child = children[i];
- visit(child, previousChild);
- previousChild = child;
- }
- }
- callback(node, previousSibling);
- }
- visit(node, null);
- }
- function d3_layout_treeShift(node) {
- var shift = 0, change = 0, children = node.children, i = children.length, child;
- while (--i >= 0) {
- child = children[i]._tree;
- child.prelim += shift;
- child.mod += shift;
- shift += child.shift + (change += child.change);
- }
- }
- function d3_layout_treeMove(ancestor, node, shift) {
- ancestor = ancestor._tree;
- node = node._tree;
- var change = shift / (node.number - ancestor.number);
- ancestor.change += change;
- node.change -= change;
- node.shift += shift;
- node.prelim += shift;
- node.mod += shift;
- }
- function d3_layout_treeAncestor(vim, node, ancestor) {
- return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor;
- }
- d3.layout.pack = function() {
- var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [
1, 1 ], radius;
- function pack(d, i) {
- var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1],
r = radius || Math.sqrt;
- root.x = root.y = 0;
- d3_layout_treeVisitAfter(root, function(d) {
- d.r = r(d.value);
- });
- d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
- if (padding) {
- var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2;
- d3_layout_treeVisitAfter(root, function(d) {
- d.r += dr;
- });
- d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
- d3_layout_treeVisitAfter(root, function(d) {
- d.r -= dr;
- });
- }
- d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r /
w, 2 * root.r / h));
- return nodes;
- }
- pack.size = function(_) {
- if (!arguments.length) return size;
- size = _;
- return pack;
- };
- pack.radius = function(_) {
- if (!arguments.length) return radius;
- radius = _;
- return pack;
- };
- pack.padding = function(_) {
- if (!arguments.length) return padding;
- padding = +_;
- return pack;
- };
- return d3_layout_hierarchyRebind(pack, hierarchy);
- };
- function d3_layout_packSort(a, b) {
- return a.value - b.value;
- }
- function d3_layout_packInsert(a, b) {
- var c = a._pack_next;
- a._pack_next = b;
- b._pack_prev = a;
- b._pack_next = c;
- c._pack_prev = b;
- }
- function d3_layout_packSplice(a, b) {
- a._pack_next = b;
- b._pack_prev = a;
- }
- function d3_layout_packIntersects(a, b) {
- var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
- return .999 * dr * dr > dx * dx + dy * dy;
- }
- function d3_layout_packSiblings(node) {
- if (!(nodes = node.children) || !(n = nodes.length)) return;
- var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a,
b, c, i, j, k, n;
- function bound(node) {
- xMin = Math.min(node.x - node.r, xMin);
- xMax = Math.max(node.x + node.r, xMax);
- yMin = Math.min(node.y - node.r, yMin);
- yMax = Math.max(node.y + node.r, yMax);
- }
- nodes.forEach(d3_layout_packLink);
- a = nodes[0];
- a.x = -a.r;
- a.y = 0;
- bound(a);
- if (n > 1) {
- b = nodes[1];
- b.x = b.r;
- b.y = 0;
- bound(b);
- if (n > 2) {
- c = nodes[2];
- d3_layout_packPlace(a, b, c);
- bound(c);
- d3_layout_packInsert(a, c);
- a._pack_prev = c;
- d3_layout_packInsert(c, b);
- b = a._pack_next;
- for (i = 3; i < n; i++) {
- d3_layout_packPlace(a, b, c = nodes[i]);
- var isect = 0, s1 = 1, s2 = 1;
- for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
- if (d3_layout_packIntersects(j, c)) {
- isect = 1;
- break;
- }
- }
- if (isect == 1) {
- for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
- if (d3_layout_packIntersects(k, c)) {
- break;
- }
- }
- }
- if (isect) {
- if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b
= j); else d3_layout_packSplice(a = k, b);
- i--;
- } else {
- d3_layout_packInsert(a, c);
- b = c;
- bound(c);
- }
- }
- }
- }
- var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
- for (i = 0; i < n; i++) {
- c = nodes[i];
- c.x -= cx;
- c.y -= cy;
- cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
- }
- node.r = cr;
- nodes.forEach(d3_layout_packUnlink);
- }
- function d3_layout_packLink(node) {
- node._pack_next = node._pack_prev = node;
- }
- function d3_layout_packUnlink(node) {
- delete node._pack_next;
- delete node._pack_prev;
- }
- function d3_layout_packTransform(node, x, y, k) {
- var children = node.children;
- node.x = x += k * node.x;
- node.y = y += k * node.y;
- node.r *= k;
- if (children) {
- var i = -1, n = children.length;
- while (++i < n) d3_layout_packTransform(children[i], x, y, k);
- }
- }
- function d3_layout_packPlace(a, b, c) {
- var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
- if (db && (dx || dy)) {
- var da = b.r + c.r, dc = dx * dx + dy * dy;
- da *= da;
- db *= db;
- var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) -
(db -= dc) * db - da * da)) / (2 * dc);
- c.x = a.x + x * dx + y * dy;
- c.y = a.y + x * dy - y * dx;
- } else {
- c.x = a.x + db;
- c.y = a.y;
- }
- }
- d3.layout.cluster = function() {
- var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation =
d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
- function cluster(d, i) {
- var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
- d3_layout_treeVisitAfter(root, function(node) {
- var children = node.children;
- if (children && children.length) {
- node.x = d3_layout_clusterX(children);
- node.y = d3_layout_clusterY(children);
- } else {
- node.x = previousNode ? x += separation(node, previousNode) : 0;
- node.y = 0;
- previousNode = node;
- }
- });
- var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 =
left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;
- d3_layout_treeVisitAfter(root, nodeSize ? function(node) {
- node.x = (node.x - root.x) * size[0];
- node.y = (root.y - node.y) * size[1];
- } : function(node) {
- node.x = (node.x - x0) / (x1 - x0) * size[0];
- node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
- });
- return nodes;
- }
- cluster.separation = function(x) {
- if (!arguments.length) return separation;
- separation = x;
- return cluster;
- };
- cluster.size = function(x) {
- if (!arguments.length) return nodeSize ? null : size;
- nodeSize = (size = x) == null;
- return cluster;
- };
- cluster.nodeSize = function(x) {
- if (!arguments.length) return nodeSize ? size : null;
- nodeSize = (size = x) != null;
- return cluster;
- };
- return d3_layout_hierarchyRebind(cluster, hierarchy);
- };
- function d3_layout_clusterY(children) {
- return 1 + d3.max(children, function(child) {
- return child.y;
- });
- }
- function d3_layout_clusterX(children) {
- return children.reduce(function(x, child) {
- return x + child.x;
- }, 0) / children.length;
- }
- function d3_layout_clusterLeft(node) {
- var children = node.children;
- return children && children.length ? d3_layout_clusterLeft(children[0]) :
node;
- }
- function d3_layout_clusterRight(node) {
- var children = node.children, n;
- return children && (n = children.length) ? d3_layout_clusterRight(children[n
- 1]) : node;
- }
- d3.layout.treemap = function() {
- var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding =
null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode =
"squarify", ratio = .5 * (1 + Math.sqrt(5));
- function scale(children, k) {
- var i = -1, n = children.length, child, area;
- while (++i < n) {
- area = (child = children[i]).value * (k < 0 ? 0 : k);
- child.area = isNaN(area) || area <= 0 ? 0 : area;
- }
- }
- function squarify(node) {
- var children = node.children;
- if (children && children.length) {
- var rect = pad(node), row = [], remaining = children.slice(), child, best =
Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ?
rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx :
Math.min(rect.dx, rect.dy), n;
- scale(remaining, rect.dx * rect.dy / node.value);
- row.area = 0;
- while ((n = remaining.length) > 0) {
- row.push(child = remaining[n - 1]);
- row.area += child.area;
- if (mode !== "squarify" || (score = worst(row, u)) <= best) {
- remaining.pop();
- best = score;
- } else {
- row.area -= row.pop().area;
- position(row, u, rect, false);
- u = Math.min(rect.dx, rect.dy);
- row.length = row.area = 0;
- best = Infinity;
- }
- }
- if (row.length) {
- position(row, u, rect, true);
- row.length = row.area = 0;
- }
- children.forEach(squarify);
- }
- }
- function stickify(node) {
- var children = node.children;
- if (children && children.length) {
- var rect = pad(node), remaining = children.slice(), child, row = [];
- scale(remaining, rect.dx * rect.dy / node.value);
- row.area = 0;
- while (child = remaining.pop()) {
- row.push(child);
- row.area += child.area;
- if (child.z != null) {
- position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
- row.length = row.area = 0;
- }
- }
- children.forEach(stickify);
- }
- }
- function worst(row, u) {
- var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
- while (++i < n) {
- if (!(r = row[i].area)) continue;
- if (r < rmin) rmin = r;
- if (r > rmax) rmax = r;
- }
- s *= s;
- u *= u;
- return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
- }
- function position(row, u, rect, flush) {
- var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) :
0, o;
- if (u == rect.dx) {
- if (flush || v > rect.dy) v = rect.dy;
- while (++i < n) {
- o = row[i];
- o.x = x;
- o.y = y;
- o.dy = v;
- x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
- }
- o.z = true;
- o.dx += rect.x + rect.dx - x;
- rect.y += v;
- rect.dy -= v;
- } else {
- if (flush || v > rect.dx) v = rect.dx;
- while (++i < n) {
- o = row[i];
- o.x = x;
- o.y = y;
- o.dx = v;
- y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
- }
- o.z = false;
- o.dy += rect.y + rect.dy - y;
- rect.x += v;
- rect.dx -= v;
- }
- }
- function treemap(d) {
- var nodes = stickies || hierarchy(d), root = nodes[0];
- root.x = 0;
- root.y = 0;
- root.dx = size[0];
- root.dy = size[1];
- if (stickies) hierarchy.revalue(root);
- scale([ root ], root.dx * root.dy / root.value);
- (stickies ? stickify : squarify)(root);
- if (sticky) stickies = nodes;
- return nodes;
- }
- treemap.size = function(x) {
- if (!arguments.length) return size;
- size = x;
- return treemap;
- };
- treemap.padding = function(x) {
- if (!arguments.length) return padding;
- function padFunction(node) {
- var p = x.call(treemap, node, node.depth);
- return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node,
typeof p === "number" ? [ p, p, p, p ] : p);
- }
- function padConstant(node) {
- return d3_layout_treemapPad(node, x);
- }
- var type;
- pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) ===
"function" ? padFunction : type === "number" ? (x = [ x, x, x, x ],
- padConstant) : padConstant;
- return treemap;
- };
- treemap.round = function(x) {
- if (!arguments.length) return round != Number;
- round = x ? Math.round : Number;
- return treemap;
- };
- treemap.sticky = function(x) {
- if (!arguments.length) return sticky;
- sticky = x;
- stickies = null;
- return treemap;
- };
- treemap.ratio = function(x) {
- if (!arguments.length) return ratio;
- ratio = x;
- return treemap;
- };
- treemap.mode = function(x) {
- if (!arguments.length) return mode;
- mode = x + "";
- return treemap;
- };
- return d3_layout_hierarchyRebind(treemap, hierarchy);
- };
- function d3_layout_treemapPadNull(node) {
- return {
- x: node.x,
- y: node.y,
- dx: node.dx,
- dy: node.dy
- };
- }
- function d3_layout_treemapPad(node, padding) {
- var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] -
padding[3], dy = node.dy - padding[0] - padding[2];
- if (dx < 0) {
- x += dx / 2;
- dx = 0;
- }
- if (dy < 0) {
- y += dy / 2;
- dy = 0;
- }
- return {
- x: x,
- y: y,
- dx: dx,
- dy: dy
- };
- }
- d3.random = {
- normal: function(µ, Ï) {
- var n = arguments.length;
- if (n < 2) Ï = 1;
- if (n < 1) µ = 0;
- return function() {
- var x, y, r;
- do {
- x = Math.random() * 2 - 1;
- y = Math.random() * 2 - 1;
- r = x * x + y * y;
- } while (!r || r > 1);
- return µ + Ï * x * Math.sqrt(-2 * Math.log(r) / r);
- };
- },
- logNormal: function() {
- var random = d3.random.normal.apply(d3, arguments);
- return function() {
- return Math.exp(random());
- };
- },
- irwinHall: function(m) {
- return function() {
- for (var s = 0, j = 0; j < m; j++) s += Math.random();
- return s / m;
- };
- }
- };
- d3.scale = {};
- function d3_scaleExtent(domain) {
- var start = domain[0], stop = domain[domain.length - 1];
- return start < stop ? [ start, stop ] : [ stop, start ];
- }
- function d3_scaleRange(scale) {
- return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
- }
- function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
- var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
- return function(x) {
- return i(u(x));
- };
- }
- function d3_scale_nice(domain, nice) {
- var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
- if (x1 < x0) {
- dx = i0, i0 = i1, i1 = dx;
- dx = x0, x0 = x1, x1 = dx;
- }
- domain[i0] = nice.floor(x0);
- domain[i1] = nice.ceil(x1);
- return domain;
- }
- function d3_scale_niceStep(step) {
- return step ? {
- floor: function(x) {
- return Math.floor(x / step) * step;
- },
- ceil: function(x) {
- return Math.ceil(x / step) * step;
- }
- } : d3_scale_niceIdentity;
- }
- var d3_scale_niceIdentity = {
- floor: d3_identity,
- ceil: d3_identity
- };
- function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
- var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
- if (domain[k] < domain[0]) {
- domain = domain.slice().reverse();
- range = range.slice().reverse();
- }
- while (++j <= k) {
- u.push(uninterpolate(domain[j - 1], domain[j]));
- i.push(interpolate(range[j - 1], range[j]));
- }
- return function(x) {
- var j = d3.bisect(domain, x, 1, k) - 1;
- return i[j](u[j](x));
- };
- }
- d3.scale.linear = function() {
- return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false);
- };
- function d3_scale_linear(domain, range, interpolate, clamp) {
- var output, input;
- function rescale() {
- var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear :
d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp :
d3_uninterpolateNumber;
- output = linear(domain, range, uninterpolate, interpolate);
- input = linear(range, domain, uninterpolate, d3_interpolate);
- return scale;
- }
- function scale(x) {
- return output(x);
- }
- scale.invert = function(y) {
- return input(y);
- };
- scale.domain = function(x) {
- if (!arguments.length) return domain;
- domain = x.map(Number);
- return rescale();
- };
- scale.range = function(x) {
- if (!arguments.length) return range;
- range = x;
- return rescale();
- };
- scale.rangeRound = function(x) {
- return scale.range(x).interpolate(d3_interpolateRound);
- };
- scale.clamp = function(x) {
- if (!arguments.length) return clamp;
- clamp = x;
- return rescale();
- };
- scale.interpolate = function(x) {
- if (!arguments.length) return interpolate;
- interpolate = x;
- return rescale();
- };
- scale.ticks = function(m) {
- return d3_scale_linearTicks(domain, m);
- };
- scale.tickFormat = function(m, format) {
- return d3_scale_linearTickFormat(domain, m, format);
- };
- scale.nice = function(m) {
- d3_scale_linearNice(domain, m);
- return rescale();
- };
- scale.copy = function() {
- return d3_scale_linear(domain, range, interpolate, clamp);
- };
- return rescale();
- }
- function d3_scale_linearRebind(scale, linear) {
- return d3.rebind(scale, linear, "range", "rangeRound",
"interpolate", "clamp");
- }
- function d3_scale_linearNice(domain, m) {
- return d3_scale_nice(domain, d3_scale_niceStep(m ? d3_scale_linearTickRange(domain,
m)[2] : d3_scale_linearNiceStep(domain)));
- }
- function d3_scale_linearNiceStep(domain) {
- var extent = d3_scaleExtent(domain), span = extent[1] - extent[0];
- return Math.pow(10, Math.round(Math.log(span) / Math.LN10) - 1);
- }
- function d3_scale_linearTickRange(domain, m) {
- var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step =
Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
- if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <=
.75) step *= 2;
- extent[0] = Math.ceil(extent[0] / step) * step;
- extent[1] = Math.floor(extent[1] / step) * step + step * .5;
- extent[2] = step;
- return extent;
- }
- function d3_scale_linearTicks(domain, m) {
- return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
- }
- function d3_scale_linearTickFormat(domain, m, format) {
- var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) /
Math.LN10 + .01);
- return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g,
h, i, j) {
- return [ b, c, d, e, f, g, h, i || "." + (precision - (j ===
"%") * 2), j ].join("");
- }) : ",." + precision + "f");
- }
- d3.scale.log = function() {
- return d3_scale_log(d3.scale.linear().domain([ 0, Math.LN10 ]), 10, d3_scale_logp,
d3_scale_powp, [ 1, 10 ]);
- };
- function d3_scale_log(linear, base, log, pow, domain) {
- function scale(x) {
- return linear(log(x));
- }
- scale.invert = function(x) {
- return pow(linear.invert(x));
- };
- scale.domain = function(x) {
- if (!arguments.length) return domain;
- if (x[0] < 0) log = d3_scale_logn, pow = d3_scale_pown; else log =
d3_scale_logp,
- pow = d3_scale_powp;
- linear.domain((domain = x.map(Number)).map(log));
- return scale;
- };
- scale.base = function(_) {
- if (!arguments.length) return base;
- base = +_;
- return scale;
- };
- scale.nice = function() {
- function floor(x) {
- return Math.pow(base, Math.floor(Math.log(x) / Math.log(base)));
- }
- function ceil(x) {
- return Math.pow(base, Math.ceil(Math.log(x) / Math.log(base)));
- }
- linear.domain(d3_scale_nice(domain, log === d3_scale_logp ? {
- floor: floor,
- ceil: ceil
- } : {
- floor: function(x) {
- return -ceil(-x);
- },
- ceil: function(x) {
- return -floor(-x);
- }
- }).map(log));
- return scale;
- };
- scale.ticks = function() {
- var extent = d3_scaleExtent(linear.domain()), ticks = [];
- if (extent.every(isFinite)) {
- var b = Math.log(base), i = Math.floor(extent[0] / b), j = Math.ceil(extent[1] /
b), u = pow(extent[0]), v = pow(extent[1]), n = base % 1 ? 2 : base;
- if (log === d3_scale_logn) {
- ticks.push(-Math.pow(base, -i));
- for (;i++ < j; ) for (var k = n - 1; k > 0; k--)
ticks.push(-Math.pow(base, -i) * k);
- } else {
- for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(Math.pow(base,
i) * k);
- ticks.push(Math.pow(base, i));
- }
- for (i = 0; ticks[i] < u; i++) {}
- for (j = ticks.length; ticks[j - 1] > v; j--) {}
- ticks = ticks.slice(i, j);
- }
- return ticks;
- };
- scale.tickFormat = function(n, format) {
- if (!arguments.length) return d3_scale_logFormat;
- if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format
!== "function") format = d3.format(format);
- var b = Math.log(base), k = Math.max(.1, n / scale.ticks().length), f = log ===
d3_scale_logn ? (e = -1e-12,
- Math.floor) : (e = 1e-12, Math.ceil), e;
- return function(d) {
- return d / pow(b * f(log(d) / b + e)) <= k ? format(d) : "";
- };
- };
- scale.copy = function() {
- return d3_scale_log(linear.copy(), base, log, pow, domain);
- };
- return d3_scale_linearRebind(scale, linear);
- }
- var d3_scale_logFormat = d3.format(".0e");
- function d3_scale_logp(x) {
- return Math.log(x < 0 ? 0 : x);
- }
- function d3_scale_powp(x) {
- return Math.exp(x);
- }
- function d3_scale_logn(x) {
- return -Math.log(x > 0 ? 0 : -x);
- }
- function d3_scale_pown(x) {
- return -Math.exp(-x);
- }
- d3.scale.pow = function() {
- return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]);
- };
- function d3_scale_pow(linear, exponent, domain) {
- var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
- function scale(x) {
- return linear(powp(x));
- }
- scale.invert = function(x) {
- return powb(linear.invert(x));
- };
- scale.domain = function(x) {
- if (!arguments.length) return domain;
- linear.domain((domain = x.map(Number)).map(powp));
- return scale;
- };
- scale.ticks = function(m) {
- return d3_scale_linearTicks(domain, m);
- };
- scale.tickFormat = function(m, format) {
- return d3_scale_linearTickFormat(domain, m, format);
- };
- scale.nice = function(m) {
- return scale.domain(d3_scale_linearNice(domain, m));
- };
- scale.exponent = function(x) {
- if (!arguments.length) return exponent;
- powp = d3_scale_powPow(exponent = x);
- powb = d3_scale_powPow(1 / exponent);
- linear.domain(domain.map(powp));
- return scale;
- };
- scale.copy = function() {
- return d3_scale_pow(linear.copy(), exponent, domain);
- };
- return d3_scale_linearRebind(scale, linear);
- }
- function d3_scale_powPow(e) {
- return function(x) {
- return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
- };
- }
- d3.scale.sqrt = function() {
- return d3.scale.pow().exponent(.5);
- };
- d3.scale.ordinal = function() {
- return d3_scale_ordinal([], {
- t: "range",
- a: [ [] ]
- });
- };
- function d3_scale_ordinal(domain, ranger) {
- var index, range, rangeBand;
- function scale(x) {
- return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length];
- }
- function steps(start, step) {
- return d3.range(domain.length).map(function(i) {
- return start + step * i;
- });
- }
- scale.domain = function(x) {
- if (!arguments.length) return domain;
- domain = [];
- index = new d3_Map();
- var i = -1, n = x.length, xi;
- while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
- return scale[ranger.t].apply(scale, ranger.a);
- };
- scale.range = function(x) {
- if (!arguments.length) return range;
- range = x;
- rangeBand = 0;
- ranger = {
- t: "range",
- a: arguments
- };
- return scale;
- };
- scale.rangePoints = function(x, padding) {
- if (arguments.length < 2) padding = 0;
- var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length -
1) + padding);
- range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding /
2, step);
- rangeBand = 0;
- ranger = {
- t: "rangePoints",
- a: arguments
- };
- return scale;
- };
- scale.rangeBands = function(x, padding, outerPadding) {
- if (arguments.length < 2) padding = 0;
- if (arguments.length < 3) outerPadding = padding;
- var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step =
(stop - start) / (domain.length - padding + 2 * outerPadding);
- range = steps(start + step * outerPadding, step);
- if (reverse) range.reverse();
- rangeBand = step * (1 - padding);
- ranger = {
- t: "rangeBands",
- a: arguments
- };
- return scale;
- };
- scale.rangeRoundBands = function(x, padding, outerPadding) {
- if (arguments.length < 2) padding = 0;
- if (arguments.length < 3) outerPadding = padding;
- var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step =
Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop -
start - (domain.length - padding) * step;
- range = steps(start + Math.round(error / 2), step);
- if (reverse) range.reverse();
- rangeBand = Math.round(step * (1 - padding));
- ranger = {
- t: "rangeRoundBands",
- a: arguments
- };
- return scale;
- };
- scale.rangeBand = function() {
- return rangeBand;
- };
- scale.rangeExtent = function() {
- return d3_scaleExtent(ranger.a[0]);
- };
- scale.copy = function() {
- return d3_scale_ordinal(domain, ranger);
- };
- return scale.domain(domain);
- }
- d3.scale.category10 = function() {
- return d3.scale.ordinal().range(d3_category10);
- };
- d3.scale.category20 = function() {
- return d3.scale.ordinal().range(d3_category20);
- };
- d3.scale.category20b = function() {
- return d3.scale.ordinal().range(d3_category20b);
- };
- d3.scale.category20c = function() {
- return d3.scale.ordinal().range(d3_category20c);
- };
- var d3_category10 = [ "#1f77b4", "#ff7f0e", "#2ca02c",
"#d62728", "#9467bd", "#8c564b", "#e377c2",
"#7f7f7f", "#bcbd22", "#17becf" ];
- var d3_category20 = [ "#1f77b4", "#aec7e8", "#ff7f0e",
"#ffbb78", "#2ca02c", "#98df8a", "#d62728",
"#ff9896", "#9467bd", "#c5b0d5", "#8c564b",
"#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f",
"#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf",
"#9edae5" ];
- var d3_category20b = [ "#393b79", "#5254a3", "#6b6ecf",
"#9c9ede", "#637939", "#8ca252", "#b5cf6b",
"#cedb9c", "#8c6d31", "#bd9e39", "#e7ba52",
"#e7cb94", "#843c39", "#ad494a", "#d6616b",
"#e7969c", "#7b4173", "#a55194", "#ce6dbd",
"#de9ed6" ];
- var d3_category20c = [ "#3182bd", "#6baed6", "#9ecae1",
"#c6dbef", "#e6550d", "#fd8d3c", "#fdae6b",
"#fdd0a2", "#31a354", "#74c476", "#a1d99b",
"#c7e9c0", "#756bb1", "#9e9ac8", "#bcbddc",
"#dadaeb", "#636363", "#969696", "#bdbdbd",
"#d9d9d9" ];
- d3.scale.quantile = function() {
- return d3_scale_quantile([], []);
- };
- function d3_scale_quantile(domain, range) {
- var thresholds;
- function rescale() {
- var k = 0, q = range.length;
- thresholds = [];
- while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
- return scale;
- }
- function scale(x) {
- if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)];
- }
- scale.domain = function(x) {
- if (!arguments.length) return domain;
- domain = x.filter(function(d) {
- return !isNaN(d);
- }).sort(d3.ascending);
- return rescale();
- };
- scale.range = function(x) {
- if (!arguments.length) return range;
- range = x;
- return rescale();
- };
- scale.quantiles = function() {
- return thresholds;
- };
- scale.copy = function() {
- return d3_scale_quantile(domain, range);
- };
- return rescale();
- }
- d3.scale.quantize = function() {
- return d3_scale_quantize(0, 1, [ 0, 1 ]);
- };
- function d3_scale_quantize(x0, x1, range) {
- var kx, i;
- function scale(x) {
- return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
- }
- function rescale() {
- kx = range.length / (x1 - x0);
- i = range.length - 1;
- return scale;
- }
- scale.domain = function(x) {
- if (!arguments.length) return [ x0, x1 ];
- x0 = +x[0];
- x1 = +x[x.length - 1];
- return rescale();
- };
- scale.range = function(x) {
- if (!arguments.length) return range;
- range = x;
- return rescale();
- };
- scale.copy = function() {
- return d3_scale_quantize(x0, x1, range);
- };
- scale.invertExtent = function(y) {
- y = range.indexOf(y);
- y = y < 0 ? NaN : y / kx + x0;
- return [ y, y + 1 / kx ];
- };
- return rescale();
- }
- d3.scale.threshold = function() {
- return d3_scale_threshold([ .5 ], [ 0, 1 ]);
- };
- function d3_scale_threshold(domain, range) {
- function scale(x) {
- if (x <= x) return range[d3.bisect(domain, x)];
- }
- scale.domain = function(_) {
- if (!arguments.length) return domain;
- domain = _;
- return scale;
- };
- scale.range = function(_) {
- if (!arguments.length) return range;
- range = _;
- return scale;
- };
- scale.invertExtent = function(y) {
- y = range.indexOf(y);
- return [ domain[y - 1], domain[y] ];
- };
- scale.copy = function() {
- return d3_scale_threshold(domain, range);
- };
- return scale;
- }
- d3.scale.identity = function() {
- return d3_scale_identity([ 0, 1 ]);
- };
- function d3_scale_identity(domain) {
- function identity(x) {
- return +x;
- }
- identity.invert = identity;
- identity.domain = identity.range = function(x) {
- if (!arguments.length) return domain;
- domain = x.map(identity);
- return identity;
- };
- identity.ticks = function(m) {
- return d3_scale_linearTicks(domain, m);
- };
- identity.tickFormat = function(m, format) {
- return d3_scale_linearTickFormat(domain, m, format);
- };
- identity.copy = function() {
- return d3_scale_identity(domain);
- };
- return identity;
- }
- d3.svg.arc = function() {
- var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius,
startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
- function arc() {
- var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this,
arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 =
endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0,
- a0 = a1, a1 = da), a1 - a0), df = da < Ï ? "0" : "1", c0 =
Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1);
- return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 +
"," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1
+ " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," +
r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0
0," + r0 + "Z" : "M0," + r1 + "A" + r1 + ","
+ r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0
1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0
+ "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 *
c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 +
"A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0
+ "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 *
s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1
* c1 + "," + r1 * s1 + "L0,0" + "Z";
- }
- arc.innerRadius = function(v) {
- if (!arguments.length) return innerRadius;
- innerRadius = d3_functor(v);
- return arc;
- };
- arc.outerRadius = function(v) {
- if (!arguments.length) return outerRadius;
- outerRadius = d3_functor(v);
- return arc;
- };
- arc.startAngle = function(v) {
- if (!arguments.length) return startAngle;
- startAngle = d3_functor(v);
- return arc;
- };
- arc.endAngle = function(v) {
- if (!arguments.length) return endAngle;
- endAngle = d3_functor(v);
- return arc;
- };
- arc.centroid = function() {
- var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) /
2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 +
d3_svg_arcOffset;
- return [ Math.cos(a) * r, Math.sin(a) * r ];
- };
- return arc;
- };
- var d3_svg_arcOffset = -Ï / 2, d3_svg_arcMax = 2 * Ï - 1e-6;
- function d3_svg_arcInnerRadius(d) {
- return d.innerRadius;
- }
- function d3_svg_arcOuterRadius(d) {
- return d.outerRadius;
- }
- function d3_svg_arcStartAngle(d) {
- return d.startAngle;
- }
- function d3_svg_arcEndAngle(d) {
- return d.endAngle;
- }
- d3.svg.line.radial = function() {
- var line = d3_svg_line(d3_svg_lineRadial);
- line.radius = line.x, delete line.x;
- line.angle = line.y, delete line.y;
- return line;
- };
- function d3_svg_lineRadial(points) {
- var point, i = -1, n = points.length, r, a;
- while (++i < n) {
- point = points[i];
- r = point[0];
- a = point[1] + d3_svg_arcOffset;
- point[0] = r * Math.cos(a);
- point[1] = r * Math.sin(a);
- }
- return points;
- }
- function d3_svg_area(projection) {
- var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined =
d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key,
interpolateReverse = interpolate, L = "L", tension = .7;
- function area(data) {
- var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 =
d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
- return x;
- } : d3_functor(x1), fy1 = y0 === y1 ? function() {
- return y;
- } : d3_functor(y1), x, y;
- function segment() {
- segments.push("M", interpolate(projection(points1), tension), L,
interpolateReverse(projection(points0.reverse()), tension), "Z");
- }
- while (++i < n) {
- if (defined.call(this, d = data[i], i)) {
- points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);
- points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);
- } else if (points0.length) {
- segment();
- points0 = [];
- points1 = [];
- }
- }
- if (points0.length) segment();
- return segments.length ? segments.join("") : null;
- }
- area.x = function(_) {
- if (!arguments.length) return x1;
- x0 = x1 = _;
- return area;
- };
- area.x0 = function(_) {
- if (!arguments.length) return x0;
- x0 = _;
- return area;
- };
- area.x1 = function(_) {
- if (!arguments.length) return x1;
- x1 = _;
- return area;
- };
- area.y = function(_) {
- if (!arguments.length) return y1;
- y0 = y1 = _;
- return area;
- };
- area.y0 = function(_) {
- if (!arguments.length) return y0;
- y0 = _;
- return area;
- };
- area.y1 = function(_) {
- if (!arguments.length) return y1;
- y1 = _;
- return area;
- };
- area.defined = function(_) {
- if (!arguments.length) return defined;
- defined = _;
- return area;
- };
- area.interpolate = function(_) {
- if (!arguments.length) return interpolateKey;
- if (typeof _ === "function") interpolateKey = interpolate = _; else
interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) ||
d3_svg_lineLinear).key;
- interpolateReverse = interpolate.reverse || interpolate;
- L = interpolate.closed ? "M" : "L";
- return area;
- };
- area.tension = function(_) {
- if (!arguments.length) return tension;
- tension = _;
- return area;
- };
- return area;
- }
- d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
- d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
- d3.svg.area = function() {
- return d3_svg_area(d3_identity);
- };
- d3.svg.area.radial = function() {
- var area = d3_svg_area(d3_svg_lineRadial);
- area.radius = area.x, delete area.x;
- area.innerRadius = area.x0, delete area.x0;
- area.outerRadius = area.x1, delete area.x1;
- area.angle = area.y, delete area.y;
- area.startAngle = area.y0, delete area.y0;
- area.endAngle = area.y1, delete area.y1;
- return area;
- };
- d3.svg.chord = function() {
- var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle =
d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
- function chord(d, i) {
- var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);
- return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ?
curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) +
curve(t.r, t.p1, s.r, s.p0)) + "Z";
- }
- function subgroup(self, f, d, i) {
- var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 =
startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup,
i) + d3_svg_arcOffset;
- return {
- r: r,
- a0: a0,
- a1: a1,
- p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
- p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
- };
- }
- function equals(a, b) {
- return a.a0 == b.a0 && a.a1 == b.a1;
- }
- function arc(r, p, a) {
- return "A" + r + "," + r + " 0 " + +(a > Ï) +
",1 " + p;
- }
- function curve(r0, p0, r1, p1) {
- return "Q 0,0 " + p1;
- }
- chord.radius = function(v) {
- if (!arguments.length) return radius;
- radius = d3_functor(v);
- return chord;
- };
- chord.source = function(v) {
- if (!arguments.length) return source;
- source = d3_functor(v);
- return chord;
- };
- chord.target = function(v) {
- if (!arguments.length) return target;
- target = d3_functor(v);
- return chord;
- };
- chord.startAngle = function(v) {
- if (!arguments.length) return startAngle;
- startAngle = d3_functor(v);
- return chord;
- };
- chord.endAngle = function(v) {
- if (!arguments.length) return endAngle;
- endAngle = d3_functor(v);
- return chord;
- };
- return chord;
- };
- function d3_svg_chordRadius(d) {
- return d.radius;
- }
- d3.svg.diagonal = function() {
- var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;
- function diagonal(d, i) {
- var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) /
2, p = [ p0, {
- x: p0.x,
- y: m
- }, {
- x: p3.x,
- y: m
- }, p3 ];
- p = p.map(projection);
- return "M" + p[0] + "C" + p[1] + " " + p[2] + "
" + p[3];
- }
- diagonal.source = function(x) {
- if (!arguments.length) return source;
- source = d3_functor(x);
- return diagonal;
- };
- diagonal.target = function(x) {
- if (!arguments.length) return target;
- target = d3_functor(x);
- return diagonal;
- };
- diagonal.projection = function(x) {
- if (!arguments.length) return projection;
- projection = x;
- return diagonal;
- };
- return diagonal;
- };
- function d3_svg_diagonalProjection(d) {
- return [ d.x, d.y ];
- }
- d3.svg.diagonal.radial = function() {
- var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_
= diagonal.projection;
- diagonal.projection = function(x) {
- return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection =
x)) : projection;
- };
- return diagonal;
- };
- function d3_svg_diagonalRadialProjection(projection) {
- return function() {
- var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset;
- return [ r * Math.cos(a), r * Math.sin(a) ];
- };
- }
- d3.svg.symbol = function() {
- var type = d3_svg_symbolType, size = d3_svg_symbolSize;
- function symbol(d, i) {
- return (d3_svg_symbols.get(type.call(this, d, i)) ||
d3_svg_symbolCircle)(size.call(this, d, i));
- }
- symbol.type = function(x) {
- if (!arguments.length) return type;
- type = d3_functor(x);
- return symbol;
- };
- symbol.size = function(x) {
- if (!arguments.length) return size;
- size = d3_functor(x);
- return symbol;
- };
- return symbol;
- };
- function d3_svg_symbolSize() {
- return 64;
- }
- function d3_svg_symbolType() {
- return "circle";
- }
- function d3_svg_symbolCircle(size) {
- var r = Math.sqrt(size / Ï);
- return "M0," + r + "A" + r + "," + r + " 0 1,1
0," + -r + "A" + r + "," + r + " 0 1,1 0," + r +
"Z";
- }
- var d3_svg_symbols = d3.map({
- circle: d3_svg_symbolCircle,
- cross: function(size) {
- var r = Math.sqrt(size / 5) / 2;
- return "M" + -3 * r + "," + -r + "H" + -r +
"V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r +
"V" + r + "H" + r + "V" + 3 * r + "H" + -r +
"V" + r + "H" + -3 * r + "Z";
- },
- diamond: function(size) {
- var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;
- return "M0," + -ry + "L" + rx + ",0" + "
0," + ry + " " + -rx + ",0" + "Z";
- },
- square: function(size) {
- var r = Math.sqrt(size) / 2;
- return "M" + -r + "," + -r + "L" + r + ","
+ -r + " " + r + "," + r + " " + -r + "," + r +
"Z";
- },
- "triangle-down": function(size) {
- var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
- return "M0," + ry + "L" + rx + "," + -ry + "
" + -rx + "," + -ry + "Z";
- },
- "triangle-up": function(size) {
- var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
- return "M0," + -ry + "L" + rx + "," + ry + "
" + -rx + "," + ry + "Z";
- }
- });
- d3.svg.symbolTypes = d3_svg_symbols.keys();
- var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);
- function d3_transition(groups, id) {
- d3_arraySubclass(groups, d3_transitionPrototype);
- groups.id = id;
- return groups;
- }
- var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId,
d3_transitionInherit = {
- ease: d3_ease_cubicInOut,
- delay: 0,
- duration: 250
- };
- d3_transitionPrototype.call = d3_selectionPrototype.call;
- d3_transitionPrototype.empty = d3_selectionPrototype.empty;
- d3_transitionPrototype.node = d3_selectionPrototype.node;
- d3_transitionPrototype.size = d3_selectionPrototype.size;
- d3.transition = function(selection) {
- return arguments.length ? d3_transitionInheritId ? selection.transition() : selection
: d3_selectionRoot.transition();
- };
- d3.transition.prototype = d3_transitionPrototype;
- d3_transitionPrototype.select = function(selector) {
- var id = this.id, subgroups = [], subgroup, subnode, node;
- if (typeof selector !== "function") selector =
d3_selection_selector(selector);
- for (var j = -1, m = this.length; ++j < m; ) {
- subgroups.push(subgroup = []);
- for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
- if ((node = group[i]) && (subnode = selector.call(node, node.__data__,
i))) {
- if ("__data__" in node) subnode.__data__ = node.__data__;
- d3_transitionNode(subnode, i, id, node.__transition__[id]);
- subgroup.push(subnode);
- } else {
- subgroup.push(null);
- }
- }
- }
- return d3_transition(subgroups, id);
- };
- d3_transitionPrototype.selectAll = function(selector) {
- var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition;
- if (typeof selector !== "function") selector =
d3_selection_selectorAll(selector);
- for (var j = -1, m = this.length; ++j < m; ) {
- for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
- if (node = group[i]) {
- transition = node.__transition__[id];
- subnodes = selector.call(node, node.__data__, i);
- subgroups.push(subgroup = []);
- for (var k = -1, o = subnodes.length; ++k < o; ) {
- if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition);
- subgroup.push(subnode);
- }
- }
- }
- }
- return d3_transition(subgroups, id);
- };
- d3_transitionPrototype.filter = function(filter) {
- var subgroups = [], subgroup, group, node;
- if (typeof filter !== "function") filter = d3_selection_filter(filter);
- for (var j = 0, m = this.length; j < m; j++) {
- subgroups.push(subgroup = []);
- for (var group = this[j], i = 0, n = group.length; i < n; i++) {
- if ((node = group[i]) && filter.call(node, node.__data__, i)) {
- subgroup.push(node);
- }
- }
- }
- return d3_transition(subgroups, this.id, this.time).ease(this.ease());
- };
- d3_transitionPrototype.tween = function(name, tween) {
- var id = this.id;
- if (arguments.length < 2) return this.node().__transition__[id].tween.get(name);
- return d3_selection_each(this, tween == null ? function(node) {
- node.__transition__[id].tween.remove(name);
- } : function(node) {
- node.__transition__[id].tween.set(name, tween);
- });
- };
- function d3_transition_tween(groups, name, value, tween) {
- var id = groups.id;
- return d3_selection_each(groups, typeof value === "function" ?
function(node, i, j) {
- node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i,
j)));
- } : (value = tween(value), function(node) {
- node.__transition__[id].tween.set(name, value);
- }));
- }
- d3_transitionPrototype.attr = function(nameNS, value) {
- if (arguments.length < 2) {
- for (value in nameNS) this.attr(value, nameNS[value]);
- return this;
- }
- var interpolate = d3_interpolateByName(nameNS), name = d3.ns.qualify(nameNS);
- function attrNull() {
- this.removeAttribute(name);
- }
- function attrNullNS() {
- this.removeAttributeNS(name.space, name.local);
- }
- function attrTween(b) {
- return b == null ? attrNull : (b += "", function() {
- var a = this.getAttribute(name), i;
- return a !== b && (i = interpolate(a, b), function(t) {
- this.setAttribute(name, i(t));
- });
- });
- }
- function attrTweenNS(b) {
- return b == null ? attrNullNS : (b += "", function() {
- var a = this.getAttributeNS(name.space, name.local), i;
- return a !== b && (i = interpolate(a, b), function(t) {
- this.setAttributeNS(name.space, name.local, i(t));
- });
- });
- }
- return d3_transition_tween(this, "attr." + nameNS, value, name.local ?
attrTweenNS : attrTween);
- };
- d3_transitionPrototype.attrTween = function(nameNS, tween) {
- var name = d3.ns.qualify(nameNS);
- function attrTween(d, i) {
- var f = tween.call(this, d, i, this.getAttribute(name));
- return f && function(t) {
- this.setAttribute(name, f(t));
- };
- }
- function attrTweenNS(d, i) {
- var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
- return f && function(t) {
- this.setAttributeNS(name.space, name.local, f(t));
- };
- }
- return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
- };
- d3_transitionPrototype.style = function(name, value, priority) {
- var n = arguments.length;
- if (n < 3) {
- if (typeof name !== "string") {
- if (n < 2) value = "";
- for (priority in name) this.style(priority, name[priority], value);
- return this;
- }
- priority = "";
- }
- var interpolate = d3_interpolateByName(name);
- function styleNull() {
- this.style.removeProperty(name);
- }
- function styleString(b) {
- return b == null ? styleNull : (b += "", function() {
- var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i;
- return a !== b && (i = interpolate(a, b), function(t) {
- this.style.setProperty(name, i(t), priority);
- });
- });
- }
- return d3_transition_tween(this, "style." + name, value, styleString);
- };
- d3_transitionPrototype.styleTween = function(name, tween, priority) {
- if (arguments.length < 3) priority = "";
- function styleTween(d, i) {
- var f = tween.call(this, d, i, d3_window.getComputedStyle(this,
null).getPropertyValue(name));
- return f && function(t) {
- this.style.setProperty(name, f(t), priority);
- };
- }
- return this.tween("style." + name, styleTween);
- };
- d3_transitionPrototype.text = function(value) {
- return d3_transition_tween(this, "text", value, d3_transition_text);
- };
- function d3_transition_text(b) {
- if (b == null) b = "";
- return function() {
- this.textContent = b;
- };
- }
- d3_transitionPrototype.remove = function() {
- return this.each("end.transition", function() {
- var p;
- if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this);
- });
- };
- d3_transitionPrototype.ease = function(value) {
- var id = this.id;
- if (arguments.length < 1) return this.node().__transition__[id].ease;
- if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
- return d3_selection_each(this, function(node) {
- node.__transition__[id].ease = value;
- });
- };
- d3_transitionPrototype.delay = function(value) {
- var id = this.id;
- return d3_selection_each(this, typeof value === "function" ? function(node,
i, j) {
- node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0;
- } : (value |= 0, function(node) {
- node.__transition__[id].delay = value;
- }));
- };
- d3_transitionPrototype.duration = function(value) {
- var id = this.id;
- return d3_selection_each(this, typeof value === "function" ? function(node,
i, j) {
- node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i,
j) | 0);
- } : (value = Math.max(1, value | 0), function(node) {
- node.__transition__[id].duration = value;
- }));
- };
- d3_transitionPrototype.each = function(type, listener) {
- var id = this.id;
- if (arguments.length < 2) {
- var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
- d3_transitionInheritId = id;
- d3_selection_each(this, function(node, i, j) {
- d3_transitionInherit = node.__transition__[id];
- type.call(node, node.__data__, i, j);
- });
- d3_transitionInherit = inherit;
- d3_transitionInheritId = inheritId;
- } else {
- d3_selection_each(this, function(node) {
- node.__transition__[id].event.on(type, listener);
- });
- }
- return this;
- };
- d3_transitionPrototype.transition = function() {
- var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node,
transition;
- for (var j = 0, m = this.length; j < m; j++) {
- subgroups.push(subgroup = []);
- for (var group = this[j], i = 0, n = group.length; i < n; i++) {
- if (node = group[i]) {
- transition = Object.create(node.__transition__[id0]);
- transition.delay += transition.duration;
- d3_transitionNode(node, i, id1, transition);
- }
- subgroup.push(node);
- }
- }
- return d3_transition(subgroups, id1);
- };
- function d3_transitionNode(node, i, id, inherit) {
- var lock = node.__transition__ || (node.__transition__ = {
- active: 0,
- count: 0
- }), transition = lock[id];
- if (!transition) {
- var time = inherit.time;
- transition = lock[id] = {
- tween: new d3_Map(),
- event: d3.dispatch("start", "end"),
- time: time,
- ease: inherit.ease,
- delay: inherit.delay,
- duration: inherit.duration
- };
- ++lock.count;
- d3.timer(function(elapsed) {
- var d = node.__data__, ease = transition.ease, event = transition.event, delay =
transition.delay, duration = transition.duration, tweened = [];
- return delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time), 1;
- function start(elapsed) {
- if (lock.active > id) return stop();
- lock.active = id;
- event.start.call(node, d, i);
- transition.tween.forEach(function(key, value) {
- if (value = value.call(node, d, i)) {
- tweened.push(value);
- }
- });
- if (!tick(elapsed)) d3.timer(tick, 0, time);
- return 1;
- }
- function tick(elapsed) {
- if (lock.active !== id) return stop();
- var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length;
- while (n > 0) {
- tweened[--n].call(node, e);
- }
- if (t >= 1) {
- stop();
- event.end.call(node, d, i);
- return 1;
- }
- }
- function stop() {
- if (--lock.count) delete lock[id]; else delete node.__transition__;
- return 1;
- }
- }, 0, time);
- return transition;
- }
- }
- d3.svg.axis = function() {
- var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, tickMajorSize = 6,
tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues =
null, tickFormat_, tickSubdivide = 0;
- function axis(g) {
- g.each(function() {
- var g = d3.select(this);
- var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale,
tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ?
scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_;
- var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick =
g.selectAll(".tick.minor").data(subticks, String), subtickEnter =
subtick.enter().insert("line", ".tick").attr("class",
"tick minor").style("opacity", 1e-6), subtickExit =
d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate =
d3.transition(subtick).style("opacity", 1);
- var tick = g.selectAll(".tick.major").data(ticks, String), tickEnter =
tick.enter().insert("g", ".domain").attr("class", "tick
major").style("opacity", 1e-6), tickExit =
d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate =
d3.transition(tick).style("opacity", 1), tickTransform;
- var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([
0 ]), pathUpdate = (path.enter().append("path").attr("class",
"domain"),
- d3.transition(path));
- var scale1 = scale.copy(), scale0 = this.__chart__ || scale1;
- this.__chart__ = scale1;
- tickEnter.append("line");
- tickEnter.append("text");
- var lineEnter = tickEnter.select("line"), lineUpdate =
tickUpdate.select("line"), text =
tick.select("text").text(tickFormat), textEnter =
tickEnter.select("text"), textUpdate = tickUpdate.select("text");
- switch (orient) {
- case "bottom":
- {
- tickTransform = d3_svg_axisX;
- subtickEnter.attr("y2", tickMinorSize);
- subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize);
- lineEnter.attr("y2", tickMajorSize);
- textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding);
- lineUpdate.attr("x2", 0).attr("y2", tickMajorSize);
- textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize,
0) + tickPadding);
- text.attr("dy", ".71em").style("text-anchor",
"middle");
- pathUpdate.attr("d", "M" + range[0] + "," +
tickEndSize + "V0H" + range[1] + "V" + tickEndSize);
- break;
- }
-
- case "top":
- {
- tickTransform = d3_svg_axisX;
- subtickEnter.attr("y2", -tickMinorSize);
- subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize);
- lineEnter.attr("y2", -tickMajorSize);
- textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding));
- lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize);
- textUpdate.attr("x", 0).attr("y",
-(Math.max(tickMajorSize, 0) + tickPadding));
- text.attr("dy", "0em").style("text-anchor",
"middle");
- pathUpdate.attr("d", "M" + range[0] + "," +
-tickEndSize + "V0H" + range[1] + "V" + -tickEndSize);
- break;
- }
-
- case "left":
- {
- tickTransform = d3_svg_axisY;
- subtickEnter.attr("x2", -tickMinorSize);
- subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0);
- lineEnter.attr("x2", -tickMajorSize);
- textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding));
- lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0);
- textUpdate.attr("x", -(Math.max(tickMajorSize, 0) +
tickPadding)).attr("y", 0);
- text.attr("dy", ".32em").style("text-anchor",
"end");
- pathUpdate.attr("d", "M" + -tickEndSize + "," +
range[0] + "H0V" + range[1] + "H" + -tickEndSize);
- break;
- }
-
- case "right":
- {
- tickTransform = d3_svg_axisY;
- subtickEnter.attr("x2", tickMinorSize);
- subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0);
- lineEnter.attr("x2", tickMajorSize);
- textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding);
- lineUpdate.attr("x2", tickMajorSize).attr("y2", 0);
- textUpdate.attr("x", Math.max(tickMajorSize, 0) +
tickPadding).attr("y", 0);
- text.attr("dy", ".32em").style("text-anchor",
"start");
- pathUpdate.attr("d", "M" + tickEndSize + "," +
range[0] + "H0V" + range[1] + "H" + tickEndSize);
- break;
- }
- }
- if (scale.ticks) {
- tickEnter.call(tickTransform, scale0);
- tickUpdate.call(tickTransform, scale1);
- tickExit.call(tickTransform, scale1);
- subtickEnter.call(tickTransform, scale0);
- subtickUpdate.call(tickTransform, scale1);
- subtickExit.call(tickTransform, scale1);
- } else {
- var dx = scale1.rangeBand() / 2, x = function(d) {
- return scale1(d) + dx;
- };
- tickEnter.call(tickTransform, x);
- tickUpdate.call(tickTransform, x);
- }
- });
- }
- axis.scale = function(x) {
- if (!arguments.length) return scale;
- scale = x;
- return axis;
- };
- axis.orient = function(x) {
- if (!arguments.length) return orient;
- orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient;
- return axis;
- };
- axis.ticks = function() {
- if (!arguments.length) return tickArguments_;
- tickArguments_ = arguments;
- return axis;
- };
- axis.tickValues = function(x) {
- if (!arguments.length) return tickValues;
- tickValues = x;
- return axis;
- };
- axis.tickFormat = function(x) {
- if (!arguments.length) return tickFormat_;
- tickFormat_ = x;
- return axis;
- };
- axis.tickSize = function(x, y) {
- if (!arguments.length) return tickMajorSize;
- var n = arguments.length - 1;
- tickMajorSize = +x;
- tickMinorSize = n > 1 ? +y : tickMajorSize;
- tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;
- return axis;
- };
- axis.tickPadding = function(x) {
- if (!arguments.length) return tickPadding;
- tickPadding = +x;
- return axis;
- };
- axis.tickSubdivide = function(x) {
- if (!arguments.length) return tickSubdivide;
- tickSubdivide = +x;
- return axis;
- };
- return axis;
- };
- var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = {
- top: 1,
- right: 1,
- bottom: 1,
- left: 1
- };
- function d3_svg_axisX(selection, x) {
- selection.attr("transform", function(d) {
- return "translate(" + x(d) + ",0)";
- });
- }
- function d3_svg_axisY(selection, y) {
- selection.attr("transform", function(d) {
- return "translate(0," + y(d) + ")";
- });
- }
- function d3_svg_axisSubdivide(scale, ticks, m) {
- subticks = [];
- if (m && ticks.length > 1) {
- var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d
= (ticks[1] - ticks[0]) / ++m, j, v;
- while (++i < n) {
- for (j = m; --j > 0; ) {
- if ((v = +ticks[i] - j * d) >= extent[0]) {
- subticks.push(v);
- }
- }
- }
- for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) {
- subticks.push(v);
- }
- }
- return subticks;
- }
- d3.svg.brush = function() {
- var event = d3_eventDispatch(brush, "brushstart", "brush",
"brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [
0, 0 ], [ 0, 0 ] ], clamp = [ true, true ], extentDomain;
- function brush(g) {
- g.each(function() {
- var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]),
fg = g.selectAll(".extent").data([ 0 ]), tz =
g.selectAll(".resize").data(resizes, String), e;
- g.style("pointer-events",
"all").on("mousedown.brush",
brushstart).on("touchstart.brush", brushstart);
- bg.enter().append("rect").attr("class",
"background").style("visibility",
"hidden").style("cursor", "crosshair");
- fg.enter().append("rect").attr("class",
"extent").style("cursor", "move");
- tz.enter().append("g").attr("class", function(d) {
- return "resize " + d;
- }).style("cursor", function(d) {
- return d3_svg_brushCursor[d];
- }).append("rect").attr("x", function(d) {
- return /[ew]$/.test(d) ? -3 : null;
- }).attr("y", function(d) {
- return /^[ns]/.test(d) ? -3 : null;
- }).attr("width", 6).attr("height",
6).style("visibility", "hidden");
- tz.style("display", brush.empty() ? "none" : null);
- tz.exit().remove();
- if (x) {
- e = d3_scaleRange(x);
- bg.attr("x", e[0]).attr("width", e[1] - e[0]);
- redrawX(g);
- }
- if (y) {
- e = d3_scaleRange(y);
- bg.attr("y", e[0]).attr("height", e[1] - e[0]);
- redrawY(g);
- }
- redraw(g);
- });
- }
- function redraw(g) {
- g.selectAll(".resize").attr("transform", function(d) {
- return "translate(" + extent[+/e$/.test(d)][0] + "," +
extent[+/^s/.test(d)][1] + ")";
- });
- }
- function redrawX(g) {
- g.select(".extent").attr("x", extent[0][0]);
- g.selectAll(".extent,.n>rect,.s>rect").attr("width",
extent[1][0] - extent[0][0]);
- }
- function redrawY(g) {
- g.select(".extent").attr("y", extent[0][1]);
- g.selectAll(".extent,.e>rect,.w>rect").attr("height",
extent[1][1] - extent[0][1]);
- }
- function brushstart() {
- var target = this, eventTarget = d3.select(d3.event.target), event_ =
event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(),
resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing)
&& y, dragging = eventTarget.classed("extent"), dragRestore =
d3_event_dragSuppress("brush"), center, origin = mouse(), offset;
- var w = d3.select(d3_window).on("keydown.brush",
keydown).on("keyup.brush", keyup);
- if (d3.event.changedTouches) {
- w.on("touchmove.brush", brushmove).on("touchend.brush",
brushend);
- } else {
- w.on("mousemove.brush", brushmove).on("mouseup.brush",
brushend);
- }
- if (dragging) {
- origin[0] = extent[0][0] - origin[0];
- origin[1] = extent[0][1] - origin[1];
- } else if (resizing) {
- var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
- offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ];
- origin[0] = extent[ex][0];
- origin[1] = extent[ey][1];
- } else if (d3.event.altKey) center = origin.slice();
- g.style("pointer-events",
"none").selectAll(".resize").style("display", null);
- d3.select("body").style("cursor",
eventTarget.style("cursor"));
- event_({
- type: "brushstart"
- });
- brushmove();
- function mouse() {
- var touches = d3.event.changedTouches;
- return touches ? d3.touches(target, touches)[0] : d3.mouse(target);
- }
- function keydown() {
- if (d3.event.keyCode == 32) {
- if (!dragging) {
- center = null;
- origin[0] -= extent[1][0];
- origin[1] -= extent[1][1];
- dragging = 2;
- }
- d3_eventPreventDefault();
- }
- }
- function keyup() {
- if (d3.event.keyCode == 32 && dragging == 2) {
- origin[0] += extent[1][0];
- origin[1] += extent[1][1];
- dragging = 0;
- d3_eventPreventDefault();
- }
- }
- function brushmove() {
- var point = mouse(), moved = false;
- if (offset) {
- point[0] += offset[0];
- point[1] += offset[1];
- }
- if (!dragging) {
- if (d3.event.altKey) {
- if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] +
extent[1][1]) / 2 ];
- origin[0] = extent[+(point[0] < center[0])][0];
- origin[1] = extent[+(point[1] < center[1])][1];
- } else center = null;
- }
- if (resizingX && move1(point, x, 0)) {
- redrawX(g);
- moved = true;
- }
- if (resizingY && move1(point, y, 1)) {
- redrawY(g);
- moved = true;
- }
- if (moved) {
- redraw(g);
- event_({
- type: "brush",
- mode: dragging ? "move" : "resize"
- });
- }
- }
- function move1(point, scale, i) {
- var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position =
origin[i], size = extent[1][i] - extent[0][i], min, max;
- if (dragging) {
- r0 -= position;
- r1 -= size + position;
- }
- min = clamp[i] ? Math.max(r0, Math.min(r1, point[i])) : point[i];
- if (dragging) {
- max = (min += position) + size;
- } else {
- if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
- if (position < min) {
- max = min;
- min = position;
- } else {
- max = position;
- }
- }
- if (extent[0][i] !== min || extent[1][i] !== max) {
- extentDomain = null;
- extent[0][i] = min;
- extent[1][i] = max;
- return true;
- }
- }
- function brushend() {
- brushmove();
- g.style("pointer-events",
"all").selectAll(".resize").style("display", brush.empty() ?
"none" : null);
- d3.select("body").style("cursor", null);
- w.on("mousemove.brush", null).on("mouseup.brush",
null).on("touchmove.brush", null).on("touchend.brush",
null).on("keydown.brush", null).on("keyup.brush", null);
- dragRestore();
- event_({
- type: "brushend"
- });
- }
- }
- brush.x = function(z) {
- if (!arguments.length) return x;
- x = z;
- resizes = d3_svg_brushResizes[!x << 1 | !y];
- return brush;
- };
- brush.y = function(z) {
- if (!arguments.length) return y;
- y = z;
- resizes = d3_svg_brushResizes[!x << 1 | !y];
- return brush;
- };
- brush.clamp = function(z) {
- if (!arguments.length) return x && y ? clamp : x || y ? clamp[+!x] : null;
- if (x && y) clamp = [ !!z[0], !!z[1] ]; else if (x || y) clamp[+!x] = !!z;
- return brush;
- };
- brush.extent = function(z) {
- var x0, x1, y0, y1, t;
- if (!arguments.length) {
- z = extentDomain || extent;
- if (x) {
- x0 = z[0][0], x1 = z[1][0];
- if (!extentDomain) {
- x0 = extent[0][0], x1 = extent[1][0];
- if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
- if (x1 < x0) t = x0, x0 = x1, x1 = t;
- }
- }
- if (y) {
- y0 = z[0][1], y1 = z[1][1];
- if (!extentDomain) {
- y0 = extent[0][1], y1 = extent[1][1];
- if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
- if (y1 < y0) t = y0, y0 = y1, y1 = t;
- }
- }
- return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y
&& [ y0, y1 ];
- }
- extentDomain = [ [ 0, 0 ], [ 0, 0 ] ];
- if (x) {
- x0 = z[0], x1 = z[1];
- if (y) x0 = x0[0], x1 = x1[0];
- extentDomain[0][0] = x0, extentDomain[1][0] = x1;
- if (x.invert) x0 = x(x0), x1 = x(x1);
- if (x1 < x0) t = x0, x0 = x1, x1 = t;
- extent[0][0] = x0 | 0, extent[1][0] = x1 | 0;
- }
- if (y) {
- y0 = z[0], y1 = z[1];
- if (x) y0 = y0[1], y1 = y1[1];
- extentDomain[0][1] = y0, extentDomain[1][1] = y1;
- if (y.invert) y0 = y(y0), y1 = y(y1);
- if (y1 < y0) t = y0, y0 = y1, y1 = t;
- extent[0][1] = y0 | 0, extent[1][1] = y1 | 0;
- }
- return brush;
- };
- brush.clear = function() {
- extentDomain = null;
- extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0;
- return brush;
- };
- brush.empty = function() {
- return x && extent[0][0] === extent[1][0] || y && extent[0][1] ===
extent[1][1];
- };
- return d3.rebind(brush, event, "on");
- };
- var d3_svg_brushCursor = {
- n: "ns-resize",
- e: "ew-resize",
- s: "ns-resize",
- w: "ew-resize",
- nw: "nwse-resize",
- ne: "nesw-resize",
- se: "nwse-resize",
- sw: "nesw-resize"
- };
- var d3_svg_brushResizes = [ [ "n", "e", "s",
"w", "nw", "ne", "se", "sw" ], [
"e", "w" ], [ "n", "s" ], [] ];
- d3.time = {};
- var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday",
"Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday" ];
- function d3_time_utc() {
- this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) :
arguments[0]);
- }
- d3_time_utc.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() {
- d3_time_prototype.setUTCDate.apply(this._, arguments);
- },
- setDay: function() {
- d3_time_prototype.setUTCDay.apply(this._, arguments);
- },
- setFullYear: function() {
- d3_time_prototype.setUTCFullYear.apply(this._, arguments);
- },
- setHours: function() {
- d3_time_prototype.setUTCHours.apply(this._, arguments);
- },
- setMilliseconds: function() {
- d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
- },
- setMinutes: function() {
- d3_time_prototype.setUTCMinutes.apply(this._, arguments);
- },
- setMonth: function() {
- d3_time_prototype.setUTCMonth.apply(this._, arguments);
- },
- setSeconds: function() {
- d3_time_prototype.setUTCSeconds.apply(this._, arguments);
- },
- setTime: function() {
- d3_time_prototype.setTime.apply(this._, arguments);
- }
- };
- var d3_time_prototype = Date.prototype;
- var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate =
"%m/%d/%Y", d3_time_formatTime = "%H:%M:%S";
- var d3_time_days = [ "Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday", "Saturday" ],
d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue",
"Wed", "Thu", "Fri", "Sat" ], d3_time_months = [
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December" ],
d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar",
"Apr", "May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec" ];
- function d3_time_interval(local, step, number) {
- function round(date) {
- var d0 = local(date), d1 = offset(d0, 1);
- return date - d0 < d1 - date ? d0 : d1;
- }
- function ceil(date) {
- step(date = local(new d3_time(date - 1)), 1);
- return date;
- }
- function offset(date, k) {
- step(date = new d3_time(+date), k);
- return date;
- }
- function range(t0, t1, dt) {
- var time = ceil(t0), times = [];
- if (dt > 1) {
- while (time < t1) {
- if (!(number(time) % dt)) times.push(new Date(+time));
- step(time, 1);
- }
- } else {
- while (time < t1) times.push(new Date(+time)), step(time, 1);
- }
- return times;
- }
- function range_utc(t0, t1, dt) {
- try {
- d3_time = d3_time_utc;
- var utc = new d3_time_utc();
- utc._ = t0;
- return range(utc, t1, dt);
- } finally {
- d3_time = Date;
- }
- }
- local.floor = local;
- local.round = round;
- local.ceil = ceil;
- local.offset = offset;
- local.range = range;
- var utc = local.utc = d3_time_interval_utc(local);
- utc.floor = utc;
- utc.round = d3_time_interval_utc(round);
- utc.ceil = d3_time_interval_utc(ceil);
- utc.offset = d3_time_interval_utc(offset);
- utc.range = range_utc;
- return local;
- }
- function d3_time_interval_utc(method) {
- return function(date, k) {
- try {
- d3_time = d3_time_utc;
- var utc = new d3_time_utc();
- utc._ = date;
- return method(utc, k)._;
- } finally {
- d3_time = Date;
- }
- };
- }
- d3.time.year = d3_time_interval(function(date) {
- date = d3.time.day(date);
- date.setMonth(0, 1);
- return date;
- }, function(date, offset) {
- date.setFullYear(date.getFullYear() + offset);
- }, function(date) {
- return date.getFullYear();
- });
- d3.time.years = d3.time.year.range;
- d3.time.years.utc = d3.time.year.utc.range;
- d3.time.day = d3_time_interval(function(date) {
- var day = new d3_time(2e3, 0);
- day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
- return day;
- }, function(date, offset) {
- date.setDate(date.getDate() + offset);
- }, function(date) {
- return date.getDate() - 1;
- });
- d3.time.days = d3.time.day.range;
- d3.time.days.utc = d3.time.day.utc.range;
- d3.time.dayOfYear = function(date) {
- var year = d3.time.year(date);
- return Math.floor((date - year - (date.getTimezoneOffset() -
year.getTimezoneOffset()) * 6e4) / 864e5);
- };
- d3_time_daySymbols.forEach(function(day, i) {
- day = day.toLowerCase();
- i = 7 - i;
- var interval = d3.time[day] = d3_time_interval(function(date) {
- (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
- return date;
- }, function(date, offset) {
- date.setDate(date.getDate() + Math.floor(offset) * 7);
- }, function(date) {
- var day = d3.time.year(date).getDay();
- return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
- });
- d3.time[day + "s"] = interval.range;
- d3.time[day + "s"].utc = interval.utc.range;
- d3.time[day + "OfYear"] = function(date) {
- var day = d3.time.year(date).getDay();
- return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7);
- };
- });
- d3.time.week = d3.time.sunday;
- d3.time.weeks = d3.time.sunday.range;
- d3.time.weeks.utc = d3.time.sunday.utc.range;
- d3.time.weekOfYear = d3.time.sundayOfYear;
- d3.time.format = function(template) {
- var n = template.length;
- function format(date) {
- var string = [], i = -1, j = 0, c, p, f;
- while (++i < n) {
- if (template.charCodeAt(i) === 37) {
- string.push(template.substring(j, i));
- if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c =
template.charAt(++i);
- if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ?
" " : "0" : p);
- string.push(c);
- j = i + 1;
- }
- }
- string.push(template.substring(j, i));
- return string.join("");
- }
- format.parse = function(string) {
- var d = {
- y: 1900,
- m: 0,
- d: 1,
- H: 0,
- M: 0,
- S: 0,
- L: 0
- }, i = d3_time_parse(d, template, string, 0);
- if (i != string.length) return null;
- if ("p" in d) d.H = d.H % 12 + d.p * 12;
- var date = new d3_time();
- if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d
&& ("W" in d || "U" in d)) {
- date.setFullYear(d.y, 0, 1);
- date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 -
(date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7);
- } else date.setFullYear(d.y, d.m, d.d);
- date.setHours(d.H, d.M, d.S, d.L);
- return date;
- };
- format.toString = function() {
- return template;
- };
- return format;
- };
- function d3_time_parse(date, template, string, j) {
- var c, p, i = 0, n = template.length, m = string.length;
- while (i < n) {
- if (j >= m) return -1;
- c = template.charCodeAt(i++);
- if (c === 37) {
- p = d3_time_parsers[template.charAt(i++)];
- if (!p || (j = p(date, string, j)) < 0) return -1;
- } else if (c != string.charCodeAt(j++)) {
- return -1;
- }
- }
- return j;
- }
- function d3_time_formatRe(names) {
- return new RegExp("^(?:" + names.map(d3.requote).join("|") +
")", "i");
- }
- function d3_time_formatLookup(names) {
- var map = new d3_Map(), i = -1, n = names.length;
- while (++i < n) map.set(names[i].toLowerCase(), i);
- return map;
- }
- function d3_time_formatPad(value, fill, width) {
- var sign = value < 0 ? "-" : "", string = (sign ? -value :
value) + "", length = string.length;
- return sign + (length < width ? new Array(width - length + 1).join(fill) + string
: string);
- }
- var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayLookup =
d3_time_formatLookup(d3_time_days), d3_time_dayAbbrevRe =
d3_time_formatRe(d3_time_dayAbbreviations), d3_time_dayAbbrevLookup =
d3_time_formatLookup(d3_time_dayAbbreviations), d3_time_monthRe =
d3_time_formatRe(d3_time_months), d3_time_monthLookup =
d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe =
d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup =
d3_time_formatLookup(d3_time_monthAbbreviations), d3_time_percentRe = /^%/;
- var d3_time_formatPads = {
- "-": "",
- _: " ",
- "0": "0"
- };
- var d3_time_formats = {
- a: function(d) {
- return d3_time_dayAbbreviations[d.getDay()];
- },
- A: function(d) {
- return d3_time_days[d.getDay()];
- },
- b: function(d) {
- return d3_time_monthAbbreviations[d.getMonth()];
- },
- B: function(d) {
- return d3_time_months[d.getMonth()];
- },
- c: d3.time.format(d3_time_formatDateTime),
- d: function(d, p) {
- return d3_time_formatPad(d.getDate(), p, 2);
- },
- e: function(d, p) {
- return d3_time_formatPad(d.getDate(), p, 2);
- },
- H: function(d, p) {
- return d3_time_formatPad(d.getHours(), p, 2);
- },
- I: function(d, p) {
- return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);
- },
- j: function(d, p) {
- return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3);
- },
- L: function(d, p) {
- return d3_time_formatPad(d.getMilliseconds(), p, 3);
- },
- m: function(d, p) {
- return d3_time_formatPad(d.getMonth() + 1, p, 2);
- },
- M: function(d, p) {
- return d3_time_formatPad(d.getMinutes(), p, 2);
- },
- p: function(d) {
- return d.getHours() >= 12 ? "PM" : "AM";
- },
- S: function(d, p) {
- return d3_time_formatPad(d.getSeconds(), p, 2);
- },
- U: function(d, p) {
- return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2);
- },
- w: function(d) {
- return d.getDay();
- },
- W: function(d, p) {
- return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2);
- },
- x: d3.time.format(d3_time_formatDate),
- X: d3.time.format(d3_time_formatTime),
- y: function(d, p) {
- return d3_time_formatPad(d.getFullYear() % 100, p, 2);
- },
- Y: function(d, p) {
- return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);
- },
- Z: d3_time_zone,
- "%": function() {
- return "%";
- }
- };
- var d3_time_parsers = {
- a: d3_time_parseWeekdayAbbrev,
- A: d3_time_parseWeekday,
- b: d3_time_parseMonthAbbrev,
- B: d3_time_parseMonth,
- c: d3_time_parseLocaleFull,
- d: d3_time_parseDay,
- e: d3_time_parseDay,
- H: d3_time_parseHour24,
- I: d3_time_parseHour24,
- j: d3_time_parseDayOfYear,
- L: d3_time_parseMilliseconds,
- m: d3_time_parseMonthNumber,
- M: d3_time_parseMinutes,
- p: d3_time_parseAmPm,
- S: d3_time_parseSeconds,
- U: d3_time_parseWeekNumberSunday,
- w: d3_time_parseWeekdayNumber,
- W: d3_time_parseWeekNumberMonday,
- x: d3_time_parseLocaleDate,
- X: d3_time_parseLocaleTime,
- y: d3_time_parseYear,
- Y: d3_time_parseFullYear,
- "%": d3_time_parseLiteralPercent
- };
- function d3_time_parseWeekdayAbbrev(date, string, i) {
- d3_time_dayAbbrevRe.lastIndex = 0;
- var n = d3_time_dayAbbrevRe.exec(string.substring(i));
- return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i +
n[0].length) : -1;
- }
- function d3_time_parseWeekday(date, string, i) {
- d3_time_dayRe.lastIndex = 0;
- var n = d3_time_dayRe.exec(string.substring(i));
- return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) :
-1;
- }
- function d3_time_parseWeekdayNumber(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 1));
- return n ? (date.w = +n[0], i + n[0].length) : -1;
- }
- function d3_time_parseWeekNumberSunday(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i));
- return n ? (date.U = +n[0], i + n[0].length) : -1;
- }
- function d3_time_parseWeekNumberMonday(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i));
- return n ? (date.W = +n[0], i + n[0].length) : -1;
- }
- function d3_time_parseMonthAbbrev(date, string, i) {
- d3_time_monthAbbrevRe.lastIndex = 0;
- var n = d3_time_monthAbbrevRe.exec(string.substring(i));
- return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i +
n[0].length) : -1;
- }
- function d3_time_parseMonth(date, string, i) {
- d3_time_monthRe.lastIndex = 0;
- var n = d3_time_monthRe.exec(string.substring(i));
- return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) :
-1;
- }
- function d3_time_parseLocaleFull(date, string, i) {
- return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
- }
- function d3_time_parseLocaleDate(date, string, i) {
- return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
- }
- function d3_time_parseLocaleTime(date, string, i) {
- return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
- }
- function d3_time_parseFullYear(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 4));
- return n ? (date.y = +n[0], i + n[0].length) : -1;
- }
- function d3_time_parseYear(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 2));
- return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1;
- }
- function d3_time_expandYear(d) {
- return d + (d > 68 ? 1900 : 2e3);
- }
- function d3_time_parseMonthNumber(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 2));
- return n ? (date.m = n[0] - 1, i + n[0].length) : -1;
- }
- function d3_time_parseDay(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 2));
- return n ? (date.d = +n[0], i + n[0].length) : -1;
- }
- function d3_time_parseDayOfYear(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 3));
- return n ? (date.j = +n[0], i + n[0].length) : -1;
- }
- function d3_time_parseHour24(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 2));
- return n ? (date.H = +n[0], i + n[0].length) : -1;
- }
- function d3_time_parseMinutes(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 2));
- return n ? (date.M = +n[0], i + n[0].length) : -1;
- }
- function d3_time_parseSeconds(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 2));
- return n ? (date.S = +n[0], i + n[0].length) : -1;
- }
- function d3_time_parseMilliseconds(date, string, i) {
- d3_time_numberRe.lastIndex = 0;
- var n = d3_time_numberRe.exec(string.substring(i, i + 3));
- return n ? (date.L = +n[0], i + n[0].length) : -1;
- }
- var d3_time_numberRe = /^\s*\d+/;
- function d3_time_parseAmPm(date, string, i) {
- var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase());
- return n == null ? -1 : (date.p = n, i);
- }
- var d3_time_amPmLookup = d3.map({
- am: 0,
- pm: 1
- });
- function d3_time_zone(d) {
- var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh =
~~(Math.abs(z) / 60), zm = Math.abs(z) % 60;
- return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm,
"0", 2);
- }
- function d3_time_parseLiteralPercent(date, string, i) {
- d3_time_percentRe.lastIndex = 0;
- var n = d3_time_percentRe.exec(string.substring(i, i + 1));
- return n ? i + n[0].length : -1;
- }
- d3.time.format.utc = function(template) {
- var local = d3.time.format(template);
- function format(date) {
- try {
- d3_time = d3_time_utc;
- var utc = new d3_time();
- utc._ = date;
- return local(utc);
- } finally {
- d3_time = Date;
- }
- }
- format.parse = function(string) {
- try {
- d3_time = d3_time_utc;
- var date = local.parse(string);
- return date && date._;
- } finally {
- d3_time = Date;
- }
- };
- format.toString = local.toString;
- return format;
- };
- var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");
- d3.time.format.iso = Date.prototype.toISOString && +new
Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso;
- function d3_time_formatIsoNative(date) {
- return date.toISOString();
- }
- d3_time_formatIsoNative.parse = function(string) {
- var date = new Date(string);
- return isNaN(date) ? null : date;
- };
- d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
- d3.time.second = d3_time_interval(function(date) {
- return new d3_time(Math.floor(date / 1e3) * 1e3);
- }, function(date, offset) {
- date.setTime(date.getTime() + Math.floor(offset) * 1e3);
- }, function(date) {
- return date.getSeconds();
- });
- d3.time.seconds = d3.time.second.range;
- d3.time.seconds.utc = d3.time.second.utc.range;
- d3.time.minute = d3_time_interval(function(date) {
- return new d3_time(Math.floor(date / 6e4) * 6e4);
- }, function(date, offset) {
- date.setTime(date.getTime() + Math.floor(offset) * 6e4);
- }, function(date) {
- return date.getMinutes();
- });
- d3.time.minutes = d3.time.minute.range;
- d3.time.minutes.utc = d3.time.minute.utc.range;
- d3.time.hour = d3_time_interval(function(date) {
- var timezone = date.getTimezoneOffset() / 60;
- return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
- }, function(date, offset) {
- date.setTime(date.getTime() + Math.floor(offset) * 36e5);
- }, function(date) {
- return date.getHours();
- });
- d3.time.hours = d3.time.hour.range;
- d3.time.hours.utc = d3.time.hour.utc.range;
- d3.time.month = d3_time_interval(function(date) {
- date = d3.time.day(date);
- date.setDate(1);
- return date;
- }, function(date, offset) {
- date.setMonth(date.getMonth() + offset);
- }, function(date) {
- return date.getMonth();
- });
- d3.time.months = d3.time.month.range;
- d3.time.months.utc = d3.time.month.utc.range;
- function d3_time_scale(linear, methods, format) {
- function scale(x) {
- return linear(x);
- }
- scale.invert = function(x) {
- return d3_time_scaleDate(linear.invert(x));
- };
- scale.domain = function(x) {
- if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
- linear.domain(x);
- return scale;
- };
- scale.nice = function(m) {
- return scale.domain(d3_scale_nice(scale.domain(), m));
- };
- scale.ticks = function(m, k) {
- var extent = d3_scaleExtent(scale.domain());
- if (typeof m !== "function") {
- var span = extent[1] - extent[0], target = span / m, i =
d3.bisect(d3_time_scaleSteps, target);
- if (i == d3_time_scaleSteps.length) return methods.year(extent, m);
- if (!i) return linear.ticks(m).map(d3_time_scaleDate);
- if (Math.log(target / d3_time_scaleSteps[i - 1]) <
Math.log(d3_time_scaleSteps[i] / target)) --i;
- m = methods[i];
- k = m[1];
- m = m[0].range;
- }
- return m(extent[0], new Date(+extent[1] + 1), k);
- };
- scale.tickFormat = function() {
- return format;
- };
- scale.copy = function() {
- return d3_time_scale(linear.copy(), methods, format);
- };
- return d3_scale_linearRebind(scale, linear);
- }
- function d3_time_scaleDate(t) {
- return new Date(t);
- }
- function d3_time_scaleFormat(formats) {
- return function(date) {
- var i = formats.length - 1, f = formats[i];
- while (!f[1](date)) f = formats[--i];
- return f[0](date);
- };
- }
- function d3_time_scaleSetYear(y) {
- var d = new Date(y, 0, 1);
- d.setFullYear(y);
- return d;
- }
- function d3_time_scaleGetYear(d) {
- var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y +
1);
- return y + (d - d0) / (d1 - d0);
- }
- var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5,
216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];
- var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [
d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5
], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3
], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [
d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ];
- var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [
d3.time.format("%B"), function(d) {
- return d.getMonth();
- } ], [ d3.time.format("%b %d"), function(d) {
- return d.getDate() != 1;
- } ], [ d3.time.format("%a %d"), function(d) {
- return d.getDay() && d.getDate() != 1;
- } ], [ d3.time.format("%I %p"), function(d) {
- return d.getHours();
- } ], [ d3.time.format("%I:%M"), function(d) {
- return d.getMinutes();
- } ], [ d3.time.format(":%S"), function(d) {
- return d.getSeconds();
- } ], [ d3.time.format(".%L"), function(d) {
- return d.getMilliseconds();
- } ] ];
- var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat =
d3_time_scaleFormat(d3_time_scaleLocalFormats);
- d3_time_scaleLocalMethods.year = function(extent, m) {
- return
d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear);
- };
- d3.time.scale = function() {
- return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods,
d3_time_scaleLocalFormat);
- };
- var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) {
- return [ m[0].utc, m[1] ];
- });
- var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [
d3.time.format.utc("%B"), function(d) {
- return d.getUTCMonth();
- } ], [ d3.time.format.utc("%b %d"), function(d) {
- return d.getUTCDate() != 1;
- } ], [ d3.time.format.utc("%a %d"), function(d) {
- return d.getUTCDay() && d.getUTCDate() != 1;
- } ], [ d3.time.format.utc("%I %p"), function(d) {
- return d.getUTCHours();
- } ], [ d3.time.format.utc("%I:%M"), function(d) {
- return d.getUTCMinutes();
- } ], [ d3.time.format.utc(":%S"), function(d) {
- return d.getUTCSeconds();
- } ], [ d3.time.format.utc(".%L"), function(d) {
- return d.getUTCMilliseconds();
- } ] ];
- var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
- function d3_time_scaleUTCSetYear(y) {
- var d = new Date(Date.UTC(y, 0, 1));
- d.setUTCFullYear(y);
- return d;
- }
- function d3_time_scaleUTCGetYear(d) {
- var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 =
d3_time_scaleUTCSetYear(y + 1);
- return y + (d - d0) / (d1 - d0);
- }
- d3_time_scaleUTCMethods.year = function(extent, m) {
- return
d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear);
- };
- d3.time.scale.utc = function() {
- return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods,
d3_time_scaleUTCFormat);
- };
- d3.text = d3_xhrType(function(request) {
- return request.responseText;
- });
- d3.json = function(url, callback) {
- return d3_xhr(url, "application/json", d3_json, callback);
- };
- function d3_json(request) {
- return JSON.parse(request.responseText);
- }
- d3.html = function(url, callback) {
- return d3_xhr(url, "text/html", d3_html, callback);
- };
- function d3_html(request) {
- var range = d3_document.createRange();
- range.selectNode(d3_document.body);
- return range.createContextualFragment(request.responseText);
- }
- d3.xml = d3_xhrType(function(request) {
- return request.responseXML;
- });
- return d3;
-}();
\ No newline at end of file
diff --git a/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.min.js
b/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.min.js
deleted file mode 100644
index 0ae1d23..0000000
--- a/modules/enterprise/gui/coregui/src/main/webapp/js/d3.v3.min.js
+++ /dev/null
@@ -1,5 +0,0 @@
-d3=function(){function n(n){return null!=n&&!isNaN(n)}function t(n){return
n.length}function e(n){for(var t=1;n*t%1;)t*=10;return t}function r(n,t){try{for(var e in
t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function
i(){}function u(){}function a(n,t,e){return function(){var r=e.apply(t,arguments);return
r===t?n:r}}function o(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
i=Aa[e]+t;if(i in n)return i}}function c(n){for(var
t=-1,e=n.length,r=[];++t<e;)r.push(n[t]);return r}function l(n){return
Array.prototype.slice.call(n)}function f(){}function s(){}function h(n){function
t(){for(var
t,r=e,i=-1,u=r.length;++i<u;)(t=r[i].on)&&t.apply(this,arguments);return n}var
e=[],r=new i;return t.on=function(t,i){var u,a=r.get(t);return
arguments.length<2?a&&a.on:(a&&(a.on=null,e=e.slice(0,u=e.indexOf(a)).concat(e.slice(u+1)),r.remove(t)),i&&e.push(r.set(t,{on:i})),n)},t}function
g(){va
.event.preventDefault()}function p(){for(var n,t=va.event;n=t.sourceEvent;)t=n;return
t}function d(n){for(var t=new
s,e=0,r=arguments.length;++e<r;)t[arguments[e]]=h(t);return t.of=function(e,r){return
function(i){try{var
u=i.sourceEvent=va.event;i.target=n,va.event=i,t[i.type].apply(e,r)}finally{va.event=u}}},t}function
m(n){return Ta(n,Ha),n}function v(n){return function(){return za(n,this)}}function
y(n){return function(){return Da(n,this)}}function M(n,t){function
e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function
i(){this.setAttribute(n,t)}function u(){this.setAttributeNS(n.space,n.local,t)}function
a(){var
e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function
o(){var
e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return
n=va.ns.qualify(n),null==t?n.local?r:e:"function"==typeof
t?n.local?o:a:n.local?u:i}function x(n){return n.trim(
).replace(/\s+/g," ")}function b(n){return new
RegExp("(?:^|\\s+)"+va.requote(n)+"(?:\\s+|$)","g")}function
_(n,t){function e(){for(var e=-1;++e<i;)n[e](this,t)}function r(){for(var
e=-1,r=t.apply(this,arguments);++e<i;)n[e](this,r)}n=n.trim().split(/\s+/).map(w);var
i=n.length;return"function"==typeof t?r:e}function w(n){var t=b(n);return
function(e,r){if(i=e.classList)return r?i.add(n):i.remove(n);var
i=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(i)||e.setAttribute("class",x(i+"
"+n))):e.setAttribute("class",x(i.replace(t," ")))}}function
S(n,t,e){function r(){this.style.removeProperty(n)}function
i(){this.style.setProperty(n,t,e)}function u(){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?u:i}function E(n,t){function e(){delete
this[n]}function r(){this[n]=t}function i(){var e=t.apply(this,arguments);null==e?delete
this[n]:this[n]=e}return null==t?e:"function"==typeof t?i:r}fun
ction k(n){return{__data__:n}}function A(n){return function(){return La(this,n)}}function
N(n){return
arguments.length||(n=va.ascending),function(t,e){return!t-!e||n(t.__data__,e.__data__)}}function
q(n,t){for(var e=0,r=n.length;r>e;e++)for(var
i,u=n[e],a=0,o=u.length;o>a;a++)(i=u[a])&&t(i,a,e);return n}function
T(n){return Ta(n,Pa),n}function C(n,t,e){function r(){var
t=this[a];t&&(this.removeEventListener(n,t,t.$),delete this[a])}function i(){var
i=c(t,Na(arguments));r.call(this),this.addEventListener(n,this[a]=i,i.$=e),i._=t}function
u(){var t,e=new RegExp("^__on([^.]+)"+va.requote(n)+"$");for(var r in
this)if(t=r.match(e)){var i=this[r];this.removeEventListener(t[1],i,i.$),delete
this[r]}}var
a="__on"+n,o=n.indexOf("."),c=z;o>0&&(n=n.substring(0,o));var
l=Ra.get(n);return l&&(n=l,c=D),o?t?i:r:t?f:u}function z(n,t){return
function(e){var
r=va.event;va.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{va.event=r}}}function
D(n,t){var e=z(n,t);return function(n){var t=
this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function
j(n){var
t="selectstart."+n,e="dragstart."+n,r="click."+n,i=va.select(xa).on(t,g).on(e,g),u=Ma.style,a=u[Ya];return
u[Ya]="none",function(n){function
o(){i.on(r,null)}i.on(t,null).on(e,null),u[Ya]=a,n&&(i.on(r,function(){g(),o()},!0),setTimeout(o,0))}}function
L(n,t){var e=n.ownerSVGElement||n;if(e.createSVGPoint){var
r=e.createSVGPoint();if(0>Ua&&(xa.scrollX||xa.scrollY)){e=va.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var
i=e[0][0].getScreenCTM();Ua=!(i.f||i.e),e.remove()}return
Ua?(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
u=n.getBoundingClientRect();return[t.clientX-u.left-n.clientLeft,t.clientY-u.top-n.clientTop]}function
H(){}function F(n,t,e){return new P(n,t,e)}function
P(n,t,e){this.h=n,this.s=t,this.l=e}function O(n,t,e){function r(
n){return
n>360?n-=360:0>n&&(n+=360),60>n?u+(a-u)*n/60:180>n?a:240>n?u+(a-u)*(240-n)/60:u}function
i(n){return Math.round(255*r(n))}var u,a;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,a=.5>=e?e*(1+t):e+t-e*t,u=2*e-a,et(i(n+120),i(n),i(n-120))}function
R(n){return n>0?1:0>n?-1:0}function Y(n){return
n>1?0:-1>n?Ba:Math.acos(n)}function U(n){return
n>1?Ba/2:-1>n?-Ba/2:Math.asin(n)}function
I(n){return(Math.exp(n)-Math.exp(-n))/2}function
V(n){return(Math.exp(n)+Math.exp(-n))/2}function X(n){return(n=Math.sin(n/2))*n}function
Z(n,t,e){return new B(n,t,e)}function B(n,t,e){this.h=n,this.c=t,this.l=e}function
$(n,t,e){return
isNaN(n)&&(n=0),isNaN(t)&&(t=0),W(e,Math.cos(n*=Ja)*t,Math.sin(n)*t)}function
W(n,t,e){return new J(n,t,e)}function J(n,t,e){this.l=n,this.a=t,this.b=e}function
G(n,t,e){var r=(n+16)/116,i=r+t/500,u=r-e/200;return
i=Q(i)*no,r=Q(r)*to,u=Q(u)*eo,et(tt(3.2404542*i-1.5371385*r-.4985314*u),tt(-.969266*i+1.8760108*r+.041556*u),t
t(.0556434*i-.2040259*r+1.0572252*u))}function K(n,t,e){return
n>0?Z(Math.atan2(e,t)*Ga,Math.sqrt(t*t+e*e),n):Z(0/0,0/0,n)}function Q(n){return
n>.206893034?n*n*n:(n-4/29)/7.787037}function nt(n){return
n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function tt(n){return
Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function
et(n,t,e){return new rt(n,t,e)}function rt(n,t,e){this.r=n,this.g=t,this.b=e}function
it(n){return
16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function
ut(n,t,e){var
r,i,u,a=0,o=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(i=r[2].split(","),r[1]){case"hsl":return
e(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return
t(lt(i[0]),lt(i[1]),lt(i[2]))}return(u=uo.get(n))?t(u.r,u.g,u.b):(null!=n&&"#"===n.charAt(0)&&(4===n.length?(a=n.charAt(1),a+=a,o=n.charAt(2),o+=o,c=n.charAt(3),c+=c):7===n.length&&(a=n.substring(1,3),o=n.substring(3,5),c=n.substring(5,7)),a=parseInt(a,16),o=parseInt(o,16),c=parseIn
t(c,16)),t(a,o,c))}function at(n,t,e){var
r,i,u=Math.min(n/=255,t/=255,e/=255),a=Math.max(n,t,e),o=a-u,c=(a+u)/2;return
o?(i=.5>c?o/(a+u):o/(2-a-u),r=n==a?(t-e)/o+(e>t?6:0):t==a?(e-n)/o+2:(n-t)/o+4,r*=60):(r=0/0,i=c>0&&1>c?0:r),F(r,i,c)}function
ot(n,t,e){n=ct(n),t=ct(t),e=ct(e);var
r=nt((.4124564*n+.3575761*t+.1804375*e)/no),i=nt((.2126729*n+.7151522*t+.072175*e)/to),u=nt((.0193339*n+.119192*t+.9503041*e)/eo);return
W(116*i-16,500*(r-i),200*(i-u))}function
ct(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function lt(n){var
t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function
ft(n){return"function"==typeof n?n:function(){return n}}function st(n){return
n}function ht(n){return function(t,e,r){return
2===arguments.length&&"function"==typeof
e&&(r=e,e=null),gt(t,e,n,r)}}function gt(n,t,e,r){function i(){var
n,t=c.status;if(!t&&c.responseText||t>=200&&300>t||304===t){try{n=e.call(u,c)}catch(r){return
a.error.call(u,r),void 0}a.load.call
(u,n)}else a.error.call(u,c)}var
u={},a=va.dispatch("progress","load","error"),o={},c=new
XMLHttpRequest,l=null;return!xa.XDomainRequest||"withCredentials"in
c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in
c?c.onload=c.onerror=i:c.onreadystatechange=function(){c.readyState>3&&i()},c.onprogress=function(n){var
t=va.event;va.event=n;try{a.progress.call(u,c)}finally{va.event=t}},u.header=function(n,t){return
n=(n+"").toLowerCase(),arguments.length<2?o[n]:(null==t?delete
o[n]:o[n]=t+"",u)},u.mimeType=function(n){return
arguments.length?(t=null==n?null:n+"",u):t},u.responseType=function(n){return
arguments.length?(l=n,u):l},u.response=function(n){return
e=n,u},["get","post"].forEach(function(n){u[n]=function(){return
u.send.apply(u,[n].concat(Na(arguments)))}}),u.send=function(e,r,i){if(2===arguments.length&&"function"==typeof
r&&(i=r,r=null),c.open(e,n,!0),null==t||"accept"in
o||(o.accept=t+",*/*"),c.setRequestHeader)for(var a in
o)c.setRequestHeader(a,o[a]);r
eturn
null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=i&&u.on("error",i).on("load",function(n){i(null,n)}),c.send(null==r?null:r),u},u.abort=function(){return
c.abort(),u},va.rebind(u,a,"on"),null==r?u:u.get(pt(r))}function pt(n){return
1===n.length?function(t,e){n(null==t?e:null)}:n}function dt(){var
n=mt(),t=vt()-n;t>24?(isFinite(t)&&(clearTimeout(lo),lo=setTimeout(dt,t)),co=0):(co=1,fo(dt))}function
mt(){for(var
n=Date.now(),t=ao;t;)n>=t.time&&(t.flush=t.callback(n-t.time)),t=t.next;return
n}function vt(){for(var
n,t=ao,e=1/0;t;)t.flush?t=n?n.next=t.next:ao=t.next:(t.time<e&&(e=t.time),t=(n=t).next);return
oo=n,e}function yt(n,t){var
e=Math.pow(10,3*Math.abs(8-t));return{scale:t>8?function(n){return
n/e}:function(n){return n*e},symbol:n}}function Mt(n,t){return
t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function xt(n){return n+""}function
bt(){}function _t(n,t,e){var r=e.s=n+t,i=r-n,u=r-i;e.t=n-u+(t-i)}function
wt(n,t){n&&_o.hasOwnProper
ty(n.type)&&_o[n.type](n,t)}function St(n,t,e){var
r,i=-1,u=n.length-e;for(t.lineStart();++i<u;)r=n[i],t.point(r[0],r[1]);t.lineEnd()}function
Et(n,t){var
e=-1,r=n.length;for(t.polygonStart();++e<r;)St(n[e],t,1);t.polygonEnd()}function
kt(){function n(n,t){n*=Ja,t=t*Ja/2+Ba/4;var
e=n-r,a=Math.cos(t),o=Math.sin(t),c=u*o,l=i*a+c*Math.cos(e),f=c*Math.sin(e);So.add(Math.atan2(f,l)),r=n,i=a,u=o}var
t,e,r,i,u;Eo.point=function(a,o){Eo.point=n,r=(t=a)*Ja,i=Math.cos(o=(e=o)*Ja/2+Ba/4),u=Math.sin(o)},Eo.lineEnd=function(){n(t,e)}}function
At(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
Nt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function
qt(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
Tt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function
Ct(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function zt(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
Dt(n){return[Math.atan2(n[1],n[0]),U(
n[2])]}function jt(n,t){return
Math.abs(n[0]-t[0])<$a&&Math.abs(n[1]-t[1])<$a}function Lt(n,t){n*=Ja;var
e=Math.cos(t*=Ja);Ht(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function
Ht(n,t,e){++ko,No+=(n-No)/ko,qo+=(t-qo)/ko,To+=(e-To)/ko}function Ft(){function
n(n,i){n*=Ja;var
u=Math.cos(i*=Ja),a=u*Math.cos(n),o=u*Math.sin(n),c=Math.sin(i),l=Math.atan2(Math.sqrt((l=e*c-r*o)*l+(l=r*a-t*c)*l+(l=t*o-e*a)*l),t*a+e*o+r*c);Ao+=l,Co+=l*(t+(t=a)),zo+=l*(e+(e=o)),Do+=l*(r+(r=c)),Ht(t,e,r)}var
t,e,r;Fo.point=function(i,u){i*=Ja;var
a=Math.cos(u*=Ja);t=a*Math.cos(i),e=a*Math.sin(i),r=Math.sin(u),Fo.point=n,Ht(t,e,r)}}function
Pt(){Fo.point=Lt}function Ot(){function n(n,t){n*=Ja;var
e=Math.cos(t*=Ja),a=e*Math.cos(n),o=e*Math.sin(n),c=Math.sin(t),l=i*c-u*o,f=u*a-r*c,s=r*o-i*a,h=Math.sqrt(l*l+f*f+s*s),g=r*a+i*o+u*c,p=h&&-Y(g)/h,d=Math.atan2(h,g);jo+=p*l,Lo+=p*f,Ho+=p*s,Ao+=d,Co+=d*(r+(r=a)),zo+=d*(i+(i=o)),Do+=d*(u+(u=c)),Ht(r,i,u)}var
t,e,r,i,u;Fo.point=function(a,o){t=a,e=o,Fo.point=n,a*=Ja;
var
c=Math.cos(o*=Ja);r=c*Math.cos(a),i=c*Math.sin(a),u=Math.sin(o),Ht(r,i,u)},Fo.lineEnd=function(){n(t,e),Fo.lineEnd=Pt,Fo.point=Lt}}function
Rt(){return!0}function Yt(n,t,e,r,i){var
u=[],a=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var
t,e=n[0],r=n[t];if(jt(e,r)){i.lineStart();for(var
o=0;t>o;++o)i.point((e=n[o])[0],e[1]);return i.lineEnd(),void 0}var
c={point:e,points:n,other:null,visited:!1,entry:!0,subject:!0},l={point:e,points:[e],other:c,visited:!1,entry:!1,subject:!1};c.other=l,u.push(c),a.push(l),c={point:r,points:[r],other:null,visited:!1,entry:!1,subject:!0},l={point:r,points:[r],other:c,visited:!1,entry:!0,subject:!1},c.other=l,u.push(c),a.push(l)}}),a.sort(t),Ut(u),Ut(a),u.length){if(e)for(var
o=1,c=!e(a[0].point),l=a.length;l>o;++o)a[o].entry=c=!c;for(var
f,s,h,g=u[0];;){for(f=g;f.visited;)if((f=f.next)===g)return;s=f.points,i.lineStart();do{if(f.visited=f.other.visited=!0,f.entry){if(f.subject)for(var
o=0;o<s.length;o++)i.point((h=s[o])[0],h[1]);els
e r(f.point,f.next.point,1,i);f=f.next}else{if(f.subject){s=f.prev.points;for(var
o=s.length;--o>=0;)i.point((h=s[o])[0],h[1])}else
r(f.point,f.prev.point,-1,i);f=f.prev}f=f.other,s=f.points}while(!f.visited);i.lineEnd()}}}function
Ut(n){if(t=n.length){for(var
t,e,r=0,i=n[0];++r<t;)i.next=e=n[r],e.prev=i,i=e;i.next=e=n[0],e.prev=i}}function
It(n,t,e,r){return function(i){function u(t,e){n(t,e)&&i.point(t,e)}function
a(n,t){d.point(n,t)}function o(){m.point=a,d.lineStart()}function
c(){m.point=u,d.lineEnd()}function l(n,t){y.point(n,t),p.push([n,t])}function
f(){y.lineStart(),p=[]}function s(){l(p[0][0],p[0][1]),y.lineEnd();var
n,t=y.clean(),e=v.buffer(),r=e.length;if(p.pop(),g.push(p),p=null,r){if(1&t){n=e[0];var
u,r=n.length-1,a=-1;for(i.lineStart();++a<r;)i.point((u=n[a])[0],u[1]);return
i.lineEnd(),void
0}r>1&&2&t&&e.push(e.pop().concat(e.shift())),h.push(e.filter(Vt))}}var
h,g,p,d=t(i),m={point:u,lineStart:o,lineEnd:c,polygonStart:function(){m.point=l,m.lineStart=f,m.lin
eEnd=s,h=[],g=[],i.polygonStart()},polygonEnd:function(){m.point=u,m.lineStart=o,m.lineEnd=c,h=va.merge(h),h.length?Yt(h,Zt,null,e,i):r(g)&&(i.lineStart(),e(null,null,1,i),i.lineEnd()),i.polygonEnd(),h=g=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},v=Xt(),y=t(v);return
m}}function Vt(n){return n.length>1}function Xt(){var
n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:f,buffer:function(){var
e=t;return
t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function
Zt(n,t){return((n=n.point)[0]<0?n[1]-Ba/2-$a:Ba/2-n[1])-((t=t.point)[0]<0?t[1]-Ba/2-$a:Ba/2-t[1])}function
Bt(n,t){var
e=n[0],r=n[1],i=[Math.sin(e),-Math.cos(e),0],u=0,a=!1,o=!1,c=0;So.reset();for(var
l=0,f=t.length;f>l;++l){var s=t[l],h=s.length;if(h){for(var
g=s[0],p=g[0],d=g[1]/2+Ba/4,m=Math.sin(d),v=Math.cos(d),y=1;;){y===h&&(y=0),n=s[y];var
M=n[0],x=n[1]/2+Ba/4,b=Math.sin(x),_=Math.co
s(x),w=M-p,S=Math.abs(w)>Ba,E=m*b;if(So.add(Math.atan2(E*Math.sin(w),v*_+E*Math.cos(w))),Math.abs(x)<$a&&(o=!0),u+=S?w+(w>=0?2:-2)*Ba:w,S^p>=e^M>=e){var
k=qt(At(g),At(n));zt(k);var A=qt(i,k);zt(A);var
N=(S^w>=0?-1:1)*U(A[2]);r>N&&(c+=S^w>=0?1:-1)}if(!y++)break;p=M,m=b,v=_,g=n}Math.abs(u)>$a&&(a=!0)}}return(!o&&!a&&0>So||-$a>u)^1&c}function
$t(n){var
t,e=0/0,r=0/0,i=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(u,a){var
o=u>0?Ba:-Ba,c=Math.abs(u-e);Math.abs(c-Ba)<$a?(n.point(e,r=(r+a)/2>0?Ba/2:-Ba/2),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(o,r),n.point(u,r),t=0):i!==o&&c>=Ba&&(Math.abs(e-i)<$a&&(e-=i*$a),Math.abs(u-o)<$a&&(u-=o*$a),r=Wt(e,r,u,a),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(o,r),t=0),n.point(e=u,r=a),i=o},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return
2-t}}}function Wt(n,t,e,r){var i,u,a=Math.sin(n-e);return
Math.abs(a)>$a?Math.atan((Math.sin(t)*(u=Math.cos(r))*Math.sin(e)-Math.sin(r)*(i=Math.cos(t))*Math.sin(n))/(
i*u*a)):(t+r)/2}function Jt(n,t,e,r){var
i;if(null==n)i=e*Ba/2,r.point(-Ba,i),r.point(0,i),r.point(Ba,i),r.point(Ba,0),r.point(Ba,-i),r.point(0,-i),r.point(-Ba,-i),r.point(-Ba,0),r.point(-Ba,i);else
if(Math.abs(n[0]-t[0])>$a){var
u=(n[0]<t[0]?1:-1)*Ba;i=e*u/2,r.point(-u,i),r.point(0,i),r.point(u,i)}else
r.point(t[0],t[1])}function Gt(n){return Bt(Oo,n)}function Kt(n){function t(n,t){return
Math.cos(n)*Math.cos(t)>a}function e(n){var
e,u,a,c,f;return{lineStart:function(){c=a=!1,f=1},point:function(s,h){var
g,p=[s,h],d=t(s,h),m=o?d?0:i(s,h):d?i(s+(0>s?Ba:-Ba),h):0;if(!e&&(c=a=d)&&n.lineStart(),d!==a&&(g=r(e,p),(jt(e,g)||jt(p,g))&&(p[0]+=$a,p[1]+=$a,d=t(p[0],p[1]))),d!==a)f=0,d?(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(l&&e&&o^d){var
v;m&u||!(v=r(p,e,!0))||(f=0,o?(n.lineStart(),n.point(v[0][0],v[0][1]),n.point(v[1][0],v[1][1]),n.lineEnd()):(n.point(v[1][0],v[1][1]),n.lineEnd(),n.lineStart(),n.point(v[0][0],v[0][1])))}!d||e
&&jt(e,p)||n.point(p[0],p[1]),e=p,a=d,u=m},lineEnd:function(){a&&n.lineEnd(),e=null},clean:function(){return
f|(c&&a)<<1}}}function r(n,t,e){var
r=At(n),i=At(t),u=[1,0,0],o=qt(r,i),c=Nt(o,o),l=o[0],f=c-l*l;if(!f)return!e&&n;var
s=a*c/f,h=-a*l/f,g=qt(u,o),p=Ct(u,s),d=Ct(o,h);Tt(p,d);var
m=g,v=Nt(p,m),y=Nt(m,m),M=v*v-y*(Nt(p,p)-1);if(!(0>M)){var
x=Math.sqrt(M),b=Ct(m,(-v-x)/y);if(Tt(b,p),b=Dt(b),!e)return b;var
_,w=n[0],S=t[0],E=n[1],k=t[1];w>S&&(_=w,w=S,S=_);var
A=S-w,N=Math.abs(A-Ba)<$a,q=N||$a>A;if(!N&&E>k&&(_=E,E=k,k=_),q?N?E+k>0^b[1]<(Math.abs(b[0]-w)<$a?E:k):E<=b[1]&&b[1]<=k:A>Ba^(w<=b[0]&&b[0]<=S)){var
T=Ct(m,(-v+x)/y);return Tt(T,p),[b,Dt(T)]}}}function i(t,e){var
r=o?n:Ba-n,i=0;return-r>t?i|=1:t>r&&(i|=2),-r>e?i|=4:e>r&&(i|=8),i}function
u(n){return Bt(c,n)}var
a=Math.cos(n),o=a>0,c=[n,0],l=Math.abs(a)>$a,f=we(n,6*Ja);return
It(t,e,f,u)}function Qt(n,t,e,r){function i(r,i){return
Math.abs(r[0]-n)<$a?i>0?0:3:Math.abs(r[0]-e)<$a?i>0?2:1:Math.abs(r[1]-t)<$a?i>0?1:0:i>0?3
:2}function u(n,t){return a(n.point,t.point)}function a(n,t){var e=i(n,1),r=i(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]}function o(i,u){var
a=u[0]-i[0],o=u[1]-i[1],c=[0,1];return
Math.abs(a)<$a&&Math.abs(o)<$a?n<=i[0]&&i[0]<=e&&t<=i[1]&&i[1]<=r:ne(n-i[0],a,c)&&ne(i[0]-e,-a,c)&&ne(t-i[1],o,c)&&ne(i[1]-r,-o,c)?(c[1]<1&&(u[0]=i[0]+c[1]*a,u[1]=i[1]+c[1]*o),c[0]>0&&(i[0]+=c[0]*a,i[1]+=c[0]*o),!0):!1}return
function(c){function l(u){var a=i(u,-1),o=f([0===a||3===a?n:e,a>1?r:t]);return
o}function f(n){for(var t=0,e=M.length,r=n[1],i=0;e>i;++i)for(var
u,a=1,o=M[i],c=o.length,l=o[0];c>a;++a)u=o[a],l[1]<=r?u[1]>r&&s(l,u,n)>0&&++t:u[1]<=r&&s(l,u,n)<0&&--t,l=u;return
0!==t}function s(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(e[0]-n[0])*(t[1]-n[1])}function
h(u,o,c,l){var f=0,s=0;if(null==u||(f=i(u,c))!==(s=i(o,c))||a(u,o)<0^c>0){do
l.point(0===f||3===f?n:e,f>1?r:t);while((f=(f+c+4)%4)!==s)}else
l.point(o[0],o[1])}function g(i,u){return i>=n&&e>=i&&u>=t&
&r>=u}function p(n,t){g(n,t)&&c.point(n,t)}function
d(){T.point=v,M&&M.push(x=[]),A=!0,k=!1,S=E=0/0}function
m(){y&&(v(b,_),w&&k&&q.rejoin(),y.push(q.buffer())),T.point=p,k&&c.lineEnd()}function
v(n,t){n=Math.max(-Ro,Math.min(Ro,n)),t=Math.max(-Ro,Math.min(Ro,t));var
e=g(n,t);if(M&&x.push([n,t]),A)b=n,_=t,w=e,A=!1,e&&(c.lineStart(),c.point(n,t));else
if(e&&k)c.point(n,t);else{var
r=[S,E],i=[n,t];o(r,i)?(k||(c.lineStart(),c.point(r[0],r[1])),c.point(i[0],i[1]),e||c.lineEnd()):e&&(c.lineStart(),c.point(n,t))}S=n,E=t,k=e}var
y,M,x,b,_,w,S,E,k,A,N=c,q=Xt(),T={point:p,lineStart:d,lineEnd:m,polygonStart:function(){c=q,y=[],M=[]},polygonEnd:function(){c=N,(y=va.merge(y)).length?(c.polygonStart(),Yt(y,u,l,h,c),c.polygonEnd()):f([n,t])&&(c.polygonStart(),c.lineStart(),h(null,null,1,c),c.lineEnd(),c.polygonEnd()),y=M=x=null}};return
T}}function ne(n,t,e){if(Math.abs(t)<$a)return 0>=n;var
r=n/t;if(t>0){if(r>e[1])return!1;r>e[0]&&(e[0]=r)}else{if(r<e[0])return!1;r<e[1]&&(e[1]=r)}return!
0}function te(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 ee(n){var
t=0,e=Ba/3,r=me(n),i=r(t,e);return i.parallels=function(n){return
arguments.length?r(t=n[0]*Ba/180,e=n[1]*Ba/180):[180*(t/Ba),180*(e/Ba)]},i}function
re(n,t){function e(n,t){var
e=Math.sqrt(u-2*i*Math.sin(t))/i;return[e*Math.sin(n*=i),a-e*Math.cos(n)]}var
r=Math.sin(n),i=(r+Math.sin(t))/2,u=1+r*(2*i-r),a=Math.sqrt(u)/i;return
e.invert=function(n,t){var
e=a-t;return[Math.atan2(n,e)/i,U((u-(n*n+e*e)*i*i)/(2*i))]},e}function ie(){function
n(n,t){Uo+=i*n-r*t,r=n,i=t}var
t,e,r,i;Bo.point=function(u,a){Bo.point=n,t=r=u,e=i=a},Bo.lineEnd=function(){n(t,e)}}function
ue(n,t){Io>n&&(Io=n),n>Xo&&(Xo=n),Vo>t&&(Vo=t),t>Zo&&(Zo=t)}function
ae(){function n(n,t){a.push("M",n,",",t,u)}function
t(n,t){a.push("M",n,",",t),o.point=e}function
e(n,t){a.push("L",n,",",t)}function r(){o.point=n}function
i(){a.push("Z"
)}var
u=oe(4.5),a=[],o={point:n,lineStart:function(){o.point=t},lineEnd:r,polygonStart:function(){o.lineEnd=i},polygonEnd:function(){o.lineEnd=r,o.point=n},pointRadius:function(n){return
u=oe(n),o},result:function(){if(a.length){var n=a.join("");return
a=[],n}}};return o}function
oe(n){return"m0,"+n+"a"+n+","+n+" 0 1,1
0,"+-2*n+"a"+n+","+n+" 0 1,1
0,"+2*n+"z"}function ce(n,t){No+=n,qo+=t,++To}function le(){function
n(n,r){var
i=n-t,u=r-e,a=Math.sqrt(i*i+u*u);Co+=a*(t+n)/2,zo+=a*(e+r)/2,Do+=a,ce(t=n,e=r)}var
t,e;Wo.point=function(r,i){Wo.point=n,ce(t=r,e=i)}}function fe(){Wo.point=ce}function
se(){function n(n,t){var
e=n-r,u=t-i,a=Math.sqrt(e*e+u*u);Co+=a*(r+n)/2,zo+=a*(i+t)/2,Do+=a,a=i*n-r*t,jo+=a*(r+n),Lo+=a*(i+t),Ho+=3*a,ce(r=n,i=t)}var
t,e,r,i;Wo.point=function(u,a){Wo.point=n,ce(t=r=u,e=i=a)},Wo.lineEnd=function(){n(t,e)}}function
he(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,a,0,2*Ba)}function
e(t,e){n.moveTo(t,e),o.point=r}function r(t,e){n.lineTo(t,e)}function i(){o.p
oint=t}function u(){n.closePath()}var
a=4.5,o={point:t,lineStart:function(){o.point=e},lineEnd:i,polygonStart:function(){o.lineEnd=u},polygonEnd:function(){o.lineEnd=i,o.point=t},pointRadius:function(n){return
a=n,o},result:f};return o}function ge(n){function t(t){function
r(e,r){e=n(e,r),t.point(e[0],e[1])}function i(){M=0/0,S.point=a,t.lineStart()}function
a(r,i){var
a=At([r,i]),o=n(r,i);e(M,x,y,b,_,w,M=o[0],x=o[1],y=r,b=a[0],_=a[1],w=a[2],u,t),t.point(M,x)}function
o(){S.point=r,t.lineEnd()}function c(){i(),S.point=l,S.lineEnd=f}function
l(n,t){a(s=n,h=t),g=M,p=x,d=b,m=_,v=w,S.point=a}function
f(){e(M,x,y,b,_,w,g,p,s,d,m,v,u,t),S.lineEnd=o,o()}var
s,h,g,p,d,m,v,y,M,x,b,_,w,S={point:r,lineStart:i,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=i}};return
S}function e(t,u,a,o,c,l,f,s,h,g,p,d,m,v){var
y=f-t,M=s-u,x=y*y+M*M;if(x>4*r&&m--){var
b=o+g,_=c+p,w=l+d,S=Math.sqrt(b*b+_*_+w*w),E=Math.asin(w/=S),k=Math.
abs(Math.abs(w)-1)<$a?(a+h)/2:Math.atan2(_,b),A=n(k,E),N=A[0],q=A[1],T=N-t,C=q-u,z=M*T-y*C;(z*z/x>r||Math.abs((y*T+M*C)/x-.5)>.3||i>o*g+c*p+l*d)&&(e(t,u,a,o,c,l,N,q,k,b/=S,_/=S,w,m,v),v.point(N,q),e(N,q,k,b,_,w,f,s,h,g,p,d,m,v))}}var
r=.5,i=Math.cos(30*Ja),u=16;return t.precision=function(n){return
arguments.length?(u=(r=n*n)>0&&16,t):Math.sqrt(r)},t}function pe(n){var
t=ge(function(t,e){return n([t*Ga,e*Ga])});return function(n){return
n=t(n),{point:function(t,e){n.point(t*Ja,e*Ja)},sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}}function
de(n){return me(function(){return n})()}function me(n){function t(n){return
n=o(n[0]*Ja,n[1]*Ja),[n[0]*h+c,l-n[1]*h]}function e(n){return
n=o.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Ga,n[1]*Ga]}function
r(){o=te(a=Me(v,y,M),u);var n=u(d,m);return c=g-n[0]*h,l=p+n[1]*h,i()}function i(){return
f&&(f.valid=!1,f=nu
ll),t}var u,a,o,c,l,f,s=ge(function(n,t){return
n=u(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,d=0,m=0,v=0,y=0,M=0,x=Po,b=st,_=null,w=null;return
t.stream=function(n){return
f&&(f.valid=!1),f=ve(a,x(s(b(n)))),f.valid=!0,f},t.clipAngle=function(n){return
arguments.length?(x=null==n?(_=n,Po):Kt((_=+n)*Ja),i()):_},t.clipExtent=function(n){return
arguments.length?(w=n,b=null==n?st:Qt(n[0][0],n[0][1],n[1][0],n[1][1]),i()):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?(d=n[0]%360*Ja,m=n[1]%360*Ja,r()):[d*Ga,m*Ga]},t.rotate=function(n){return
arguments.length?(v=n[0]%360*Ja,y=n[1]%360*Ja,M=n.length>2?n[2]%360*Ja:0,r()):[v*Ga,y*Ga,M*Ga]},va.rebind(t,s,"precision"),function(){return
u=n.apply(this,arguments),t.invert=u.invert&&e,r()}}function
ve(n,t){return{point:function(e,r){r=n(e*Ja,r*Ja),e=r[0],t.point(e>Ba?e-2*Ba:-Ba>e?e+2*Ba:e,r[1])},sphere:
function(){t.sphere()},lineStart:function(){t.lineStart()},lineEnd:function(){t.lineEnd()},polygonStart:function(){t.polygonStart()},polygonEnd:function(){t.polygonEnd()}}}function
ye(n,t){return[n,t]}function Me(n,t,e){return
n?t||e?te(be(n),_e(t,e)):be(n):t||e?_e(t,e):ye}function xe(n){return function(t,e){return
t+=n,[t>Ba?t-2*Ba:-Ba>t?t+2*Ba:t,e]}}function be(n){var t=xe(n);return
t.invert=xe(-n),t}function _e(n,t){function e(n,t){var
e=Math.cos(t),o=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),f=l*r+o*i;return[Math.atan2(c*u-f*a,o*r-l*i),U(f*u+c*a)]}var
r=Math.cos(n),i=Math.sin(n),u=Math.cos(t),a=Math.sin(t);return e.invert=function(n,t){var
e=Math.cos(t),o=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),f=l*u-c*a;return[Math.atan2(c*u+l*a,o*r+f*i),U(f*r-o*i)]},e}function
we(n,t){var e=Math.cos(n),r=Math.sin(n);return
function(i,u,a,o){null!=i?(i=Se(e,i),u=Se(e,u),(a>0?u>i:i>u)&&(i+=2*a*Ba)):(i=n+2*a*Ba,u=n);for(var
c,l=a*t,f=i;a>0?f>u:u>f;f-=l)o.point((c=Dt([e,-r*Math.cos(f
),-r*Math.sin(f)]))[0],c[1])}}function Se(n,t){var e=At(t);e[0]-=n,zt(e);var
r=Y(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-$a)%(2*Math.PI)}function Ee(n,t,e){var
r=va.range(n,t-$a,e).concat(t);return function(n){return
r.map(function(t){return[n,t]})}}function ke(n,t,e){var
r=va.range(n,t-$a,e).concat(t);return function(n){return
r.map(function(t){return[t,n]})}}function Ae(n){return n.source}function Ne(n){return
n.target}function qe(n,t,e,r){var
i=Math.cos(t),u=Math.sin(t),a=Math.cos(r),o=Math.sin(r),c=i*Math.cos(n),l=i*Math.sin(n),f=a*Math.cos(e),s=a*Math.sin(e),h=2*Math.asin(Math.sqrt(X(r-t)+i*a*X(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*f,i=e*l+t*s,a=e*u+t*o;return[Math.atan2(i,r)*Ga,Math.atan2(a,Math.sqrt(r*r+i*i))*Ga]}:function(){return[n*Ga,t*Ga]};return
p.distance=h,p}function Te(){function n(n,i){var
u=Math.sin(i*=Ja),a=Math.cos(i),o=Math.abs((n*=Ja)-t),c=Math.cos(o);Jo+=Math.atan2(Math.sqrt((o=a*Math.sin(o))*o+(o=r*u-e*a
*c)*o),e*u+r*a*c),t=n,e=u,r=a}var
t,e,r;Go.point=function(i,u){t=i*Ja,e=Math.sin(u*=Ja),r=Math.cos(u),Go.point=n},Go.lineEnd=function(){Go.point=Go.lineEnd=f}}function
Ce(n,t){function e(t,e){var
r=Math.cos(t),i=Math.cos(e),u=n(r*i);return[u*i*Math.sin(t),u*Math.sin(e)]}return
e.invert=function(n,e){var
r=Math.sqrt(n*n+e*e),i=t(r),u=Math.sin(i),a=Math.cos(i);return[Math.atan2(n*u,r*a),Math.asin(r&&e*u/r)]},e}function
ze(n,t){function e(n,t){var
e=Math.abs(Math.abs(t)-Ba/2)<$a?0:a/Math.pow(i(t),u);return[e*Math.sin(u*n),a-e*Math.cos(u*n)]}var
r=Math.cos(n),i=function(n){return
Math.tan(Ba/4+n/2)},u=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(i(t)/i(n)),a=r*Math.pow(i(n),u)/u;return
u?(e.invert=function(n,t){var
e=a-t,r=R(u)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/u,2*Math.atan(Math.pow(a/r,1/u))-Ba/2]},e):je}function
De(n,t){function e(n,t){var e=u-t;return[e*Math.sin(i*n),u-e*Math.cos(i*n)]}var
r=Math.cos(n),i=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),u=r/i+n;return M
ath.abs(i)<$a?ye:(e.invert=function(n,t){var
e=u-t;return[Math.atan2(n,e)/i,u-R(i)*Math.sqrt(n*n+e*e)]},e)}function
je(n,t){return[n,Math.log(Math.tan(Ba/4+t/2))]}function Le(n){var
t,e=de(n),r=e.scale,i=e.translate,u=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=i.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var
a=u.apply(e,arguments);if(a===e){if(t=null==n){var
o=Ba*r(),c=i();u([[c[0]-o,c[1]-o],[c[0]+o,c[1]+o]])}}else t&&(a=null);return
a},e.clipExtent(null)}function He(n,t){var
e=Math.cos(t)*Math.sin(n);return[Math.log((1+e)/(1-e))/2,Math.atan2(Math.tan(t),Math.cos(n))]}function
Fe(n){function t(t){function a(){l.push("M",u(n(f),o))}for(var
c,l=[],f=[],s=-1,h=t.length,g=ft(e),p=ft(r);++s<h;)i.call(this,c=t[s],s)?f.push([+g.call(this,c,s),+p.call(this,c,s)]):f.length&&(a(),f=[]);return
f.length&&a(),l.length?l.join(""):null}var e=Pe,r=Oe,i=Rt,u=Re,a
=u.key,o=.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?(i=n,t):i},t.interpolate=function(n){return
arguments.length?(a="function"==typeof
n?u=n:(u=rc.get(n)||Re).key,t):a},t.tension=function(n){return
arguments.length?(o=n,t):o},t}function Pe(n){return n[0]}function Oe(n){return
n[1]}function Re(n){return n.join("L")}function Ye(n){return
Re(n)+"Z"}function Ue(n){for(var
t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return
e>1&&i.push("H",r[0]),i.join("")}function Ie(n){for(var
t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("V",(r=n[t])[1],"H",r[0]);return
i.join("")}function Ve(n){for(var
t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r=n[t])[0],"V",r[1]);return
i.join("")}function Xe(n,t){return
n.length<4?Re(n):n[1]+$e(n.slice(1,n.length-1),We(n,t))}function Ze(n,t){return
n.length<3?Re(n):n[0]+$e((n.
push(n[0]),n),We([n[n.length-2]].concat(n,[n[1]]),t))}function Be(n,t){return
n.length<3?Re(n):n[0]+$e(n,We(n,t))}function
$e(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return
Re(n);var
e=n.length!=t.length,r="",i=n[0],u=n[1],a=t[0],o=a,c=1;if(e&&(r+="Q"+(u[0]-2*a[0]/3)+","+(u[1]-2*a[1]/3)+","+u[0]+","+u[1],i=n[1],c=2),t.length>1){o=t[1],u=n[c],c++,r+="C"+(i[0]+a[0])+","+(i[1]+a[1])+","+(u[0]-o[0])+","+(u[1]-o[1])+","+u[0]+","+u[1];for(var
l=2;l<t.length;l++,c++)u=n[c],o=t[l],r+="S"+(u[0]-o[0])+","+(u[1]-o[1])+","+u[0]+","+u[1]}if(e){var
f=n[c];r+="Q"+(u[0]+2*o[0]/3)+","+(u[1]+2*o[1]/3)+","+f[0]+","+f[1]}return
r}function We(n,t){for(var
e,r=[],i=(1-t)/2,u=n[0],a=n[1],o=1,c=n.length;++o<c;)e=u,u=a,a=n[o],r.push([i*(a[0]-e[0]),i*(a[1]-e[1])]);return
r}function Je(n){if(n.length<3)return Re(n);var
t=1,e=n.length,r=n[0],i=r[0],u=r[1],a=[i,i,i,(r=n[1])[0]],o=[u,u,u,r[1]],c=[i,",",u];for(tr(c,a,o);++t<e;)r=n[t],a.shift(),a.push(r[0]),o.shift(),o.push(r[1]),tr(c,
a,o);for(t=-1;++t<2;)a.shift(),a.push(r[0]),o.shift(),o.push(r[1]),tr(c,a,o);return
c.join("")}function Ge(n){if(n.length<4)return Re(n);for(var
t,e=[],r=-1,i=n.length,u=[0],a=[0];++r<3;)t=n[r],u.push(t[0]),a.push(t[1]);for(e.push(nr(ac,u)+","+nr(ac,a)),--r;++r<i;)t=n[r],u.shift(),u.push(t[0]),a.shift(),a.push(t[1]),tr(e,u,a);return
e.join("")}function Ke(n){for(var
t,e,r=-1,i=n.length,u=i+4,a=[],o=[];++r<4;)e=n[r%i],a.push(e[0]),o.push(e[1]);for(t=[nr(ac,a),",",nr(ac,o)],--r;++r<u;)e=n[r%i],a.shift(),a.push(e[0]),o.shift(),o.push(e[1]),tr(t,a,o);return
t.join("")}function Qe(n,t){var e=n.length-1;if(e)for(var
r,i,u=n[0][0],a=n[0][1],o=n[e][0]-u,c=n[e][1]-a,l=-1;++l<=e;)r=n[l],i=l/e,r[0]=t*r[0]+(1-t)*(u+i*o),r[1]=t*r[1]+(1-t)*(a+i*c);return
Je(n)}function nr(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function
tr(n,t,e){n.push("C",nr(ic,t),",",nr(ic,e),",",nr(uc,t),",",nr(uc,e),",",nr(ac,t),",",nr(ac,e))}function
er(n,t){return(t[1]-n[1])/(t[0]-n[0])}function rr(n){f
or(var
t=0,e=n.length-1,r=[],i=n[0],u=n[1],a=r[0]=er(i,u);++t<e;)r[t]=(a+(a=er(i=u,u=n[t+1])))/2;return
r[t]=a,r}function ir(n){for(var
t,e,r,i,u=[],a=rr(n),o=-1,c=n.length-1;++o<c;)t=er(n[o],n[o+1]),Math.abs(t)<1e-6?a[o]=a[o+1]=0:(e=a[o]/t,r=a[o+1]/t,i=e*e+r*r,i>9&&(i=3*t/Math.sqrt(i),a[o]=i*e,a[o+1]=i*r));for(o=-1;++o<=c;)i=(n[Math.min(c,o+1)][0]-n[Math.max(0,o-1)][0])/(6*(1+a[o]*a[o])),u.push([i||0,a[o]*i||0]);
-return u}function ur(n){return n.length<3?Re(n):n[0]+$e(n,ir(n))}function
ar(n,t,e,r){var i,u,a,o,c,l,f;return
i=r[n],u=i[0],a=i[1],i=r[t],o=i[0],c=i[1],i=r[e],l=i[0],f=i[1],(f-a)*(o-u)-(c-a)*(l-u)>0}function
or(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
i=n[0],u=e[0],a=t[0]-i,o=r[0]-u,c=n[1],l=e[1],f=t[1]-c,s=r[1]-l,h=(o*(c-l)-s*(i-u))/(s*a-o*f);return[i+h*a,c+h*f]}function
lr(n,t){var
e={list:n.map(function(n,t){return{index:t,x:n[0],y:n[1]}}).sort(function(n,t){return
n.y<t.y?-1:n.y>t.y?1:n.x<t.x?-1:n.x>t.x?1:0}),bottomSite:null},r={list:[],leftEnd:null,rightEnd:null,init:function(){r.leftEnd=r.createHalfEdge(null,"l"),r.rightEnd=r.createHalfEdge(null,"l"),r.leftEnd.r=r.rightEnd,r.rightEnd.l=r.leftEnd,r.list.unshift(r.leftEnd,r.rightEnd)},createHalfEdge:function(n,t){return{edge:n,side:t,vertex:null,l:null,r:null}},insert:function(n,t){t.l=n,t.r=n.r,n.r.l=t,n.r=t},leftBound:function(n){var
t=r.leftEnd;do t=t.r;while(t!=r.rightEnd
&&i.rightOf(t,n));return
t=t.l},del:function(n){n.l.r=n.r,n.r.l=n.l,n.edge=null},right:function(n){return
n.r},left:function(n){return n.l},leftRegion:function(n){return
null==n.edge?e.bottomSite:n.edge.region[n.side]},rightRegion:function(n){return
null==n.edge?e.bottomSite:n.edge.region[oc[n.side]]}},i={bisect:function(n,t){var
e={region:{l:n,r:t},ep:{l:null,r:null}},r=t.x-n.x,i=t.y-n.y,u=r>0?r:-r,a=i>0?i:-i;return
e.c=n.x*r+n.y*i+.5*(r*r+i*i),u>a?(e.a=1,e.b=i/r,e.c/=r):(e.b=1,e.a=r/i,e.c/=i),e},intersect:function(n,t){var
e=n.edge,r=t.edge;if(!e||!r||e.region.r==r.region.r)return null;var
i=e.a*r.b-e.b*r.a;if(Math.abs(i)<1e-10)return null;var
u,a,o=(e.c*r.b-r.c*e.b)/i,c=(r.c*e.a-e.c*r.a)/i,l=e.region.r,f=r.region.r;l.y<f.y||l.y==f.y&&l.x<f.x?(u=n,a=e):(u=t,a=r);var
s=o>=a.region.r.x;return
s&&"l"===u.side||!s&&"r"===u.side?null:{x:o,y:c}},rightOf:function(n,t){var
e=n.edge,r=e.region.r,i=t.x>r.x;if(i&&"l"===n.side)return
1;if(!i&&"r"===n.side)return 0;if(1===e.a){var u=t.
y-r.y,a=t.x-r.x,o=0,c=0;if(!i&&e.b<0||i&&e.b>=0?c=o=u>=e.b*a:(c=t.x+t.y*e.b>e.c,e.b<0&&(c=!c),c||(o=1)),!o){var
l=r.x-e.region.l.x;c=e.b*(a*a-u*u)<l*u*(1+2*a/l+e.b*e.b),e.b<0&&(c=!c)}}else{var
f=e.c-e.a*t.x,s=t.y-f,h=t.x-r.x,g=f-r.y;c=s*s>h*h+g*g}return"l"===n.side?c:!c},endPoint:function(n,e,r){n.ep[e]=r,n.ep[oc[e]]&&t(n)},distance:function(n,t){var
e=n.x-t.x,r=n.y-t.y;return
Math.sqrt(e*e+r*r)}},u={list:[],insert:function(n,t,e){n.vertex=t,n.ystar=t.y+e;for(var
r=0,i=u.list,a=i.length;a>r;r++){var
o=i[r];if(!(n.ystar>o.ystar||n.ystar==o.ystar&&t.x>o.vertex.x))break}i.splice(r,0,n)},del:function(n){for(var
t=0,e=u.list,r=e.length;r>t&&e[t]!=n;++t);e.splice(t,1)},empty:function(){return
0===u.list.length},nextEvent:function(n){for(var
t=0,e=u.list,r=e.length;r>t;++t)if(e[t]==n)return e[t+1];return
null},min:function(){var
n=u.list[0];return{x:n.vertex.x,y:n.ystar}},extractMin:function(){return
u.list.shift()}};r.init(),e.bottomSite=e.list.shift();for(var a,o,c,l,f,s,h,g,p,d,
m,v,y,M=e.list.shift();;)if(u.empty()||(a=u.min()),M&&(u.empty()||M.y<a.y||M.y==a.y&&M.x<a.x))o=r.leftBound(M),c=r.right(o),h=r.rightRegion(o),v=i.bisect(h,M),s=r.createHalfEdge(v,"l"),r.insert(o,s),d=i.intersect(o,s),d&&(u.del(o),u.insert(o,d,i.distance(d,M))),o=s,s=r.createHalfEdge(v,"r"),r.insert(o,s),d=i.intersect(s,c),d&&u.insert(s,d,i.distance(d,M)),M=e.list.shift();else{if(u.empty())break;o=u.extractMin(),l=r.left(o),c=r.right(o),f=r.right(c),h=r.leftRegion(o),g=r.rightRegion(c),m=o.vertex,i.endPoint(o.edge,o.side,m),i.endPoint(c.edge,c.side,m),r.del(o),u.del(c),r.del(c),y="l",h.y>g.y&&(p=h,h=g,g=p,y="r"),v=i.bisect(h,g),s=r.createHalfEdge(v,y),r.insert(l,s),i.endPoint(v,oc[y],m),d=i.intersect(l,s),d&&(u.del(l),u.insert(l,d,i.distance(d,h))),d=i.intersect(s,f),d&&u.insert(s,d,i.distance(d,h))}for(o=r.right(r.leftEnd);o!=r.rightEnd;o=r.right(o))t(o.edge)}function
fr(n){return n.x}function sr(n){return n.y}function
hr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}
function gr(n,t,e,r,i,u){if(!n(t,e,r,i,u)){var
a=.5*(e+i),o=.5*(r+u),c=t.nodes;c[0]&&gr(n,c[0],e,r,a,o),c[1]&&gr(n,c[1],a,r,i,o),c[2]&&gr(n,c[2],e,o,a,u),c[3]&&gr(n,c[3],a,o,i,u)}}function
pr(n,t){n=va.rgb(n),t=va.rgb(t);var e=n.r,r=n.g,i=n.b,u=t.r-e,a=t.g-r,o=t.b-i;return
function(n){return"#"+it(Math.round(e+u*n))+it(Math.round(r+a*n))+it(Math.round(i+o*n))}}function
dr(n){var
t=[n.a,n.b],e=[n.c,n.d],r=vr(t),i=mr(t,e),u=vr(yr(e,t,-i))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,i*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Ga,this.translate=[n.e,n.f],this.scale=[r,u],this.skew=u?Math.atan2(i,u)*Ga:0}function
mr(n,t){return n[0]*t[0]+n[1]*t[1]}function vr(n){var t=Math.sqrt(mr(n,n));return
t&&(n[0]/=t,n[1]/=t),t}function yr(n,t,e){return
n[0]+=e*t[0],n[1]+=e*t[1],n}function Mr(n,t){return t-=n=+n,function(e){return
n+t*e}}function xr(n,t){var
e,r=[],i=[],u=va.transform(n),a=va.transform(t),o=u.translate,c=a.translate,l=u.rotate,f=a.rotate,s=u.skew
,h=a.skew,g=u.scale,p=a.scale;return
o[0]!=c[0]||o[1]!=c[1]?(r.push("translate(",null,",",null,")"),i.push({i:1,x:Mr(o[0],c[0])},{i:3,x:Mr(o[1],c[1])})):c[0]||c[1]?r.push("translate("+c+")"):r.push(""),l!=f?(l-f>180?f+=360:f-l>180&&(l+=360),i.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:Mr(l,f)})):f&&r.push(r.pop()+"rotate("+f+")"),s!=h?i.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:Mr(s,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),i.push({i:e-4,x:Mr(g[0],p[0])},{i:e-2,x:Mr(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=i.length,function(n){for(var
t,u=-1;++u<e;)r[(t=i[u]).i]=t.x(n);return r.join("")}}function br(n,t){var
e,r={},i={};for(e in n)e in t?r[e]=Sr(e)(n[e],t[e]):i[e]=n[e];for(e in t)e in
n||(i[e]=t[e]);return function(n){for(e in r)i[e]=r[e](n);return i}}function _r(n,t){var
e,r,i,u,a,o=0,c=0,l=[],f=[];for(n+="",t+="",lc.lastIndex=0,r=0;e=lc.exec(t);++r)e.index&&l.push(t.substrin
g(o,c=e.index)),f.push({i:l.length,x:e[0]}),l.push(null),o=lc.lastIndex;for(o<t.length&&l.push(t.substring(o)),r=0,u=f.length;(e=lc.exec(n))&&u>r;++r)if(a=f[r],a.x==e[0]){if(a.i)if(null==l[a.i+1])for(l[a.i-1]+=a.x,l.splice(a.i,1),i=r+1;u>i;++i)f[i].i--;else
for(l[a.i-1]+=a.x+l[a.i+1],l.splice(a.i,2),i=r+1;u>i;++i)f[i].i-=2;else
if(null==l[a.i+1])l[a.i]=a.x;else
for(l[a.i]=a.x+l[a.i+1],l.splice(a.i+1,1),i=r+1;u>i;++i)f[i].i--;f.splice(r,1),u--,r--}else
a.x=Mr(parseFloat(e[0]),parseFloat(a.x));for(;u>r;)a=f.pop(),null==l[a.i+1]?l[a.i]=a.x:(l[a.i]=a.x+l[a.i+1],l.splice(a.i+1,1)),u--;return
1===l.length?null==l[0]?(a=f[0].x,function(n){return a(n)+""}):function(){return
t}:function(n){for(r=0;u>r;++r)l[(a=f[r]).i]=a.x(n);return
l.join("")}}function wr(n,t){for(var
e,r=va.interpolators.length;--r>=0&&!(e=va.interpolators[r](n,t)););return
e}function Sr(n){return"transform"==n?xr:wr}function Er(n,t){var
e,r=[],i=[],u=n.length,a=t.length,o=Math.min(n.length,t.length);for(e=0;o>e;++
e)r.push(wr(n[e],t[e]));for(;u>e;++e)i[e]=n[e];for(;a>e;++e)i[e]=t[e];return
function(n){for(e=0;o>e;++e)i[e]=r[e](n);return i}}function kr(n){return
function(t){return 0>=t?0:t>=1?1:n(t)}}function Ar(n){return function(t){return
1-n(1-t)}}function Nr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function
qr(n){return n*n}function Tr(n){return n*n*n}function Cr(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
zr(n){return function(t){return Math.pow(t,n)}}function Dr(n){return
1-Math.cos(n*Ba/2)}function jr(n){return Math.pow(2,10*(n-1))}function Lr(n){return
1-Math.sqrt(1-n*n)}function Hr(n,t){var e;return
arguments.length<2&&(t=.45),arguments.length?e=t/(2*Ba)*Math.asin(1/n):(n=1,e=t/4),function(r){return
1+n*Math.pow(2,10*-r)*Math.sin(2*(r-e)*Ba/t)}}function Fr(n){return
n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Pr(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
Or(n,t){n=va.hcl(n),t=va.hcl(t);var e=n.h,r=n.c,i=n.l,u=t.h-e,a=t.c-r,o=t.l-i;return
isNaN(a)&&(a=0,r=isNaN(r)?t.c:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return
$(e+u*n,r+a*n,i+o*n)+""}}function Rr(n,t){n=va.hsl(n),t=va.hsl(t);var
e=n.h,r=n.s,i=n.l,u=t.h-e,a=t.s-r,o=t.l-i;return
isNaN(a)&&(a=0,r=isNaN(r)?t.s:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return
O(e+u*n,r+a*n,i+o*n)+""}}function Yr(n,t){n=va.lab(n),t=va.lab(t);var
e=n.l,r=n.a,i=n.b,u=t.l-e,a=t.a-r,o=t.b-i;return function(n){return
G(e+u*n,r+a*n,i+o*n)+""}}function Ur(n,t){return t-=n,function(e){return
Math.round(n+t*e)}}function Ir(n,t){return
t=t-(n=+n)?1/(t-n):0,function(e){return(e-n)*t}}function Vr(n,t){return
t=t-(n=+n)?1/(t-n):0,function(e){return Math.max(0,Math.min(1,(e-n)*t))}}function
Xr(n){for(var t=n.source,e=n.target,r=Br(t,e),i=[t];t!==r;)t=t.parent,i.push(t);for(v
ar u=i.length;e!==r;)i.splice(u,0,e),e=e.parent;return i}function Zr(n){for(var
t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function
Br(n,t){if(n===t)return n;for(var
e=Zr(n),r=Zr(t),i=e.pop(),u=r.pop(),a=null;i===u;)a=i,i=e.pop(),u=r.pop();return
a}function $r(n){n.fixed|=2}function Wr(n){n.fixed&=-7}function
Jr(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Gr(n){n.fixed&=-5}function Kr(n,t,e){var
r=0,i=0;if(n.charge=0,!n.leaf)for(var
u,a=n.nodes,o=a.length,c=-1;++c<o;)u=a[c],null!=u&&(Kr(u,t,e),n.charge+=u.charge,r+=u.charge*u.cx,i+=u.charge*u.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var
l=t*e[n.point.index];n.charge+=n.pointCharge=l,r+=l*n.point.x,i+=l*n.point.y}n.cx=r/n.charge,n.cy=i/n.charge}function
Qr(n,t){return
va.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=ri,n}function
ni(n){return n.children}function ti(n){return n.value}function ei(n,t){return
t.value-n.value}function ri(n){return va.merge(
n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function
ii(n){return n.x}function ui(n){return n.y}function ai(n,t,e){n.y0=t,n.y=e}function
oi(n){return va.range(n.length)}function ci(n){for(var
t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function li(n){for(var
t,e=1,r=0,i=n[0][1],u=n.length;u>e;++e)(t=n[e][1])>i&&(r=e,i=t);return
r}function fi(n){return n.reduce(si,0)}function si(n,t){return n+t[1]}function
hi(n,t){return gi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function gi(n,t){for(var
e=-1,r=+n[0],i=(n[1]-r)/t,u=[];++e<=t;)u[e]=i*e+r;return u}function
pi(n){return[va.min(n),va.max(n)]}function di(n,t){return n.parent==t.parent?1:2}function
mi(n){var t=n.children;return t&&t.length?t[0]:n._tree.thread}function vi(n){var
t,e=n.children;return e&&(t=e.length)?e[t-1]:n._tree.thread}function yi(n,t){var
e=n.children;if(e&&(i=e.length))for(var
r,i,u=-1;++u<i;)t(r=yi(e[u],t),n)>0&&(n=r);return n}function Mi(n,t){return
n.x-t.x}fu
nction xi(n,t){return t.x-n.x}function bi(n,t){return n.depth-t.depth}function
_i(n,t){function e(n,r){var i=n.children;if(i&&(a=i.length))for(var
u,a,o=null,c=-1;++c<a;)u=i[c],e(u,o),o=u;t(n,r)}e(n,null)}function wi(n){for(var
t,e=0,r=0,i=n.children,u=i.length;--u>=0;)t=i[u]._tree,t.prelim+=e,t.mod+=e,e+=t.shift+(r+=t.change)}function
Si(n,t,e){n=n._tree,t=t._tree;var
r=e/(t.number-n.number);n.change+=r,t.change-=r,t.shift+=e,t.prelim+=e,t.mod+=e}function
Ei(n,t,e){return n._tree.ancestor.parent==t.parent?n._tree.ancestor:e}function
ki(n,t){return n.value-t.value}function Ai(n,t){var
e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function
Ni(n,t){n._pack_next=t,t._pack_prev=n}function qi(n,t){var
e=t.x-n.x,r=t.y-n.y,i=n.r+t.r;return.999*i*i>e*e+r*r}function Ti(n){function
t(n){f=Math.min(n.x-n.r,f),s=Math.max(n.x+n.r,s),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var
e,r,i,u,a,o,c,l,f=1/0,s=-1/0,h=1/0,g=-1/0;if(e.
forEach(Ci),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(i=e[1],i.x=i.r,i.y=0,t(i),l>2))for(u=e[2],ji(r,i,u),t(u),Ai(r,u),r._pack_prev=u,Ai(u,i),i=r._pack_next,a=3;l>a;a++){ji(r,i,u=e[a]);var
p=0,d=1,m=1;for(o=i._pack_next;o!==i;o=o._pack_next,d++)if(qi(o,u)){p=1;break}if(1==p)for(c=r._pack_prev;c!==o._pack_prev&&!qi(c,u);c=c._pack_prev,m++);p?(m>d||d==m&&i.r<r.r?Ni(r,i=o):Ni(r=c,i),a--):(Ai(r,u),i=u,t(u))}var
v=(f+s)/2,y=(h+g)/2,M=0;for(a=0;l>a;a++)u=e[a],u.x-=v,u.y-=y,M=Math.max(M,u.r+Math.sqrt(u.x*u.x+u.y*u.y));n.r=M,e.forEach(zi)}}function
Ci(n){n._pack_next=n._pack_prev=n}function zi(n){delete n._pack_next,delete
n._pack_prev}function Di(n,t,e,r){var
i=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,i)for(var
u=-1,a=i.length;++u<a;)Di(i[u],t,e,r)}function ji(n,t,e){var
r=n.r+e.r,i=t.x-n.x,u=t.y-n.y;if(r&&(i||u)){var a=t.r+e.r,o=i*i+u*u;a*=a,r*=r;var
c=.5+(r-a)/(2*o),l=Math.sqrt(Math.max(0,2*a*(r+o)-(r-=o)*r-a*a))/(2*o);e.x=n.x+c*i+l*u,e.y=n.y+c*u-l*i}else
e.x=n.x+r,e.y=n.y}function
Li(n){return 1+va.max(n,function(n){return n.y})}function Hi(n){return
n.reduce(function(n,t){return n+t.x},0)/n.length}function Fi(n){var t=n.children;return
t&&t.length?Fi(t[0]):n}function Pi(n){var t,e=n.children;return
e&&(t=e.length)?Pi(e[t-1]):n}function
Oi(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Ri(n,t){var
e=n.x+t[3],r=n.y+t[0],i=n.dx-t[1]-t[3],u=n.dy-t[0]-t[2];return
0>i&&(e+=i/2,i=0),0>u&&(r+=u/2,u=0),{x:e,y:r,dx:i,dy:u}}function
Yi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ui(n){return
n.rangeExtent?n.rangeExtent():Yi(n.range())}function Ii(n,t,e,r){var
i=e(n[0],n[1]),u=r(t[0],t[1]);return function(n){return u(i(n))}}function Vi(n,t){var
e,r=0,i=n.length-1,u=n[r],a=n[i];return
u>a&&(e=r,r=i,i=e,e=u,u=a,a=e),n[r]=t.floor(u),n[i]=t.ceil(a),n}function
Xi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return
Math.ceil(t/n)*n}}:yc}function Zi(n,t,e,r){var
i=[],u=[],a=0,o=Math.min(n.length,t.length)-1;for(n[o]<n[0]&
&(n=n.slice().reverse(),t=t.slice().reverse());++a<=o;)i.push(e(n[a-1],n[a])),u.push(r(t[a-1],t[a]));return
function(t){var e=va.bisect(n,t,1,o)-1;return u[e](i[e](t))}}function Bi(n,t,e,r){function
i(){var i=Math.min(n.length,t.length)>2?Zi:Ii,c=r?Vr:Ir;return
a=i(n,t,c,e),o=i(t,n,c,wr),u}function u(n){return a(n)}var a,o;return
u.invert=function(n){return o(n)},u.domain=function(t){return
arguments.length?(n=t.map(Number),i()):n},u.range=function(n){return
arguments.length?(t=n,i()):t},u.rangeRound=function(n){return
u.range(n).interpolate(Ur)},u.clamp=function(n){return
arguments.length?(r=n,i()):r},u.interpolate=function(n){return
arguments.length?(e=n,i()):e},u.ticks=function(t){return
Ki(n,t)},u.tickFormat=function(t,e){return Qi(n,t,e)},u.nice=function(t){return
Wi(n,t),i()},u.copy=function(){return Bi(n,t,e,r)},i()}function $i(n,t){return
va.rebind(n,t,"range","rangeRound","interpolate","clamp")}function
Wi(n,t){return Vi(n,Xi(t?Gi(n,t)[2]:Ji(n)))}function Ji(n){var
t=Yi(n),e=t[1]-t[0];return Math.pow(10,Math.round(Math.log(e)/Math.LN10)-1)}function
Gi(n,t){var
e=Yi(n),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),u=t/r*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function
Ki(n,t){return va.range.apply(va,Gi(n,t))}function Qi(n,t,e){var
r=-Math.floor(Math.log(Gi(n,t)[2])/Math.LN10+.01);return
va.format(e?e.replace(mo,function(n,t,e,i,u,a,o,c,l,f){return[t,e,i,u,a,o,c,l||"."+(r-2*("%"===f)),f].join("")}):",."+r+"f")}function
nu(n,t,e,r,i){function u(t){return n(e(t))}return u.invert=function(t){return
r(n.invert(t))},u.domain=function(t){return
arguments.length?(t[0]<0?(e=ru,r=iu):(e=tu,r=eu),n.domain((i=t.map(Number)).map(e)),u):i},u.base=function(n){return
arguments.length?(t=+n,u):t},u.nice=function(){function r(n){return
Math.pow(t,Math.floor(Math.log(n)/Math.log(t)))}function a(n){return
Math.pow(t,Math.ceil(Math.log(n)/Math.log(t)))}return n.domain
(Vi(i,e===tu?{floor:r,ceil:a}:{floor:function(n){return-a(-n)},ceil:function(n){return-r(-n)}}).map(e)),u},u.ticks=function(){var
i=Yi(n.domain()),u=[];if(i.every(isFinite)){var
a=Math.log(t),o=Math.floor(i[0]/a),c=Math.ceil(i[1]/a),l=r(i[0]),f=r(i[1]),s=t%1?2:t;if(e===ru)for(u.push(-Math.pow(t,-o));o++<c;)for(var
h=s-1;h>0;h--)u.push(-Math.pow(t,-o)*h);else{for(;c>o;o++)for(var
h=1;s>h;h++)u.push(Math.pow(t,o)*h);u.push(Math.pow(t,o))}for(o=0;u[o]<l;o++);for(c=u.length;u[c-1]>f;c--);u=u.slice(o,c)}return
u},u.tickFormat=function(n,i){if(!arguments.length)return
Mc;arguments.length<2?i=Mc:"function"!=typeof i&&(i=va.format(i));var
a,o=Math.log(t),c=Math.max(.1,n/u.ticks().length),l=e===ru?(a=-1e-12,Math.floor):(a=1e-12,Math.ceil);return
function(n){return n/r(o*l(e(n)/o+a))<=c?i(n):""}},u.copy=function(){return
nu(n.copy(),t,e,r,i)},$i(u,n)}function tu(n){return Math.log(0>n?0:n)}function
eu(n){return Math.exp(n)}function ru(n){return-Math.log(n>0?0:-n)}function
iu(n){return
-Math.exp(-n)}function uu(n,t,e){function r(t){return n(i(t))}var
i=au(t),u=au(1/t);return r.invert=function(t){return
u(n.invert(t))},r.domain=function(t){return
arguments.length?(n.domain((e=t.map(Number)).map(i)),r):e},r.ticks=function(n){return
Ki(e,n)},r.tickFormat=function(n,t){return Qi(e,n,t)},r.nice=function(n){return
r.domain(Wi(e,n))},r.exponent=function(a){return
arguments.length?(i=au(t=a),u=au(1/t),n.domain(e.map(i)),r):t},r.copy=function(){return
uu(n.copy(),t,e)},$i(r,n)}function au(n){return function(t){return
0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ou(n,t){function e(t){return
a[((u.get(t)||u.set(t,n.push(t)))-1)%a.length]}function r(t,e){return
va.range(n.length).map(function(n){return t+e*n})}var u,a,o;return
e.domain=function(r){if(!arguments.length)return n;n=[],u=new i;for(var
a,o=-1,c=r.length;++o<c;)u.has(a=r[o])||u.set(a,n.push(a));return
e[t.t].apply(e,t.a)},e.range=function(n){return
arguments.length?(a=n,o=0,t={t:"range",a:arguments},e):a},e.
rangePoints=function(i,u){arguments.length<2&&(u=0);var
c=i[0],l=i[1],f=(l-c)/(Math.max(1,n.length-1)+u);return
a=r(n.length<2?(c+l)/2:c+f*u/2,f),o=0,t={t:"rangePoints",a:arguments},e},e.rangeBands=function(i,u,c){arguments.length<2&&(u=0),arguments.length<3&&(c=u);var
l=i[1]<i[0],f=i[l-0],s=i[1-l],h=(s-f)/(n.length-u+2*c);return
a=r(f+h*c,h),l&&a.reverse(),o=h*(1-u),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(i,u,c){arguments.length<2&&(u=0),arguments.length<3&&(c=u);var
l=i[1]<i[0],f=i[l-0],s=i[1-l],h=Math.floor((s-f)/(n.length-u+2*c)),g=s-f-(n.length-u)*h;return
a=r(f+Math.round(g/2),h),l&&a.reverse(),o=Math.round(h*(1-u)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return
o},e.rangeExtent=function(){return Yi(t.a[0])},e.copy=function(){return
ou(n,t)},e.domain(n)}function cu(n,t){function e(){var
e=0,u=t.length;for(i=[];++e<u;)i[e-1]=va.quantile(n,e/u);return r}function r(n){return
isNaN(n=+n)?void 0:t[va.bisect(i,n)]}var i;return r.dom
ain=function(t){return
arguments.length?(n=t.filter(function(n){return!isNaN(n)}).sort(va.ascending),e()):n},r.range=function(n){return
arguments.length?(t=n,e()):t},r.quantiles=function(){return i},r.copy=function(){return
cu(n,t)},e()}function lu(n,t,e){function r(t){return
e[Math.max(0,Math.min(a,Math.floor(u*(t-n))))]}function i(){return
u=e.length/(t-n),a=e.length-1,r}var u,a;return r.domain=function(e){return
arguments.length?(n=+e[0],t=+e[e.length-1],i()):[n,t]},r.range=function(n){return
arguments.length?(e=n,i()):e},r.copy=function(){return
lu(n,t,e)},r.invertExtent=function(t){return
t=e.indexOf(t),t=0>t?0/0:t/u+n,[t,t+1/u]},i()}function fu(n,t){function e(e){return
e>=e?t[va.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 fu(n,t)},e}function su(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
Ki(n,t)},t.tickFormat=function(t,e){return Qi(n,t,e)},t.copy=function(){return
su(n)},t}function hu(n){return n.innerRadius}function gu(n){return n.outerRadius}function
pu(n){return n.startAngle}function du(n){return n.endAngle}function mu(n){for(var
t,e,r,i=-1,u=n.length;++i<u;)t=n[i],e=t[0],r=t[1]+Sc,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return
n}function vu(n){function t(t){function
c(){d.push("M",o(n(v),s),f,l(n(m.reverse()),s),"Z")}for(var
h,g,p,d=[],m=[],v=[],y=-1,M=t.length,x=ft(e),b=ft(i),_=e===r?function(){return
g}:ft(r),w=i===u?function(){return
p}:ft(u);++y<M;)a.call(this,h=t[y],y)?(m.push([g=+x.call(this,h,y),p=+b.call(this,h,y)]),v.push([+_.call(this,h,y),+w.call(this,h,y)])):m.length&&(c(),m=[],v=[]);return
m.length&&c(),d.length?d.join(""):null}var
e=Pe,r=Pe,i=0,u=Oe,a=Rt,o=Re,c=o.key,l=o,f="L",s=.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?(i=u=n,t):u},t.y0=function(n){return
arguments.length?(i=n,t):i},t.y1=function(n){return
arguments.length?(u=n,t):u},t.defined=function(n){return
arguments.length?(a=n,t):a},t.interpolate=function(n){return
arguments.length?(c="function"==typeof
n?o=n:(o=rc.get(n)||Re).key,l=o.reverse||o,f=o.closed?"M":"L",t):c},t.tension=function(n){return
arguments.length?(s=n,t):s},t}function yu(n){return n.radius}function
Mu(n){return[n.x,n.y]}function xu(n){return function(){var
t=n.apply(this,arguments),e=t[0],r=t[1]+Sc;return[e*Math.cos(r),e*Math.sin(r)]}}function
bu(){return 64}function _u(){return"circle"}function wu(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
Su(n,t){return Ta(n,Tc),n.id=t,n}function Eu(n,t,e,r){var i=n.id;return
q(n,"function"==typeof e?function(n,u,a){n.__transition
__[i].tween.set(t,r(e.call(n,n.__data__,u,a)))}:(e=r(e),function(n){n.__transition__[i].tween.set(t,e)}))}function
ku(n){return null==n&&(n=""),function(){this.textContent=n}}function
Au(n,t,e,r){var
u=n.__transition__||(n.__transition__={active:0,count:0}),a=u[e];if(!a){var
o=r.time;return a=u[e]={tween:new
i,event:va.dispatch("start","end"),time:o,ease:r.ease,delay:r.delay,duration:r.duration},++u.count,va.timer(function(r){function
i(r){return
u.active>e?l():(u.active=e,h.start.call(n,f,t),a.tween.forEach(function(e,r){(r=r.call(n,f,t))&&d.push(r)}),c(r)||va.timer(c,0,o),1)}function
c(r){if(u.active!==e)return l();for(var
i=(r-g)/p,a=s(i),o=d.length;o>0;)d[--o].call(n,a);return
i>=1?(l(),h.end.call(n,f,t),1):void 0}function l(){return--u.count?delete u[e]:delete
n.__transition__,1}var f=n.__data__,s=a.ease,h=a.event,g=a.delay,p=a.duration,d=[];return
r>=g?i(r):va.timer(i,g,o),1},0,o),a}}function
Nu(n,t){n.attr("transform",function(n){return"translate("+t(n)+",0)"})}functi
on
qu(n,t){n.attr("transform",function(n){return"translate(0,"+t(n)+")"})}function
Tu(n,t,e){if(r=[],e&&t.length>1){for(var
r,i,u,a=Yi(n.domain()),o=-1,c=t.length,l=(t[1]-t[0])/++e;++o<c;)for(i=e;--i>0;)(u=+t[o]-i*l)>=a[0]&&r.push(u);for(--o,i=0;++i<e&&(u=+t[o]+i*l)<a[1];)r.push(u)}return
r}function Cu(){this._=new
Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function
zu(n,t,e){function r(t){var e=n(t),r=u(e,1);return r-t>t-e?e:r}function i(e){return
t(e=n(new Fc(e-1)),1),e}function u(n,e){return t(n=new Fc(+n),e),n}function a(n,r,u){var
a=i(n),o=[];if(u>1)for(;r>a;)e(a)%u||o.push(new Date(+a)),t(a,1);else
for(;r>a;)o.push(new Date(+a)),t(a,1);return o}function o(n,t,e){try{Fc=Cu;var r=new
Cu;return
r._=n,a(r,t,e)}finally{Fc=Date}}n.floor=n,n.round=r,n.ceil=i,n.offset=u,n.range=a;var
c=n.utc=Du(n);return
c.floor=c,c.round=Du(r),c.ceil=Du(i),c.offset=Du(u),c.range=o,n}function Du(n){return
function(t,e){try{Fc=Cu;var r=new Cu;return r._=t,n(r,e)._}fina
lly{Fc=Date}}}function ju(n,t,e,r){for(var
i,u,a=0,o=t.length,c=e.length;o>a;){if(r>=c)return-1;if(i=t.charCodeAt(a++),37===i){if(u=il[t.charAt(a++)],!u||(r=u(n,e,r))<0)return-1}else
if(i!=e.charCodeAt(r++))return-1}return r}function Lu(n){return new
RegExp("^(?:"+n.map(va.requote).join("|")+")","i")}function
Hu(n){for(var t=new i,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return
t}function Fu(n,t,e){var
r=0>n?"-":"",i=(r?-n:n)+"",u=i.length;return
r+(e>u?new Array(e-u+1).join(t)+i:i)}function Pu(n,t,e){Wc.lastIndex=0;var
r=Wc.exec(t.substring(e));return
r?(n.w=Jc.get(r[0].toLowerCase()),e+r[0].length):-1}function Ou(n,t,e){Bc.lastIndex=0;var
r=Bc.exec(t.substring(e));return
r?(n.w=$c.get(r[0].toLowerCase()),e+r[0].length):-1}function Ru(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function
Yu(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e));return
r?(n.U=+r[0],e+r[0].length):-1}function Uu(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e));return r?(n.W=+r[0],e+r[0].length):-1}function
Iu(n,t,e){Qc.lastIndex=0;var r=Qc.exec(t.substring(e));return
r?(n.m=nl.get(r[0].toLowerCase()),e+r[0].length):-1}function Vu(n,t,e){Gc.lastIndex=0;var
r=Gc.exec(t.substring(e));return
r?(n.m=Kc.get(r[0].toLowerCase()),e+r[0].length):-1}function Xu(n,t,e){return
ju(n,rl.c.toString(),t,e)}function Zu(n,t,e){return ju(n,rl.x.toString(),t,e)}function
Bu(n,t,e){return ju(n,rl.X.toString(),t,e)}function $u(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function
Wu(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e,e+2));return
r?(n.y=Ju(+r[0]),e+r[0].length):-1}function Ju(n){return n+(n>68?1900:2e3)}function
Gu(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e,e+2));return
r?(n.m=r[0]-1,e+r[0].length):-1}function Ku(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function
Qu(n,t,e){ul.lastIndex=0;var r=ul.exec(t.sub
string(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function
na(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e,e+2));return
r?(n.H=+r[0],e+r[0].length):-1}function ta(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function
ea(n,t,e){ul.lastIndex=0;var r=ul.exec(t.substring(e,e+2));return
r?(n.S=+r[0],e+r[0].length):-1}function ra(n,t,e){ul.lastIndex=0;var
r=ul.exec(t.substring(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ia(n,t,e){var
r=al.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}function ua(n){var
t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(Math.abs(t)/60),i=Math.abs(t)%60;return
e+Fu(r,"0",2)+Fu(i,"0",2)}function aa(n,t,e){tl.lastIndex=0;var
r=tl.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function oa(n){return
n.toISOString()}function ca(n,t,e){function r(t){return n(t)}return
r.invert=function(t){return la(n.invert(t))},r.domain=function(t){return
arguments.length?(n.domain(t),r)
:n.domain().map(la)},r.nice=function(n){return
r.domain(Vi(r.domain(),n))},r.ticks=function(e,i){var
u=Yi(r.domain());if("function"!=typeof e){var
a=u[1]-u[0],o=a/e,c=va.bisect(cl,o);if(c==cl.length)return t.year(u,e);if(!c)return
n.ticks(e).map(la);Math.log(o/cl[c-1])<Math.log(cl[c]/o)&&--c,e=t[c],i=e[1],e=e[0].range}return
e(u[0],new Date(+u[1]+1),i)},r.tickFormat=function(){return e},r.copy=function(){return
ca(n.copy(),t,e)},$i(r,n)}function la(n){return new Date(n)}function fa(n){return
function(t){for(var e=n.length-1,r=n[e];!r[1](t);)r=n[--e];return r[0](t)}}function
sa(n){var t=new Date(n,0,1);return t.setFullYear(n),t}function ha(n){var
t=n.getFullYear(),e=sa(t),r=sa(t+1);return t+(n-e)/(r-e)}function ga(n){var t=new
Date(Date.UTC(n,0,1));return t.setUTCFullYear(n),t}function pa(n){var
t=n.getUTCFullYear(),e=ga(t),r=ga(t+1);return t+(n-e)/(r-e)}function da(n){return
JSON.parse(n.responseText)}function ma(n){var t=ya.createRange();return
t.selectNode(ya.body),t.creat
eContextualFragment(n.responseText)}var
va={version:"3.2.2"};Date.now||(Date.now=function(){return+new Date});var
ya=document,Ma=ya.documentElement,xa=window;try{ya.createElement("div").style.setProperty("opacity",0,"")}catch(ba){var
_a=xa.CSSStyleDeclaration.prototype,wa=_a.setProperty;_a.setProperty=function(n,t,e){wa.call(this,n,t+"",e)}}va.ascending=function(n,t){return
t>n?-1:n>t?1:n>=t?0:0/0},va.descending=function(n,t){return
n>t?-1:t>n?1:t>=n?0:0/0},va.min=function(n,t){var
e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u&&!(null!=(e=n[i])&&e>=e);)e=void
0;for(;++i<u;)null!=(r=n[i])&&e>r&&(e=r)}else{for(;++i<u&&!(null!=(e=t.call(n,n[i],i))&&e>=e);)e=void
0;for(;++i<u;)null!=(r=t.call(n,n[i],i))&&e>r&&(e=r)}return
e},va.max=function(n,t){var
e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u&&!(null!=(e=n[i])&&e>=e);)e=void
0;for(;++i<u;)null!=(r=n[i])&&r>e&&(e=r)}else{for(;++i<u&&!(null!=(e=t.call(n,n[i],i))&&e>=e);)e=void
0;for(;++i<u;)null!=(r=t.call(n,
n[i],i))&&r>e&&(e=r)}return e},va.extent=function(n,t){var
e,r,i,u=-1,a=n.length;if(1===arguments.length){for(;++u<a&&!(null!=(e=i=n[u])&&e>=e);)e=i=void
0;for(;++u<a;)null!=(r=n[u])&&(e>r&&(e=r),r>i&&(i=r))}else{for(;++u<a&&!(null!=(e=i=t.call(n,n[u],u))&&e>=e);)e=void
0;for(;++u<a;)null!=(r=t.call(n,n[u],u))&&(e>r&&(e=r),r>i&&(i=r))}return[e,i]},va.sum=function(n,t){var
e,r=0,i=n.length,u=-1;if(1===arguments.length)for(;++u<i;)isNaN(e=+n[u])||(r+=e);else
for(;++u<i;)isNaN(e=+t.call(n,n[u],u))||(r+=e);return r},va.mean=function(t,e){var
r,i=t.length,u=0,a=-1,o=0;if(1===arguments.length)for(;++a<i;)n(r=t[a])&&(u+=(r-u)/++o);else
for(;++a<i;)n(r=e.call(t,t[a],a))&&(u+=(r-u)/++o);return o?u:void
0},va.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),i=+n[r-1],u=e-r;return
u?i+u*(n[r]-i):i},va.median=function(t,e){return
arguments.length>1&&(t=t.map(e)),t=t.filter(n),t.length?va.quantile(t.sort(va.ascending),.5):void
0},va.bisector=function(n){return{left:function(
t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var
u=r+i>>>1;n.call(t,t[u],u)<e?r=u+1:i=u}return
r},right:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var
u=r+i>>>1;e<n.call(t,t[u],u)?i=u:r=u+1}return r}}};var
Sa=va.bisector(function(n){return
n});va.bisectLeft=Sa.left,va.bisect=va.bisectRight=Sa.right,va.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},va.permute=function(n,t){for(var e=[],r=-1,i=t.length;++r<i;)e[r]=n[t[r]];return
e},va.zip=function(){if(!(i=arguments.length))return[];for(var
n=-1,e=va.min(arguments,t),r=new Array(e);++n<e;)for(var i,u=-1,a=r[n]=new
Array(i);++u<i;)a[u]=arguments[u][n];return r},va.transpose=function(n){return
va.zip.apply(va,n)},va.keys=function(n){var t=[];for(var e in n)t.push(e);return
t},va.values=function(n){var t=[];for(var e in n)t.push(n[e]);return
t},va.entries=function(n){var t=[];for(var e in n)t.push({k
ey:e,value:n[e]});return t},va.merge=function(n){return
Array.prototype.concat.apply([],n)},va.range=function(n,t,r){if(arguments.length<3&&(r=1,arguments.length<2&&(t=n,n=0)),1/0===(t-n)/r)throw
new Error("infinite range");var
i,u=[],a=e(Math.abs(r)),o=-1;if(n*=a,t*=a,r*=a,0>r)for(;(i=n+r*++o)>t;)u.push(i/a);else
for(;(i=n+r*++o)<t;)u.push(i/a);return u},va.map=function(n){var t=new i;for(var e in
n)t.set(e,n[e]);return t},r(i,{has:function(n){return Ea+n in this},get:function(n){return
this[Ea+n]},set:function(n,t){return this[Ea+n]=t},remove:function(n){return n=Ea+n,n in
this&&delete this[n]},keys:function(){var n=[];return
this.forEach(function(t){n.push(t)}),n},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},forEach:function(n){for(var t in
this)t.charCodeAt(0)===ka&&n.call(this,t.substring(1),this[t])}});var
Ea="\0",ka=Ea.charCodeAt(0);va.nest=functio
n(){function n(t,o,c){if(c>=a.length)return r?r.call(u,o):e?o.sort(e):o;for(var
l,f,s,h,g=-1,p=o.length,d=a[c++],m=new
i;++g<p;)(h=m.get(l=d(f=o[g])))?h.push(f):m.set(l,[f]);return
t?(f=t(),s=function(e,r){f.set(e,n(t,r,c))}):(f={},s=function(e,r){f[e]=n(t,r,c)}),m.forEach(s),f}function
t(n,e){if(e>=a.length)return n;var r=[],i=o[e++];return
n.forEach(function(n,i){r.push({key:n,values:t(i,e)})
-}),i?r.sort(function(n,t){return i(n.key,t.key)}):r}var e,r,u={},a=[],o=[];return
u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return
t(n(va.map,e,0),0)},u.key=function(n){return a.push(n),u},u.sortKeys=function(n){return
o[a.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return
r=n,u},u},va.set=function(n){var t=new u;if(n)for(var
e=0;e<n.length;e++)t.add(n[e]);return t},r(u,{has:function(n){return Ea+n in
this},add:function(n){return this[Ea+n]=!0,n},remove:function(n){return n=Ea+n,n in
this&&delete this[n]},values:function(){var n=[];return
this.forEach(function(t){n.push(t)}),n},forEach:function(n){for(var t in
this)t.charCodeAt(0)===ka&&n.call(this,t.substring(1))}}),va.behavior={},va.rebind=function(n,t){for(var
e,r=1,i=arguments.length;++r<i;)n[e=arguments[r]]=a(n,t,t[e]);return n};var
Aa=["webkit","ms","moz","Moz","o","O"],Na=l;try{Na(Ma.childNodes)[0].nodeType}catch(qa){Na=c}var
Ta=[].__proto__?function(n,t){n.__proto__=t}:
function(n,t){for(var e in t)n[e]=t[e]};va.dispatch=function(){for(var n=new
s,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=h(n);return
n},s.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}},va.event=null,va.requote=function(n){return n.replace(Ca,"\\$&")};var
Ca=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,za=function(n,t){return
t.querySelector(n)},Da=function(n,t){return
t.querySelectorAll(n)},ja=Ma[o(Ma,"matchesSelector")],La=function(n,t){return
ja.call(n,t)};"function"==typeof Sizzle&&(za=function(n,t){return
Sizzle(n,t)[0]||null},Da=function(n,t){return
Sizzle.uniqueSort(Sizzle(n,t))},La=Sizzle.matchesSelector),va.selection=function(){return
Oa};var Ha=va.selection.prototype=[];Ha.select=function(n){var
t,e,r,i,u=[];"function"!=typeof n&&(n=v(n));for(var a=-1,o=th
is.length;++a<o;){u.push(t=[]),t.parentNode=(r=this[a]).parentNode;for(var
c=-1,l=r.length;++c<l;)(i=r[c])?(t.push(e=n.call(i,i.__data__,c)),e&&"__data__"in
i&&(e.__data__=i.__data__)):t.push(null)}return m(u)},Ha.selectAll=function(n){var
t,e,r=[];"function"!=typeof n&&(n=y(n));for(var
i=-1,u=this.length;++i<u;)for(var
a=this[i],o=-1,c=a.length;++o<c;)(e=a[o])&&(r.push(t=Na(n.call(e,e.__data__,o))),t.parentNode=e);return
m(r)};var
Fa={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3....
t=n.indexOf(":"),e=n;return
t>=0&&(e=n.substring(0,t),n=n.substring(t+1)),Fa.hasOwnProperty(e)?{space:Fa[e],local:n}:n}},Ha.attr=function(n,t){if(arguments.length<2){if("string"==typeof
n){var e=this.node();return
n=va.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in
n)this.each(M(t,n
[t]));return this}return
this.each(M(n,t))},Ha.classed=function(n,t){if(arguments.length<2){if("string"==typeof
n){var
e=this.node(),r=(n=n.trim().split(/^|\s+/g)).length,i=-1;if(t=e.classList){for(;++i<r;)if(!t.contains(n[i]))return!1}else
for(t=e.getAttribute("class");++i<r;)if(!b(n[i]).test(t))return!1;return!0}for(t
in n)this.each(_(t,n[t]));return this}return
this.each(_(n,t))},Ha.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(S(e,n[e],t));return
this}if(2>r)return
xa.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return
this.each(S(n,t,e))},Ha.property=function(n,t){if(arguments.length<2){if("string"==typeof
n)return this.node()[n];for(t in n)this.each(E(t,n[t]));return this}return
this.each(E(n,t))},Ha.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},Ha.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},Ha.append=function(n){function
t(){return this.appendChild(ya.createElementNS(this.namespaceURI,n))}function e(){return
this.appendChild(ya.createElementNS(n.space,n.local))}return
n=va.ns.qualify(n),this.select(n.local?e:t)},Ha.insert=function(n,t){function
e(e,r){return
this.insertBefore(ya.createElementNS(this.namespaceURI,n),t.call(this,e,r))}function
r(e,r){return
this.insertBefore(ya.createElementNS(n.space,n.local),t.call(this,e,r))}return
n=va.ns.qualify(n),"function"!=typeof
t&&(t=v(t)),this.select(n.local?r:e)},Ha.remove=function(){return
this.each(function(){var
n=this.parentNode;n&&n.removeChild(this)})},Ha.data=function(n,t){function
e(n,e){var r,u,a,o=n.length,s=e.length,h=Math.min(o,
s),g=new Array(s),p=new Array(s),d=new Array(o);if(t){var m,v=new i,y=new
i,M=[];for(r=-1;++r<o;)m=t.call(u=n[r],u.__data__,r),v.has(m)?d[r]=u:v.set(m,u),M.push(m);for(r=-1;++r<s;)m=t.call(e,a=e[r],r),(u=v.get(m))?(g[r]=u,u.__data__=a):y.has(m)||(p[r]=k(a)),y.set(m,a),v.remove(m);for(r=-1;++r<o;)v.has(M[r])&&(d[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],a=e[r],u?(u.__data__=a,g[r]=u):p[r]=k(a);for(;s>r;++r)p[r]=k(e[r]);for(;o>r;++r)d[r]=n[r]}p.update=g,p.parentNode=g.parentNode=d.parentNode=n.parentNode,c.push(p),l.push(g),f.push(d)}var
r,u,a=-1,o=this.length;if(!arguments.length){for(n=new
Array(o=(r=this[0]).length);++a<o;)(u=r[a])&&(n[a]=u.__data__);return n}var
c=T([]),l=m([]),f=m([]);if("function"==typeof
n)for(;++a<o;)e(r=this[a],n.call(r,r.parentNode.__data__,a));else
for(;++a<o;)e(r=this[a],n);return l.enter=function(){return c},l.exit=function(){return
f},l},Ha.datum=function(n){return
arguments.length?this.property("__data__",n):this.property("__data__")},Ha.filter=funct
ion(n){var t,e,r,i=[];"function"!=typeof n&&(n=A(n));for(var
u=0,a=this.length;a>u;u++){i.push(t=[]),t.parentNode=(e=this[u]).parentNode;for(var
o=0,c=e.length;c>o;o++)(r=e[o])&&n.call(r,r.__data__,o)&&t.push(r)}return
m(i)},Ha.order=function(){for(var n=-1,t=this.length;++n<t;)for(var
e,r=this[n],i=r.length-1,u=r[i];--i>=0;)(e=r[i])&&(u&&u!==e.nextSibling&&u.parentNode.insertBefore(e,u),u=e);return
this},Ha.sort=function(n){n=N.apply(this,arguments);for(var
t=-1,e=this.length;++t<e;)this[t].sort(n);return
this.order()},Ha.each=function(n){return
q(this,function(t,e,r){n.call(t,t.__data__,e,r)})},Ha.call=function(n){var
t=Na(arguments);return
n.apply(t[0]=this,t),this},Ha.empty=function(){return!this.node()},Ha.node=function(){for(var
n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,i=e.length;i>r;r++){var
u=e[r];if(u)return u}return null},Ha.size=function(){var n=0;return
this.each(function(){++n}),n};var
Pa=[];va.selection.enter=T,va.selection.enter.prototype=Pa,Pa.append=H
a.append,Pa.insert=Ha.insert,Pa.empty=Ha.empty,Pa.node=Ha.node,Pa.call=Ha.call,Pa.size=Ha.size,Pa.select=function(n){for(var
t,e,r,i,u,a=[],o=-1,c=this.length;++o<c;){r=(i=this[o]).update,a.push(t=[]),t.parentNode=i.parentNode;for(var
l=-1,f=i.length;++l<f;)(u=i[l])?(t.push(r[l]=e=n.call(i.parentNode,u.__data__,l)),e.__data__=u.__data__):t.push(null)}return
m(a)},Ha.transition=function(){var
n,t,e=Ac||++Cc,r=[],i=Object.create(zc);i.time=Date.now();for(var
u=-1,a=this.length;++u<a;){r.push(n=[]);for(var
o=this[u],c=-1,l=o.length;++c<l;)(t=o[c])&&Au(t,c,e,i),n.push(t)}return
Su(r,e)},va.select=function(n){var t=["string"==typeof n?za(n,ya):n];return
t.parentNode=Ma,m([t])},va.selectAll=function(n){var t=Na("string"==typeof
n?Da(n,ya):n);return t.parentNode=Ma,m([t])};var
Oa=va.select(Ma);Ha.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(C(e,n[e],t));return
this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return t
his.each(C(n,t,e))};var
Ra=va.map({mouseenter:"mouseover",mouseleave:"mouseout"});Ra.forEach(function(n){"on"+n
in ya&&Ra.remove(n)});var
Ya=o(Ma.style,"userSelect");va.mouse=function(n){return L(n,p())};var
Ua=/WebKit/.test(xa.navigator.userAgent)?-1:0;va.touches=function(n,t){return
arguments.length<2&&(t=p().touches),t?Na(t).map(function(t){var e=L(n,t);return
e.identifier=t.identifier,e}):[]},va.behavior.drag=function(){function
n(){this.on("mousedown.drag",t).on("touchstart.drag",t)}function
t(){function n(){var n=a.parentNode;return null!=l?va.touches(n).filter(function(n){return
n.identifier===l})[0]:va.mouse(n)}function t(){if(!a.parentNode)return i();var
t=n(),e=t[0]-f[0],r=t[1]-f[1];s|=e|r,f=t,o({type:"drag",x:t[0]+u[0],y:t[1]+u[1],dx:e,dy:r})}function
i(){g.on(null!=l?"touchmove.drag-"+l:"mousemove.drag",null).on(null!=l?"touchend.drag-"+l:"mouseup.drag",null),h(s&&va.event.target===c),o({type:"dragend"})}var
u,a=this,o=e.of(a,arguments),c=va.event.target,l=va.eve
nt.touches?va.event.changedTouches[0].identifier:null,f=n(),s=0,h=j(null!=l?"drag-"+l:"drag"),g=va.select(xa).on(null!=l?"touchmove.drag-"+l:"mousemove.drag",t).on(null!=l?"touchend.drag-"+l:"mouseup.drag",i,!0);r?(u=r.apply(a,arguments),u=[u.x-f[0],u.y-f[1]]):u=[0,0],o({type:"dragstart"})}var
e=d(n,"drag","dragstart","dragend"),r=null;return
n.origin=function(t){return
arguments.length?(r=t,n):r},va.rebind(n,e,"on")},va.behavior.zoom=function(){function
n(){this.on("mousedown.zoom",o).on("mousemove.zoom",l).on(Xa+".zoom",c).on("dblclick.zoom",f).on("touchstart.zoom",s).on("touchmove.zoom",h).on("touchend.zoom",s)}function
t(n){return[(n[0]-_[0])/w,(n[1]-_[1])/w]}function
e(n){return[n[0]*w+_[0],n[1]*w+_[1]]}function
r(n){w=Math.max(S[0],Math.min(S[1],n))}function
i(n,t){t=e(t),_[0]+=n[0]-t[0],_[1]+=n[1]-t[1]}function
u(){y&&y.domain(v.range().map(function(n){return(n-_[0])/w}).map(v.invert)),x&&x.domain(M.range().map(function(n){return(n-_[1])/w}).map(M.invert))}function
a(
n){u(),va.event.preventDefault(),n({type:"zoom",scale:w,translate:_})}function
o(){function n(){c=1,i(va.mouse(r),f),a(u)}function
e(){l.on("mousemove.zoom",null).on("mouseup.zoom",null),s(c&&va.event.target===o)}var
r=this,u=E.of(r,arguments),o=va.event.target,c=0,l=va.select(xa).on("mousemove.zoom",n).on("mouseup.zoom",e),f=t(va.mouse(r)),s=j("zoom")}function
c(){g||(g=t(va.mouse(this))),r(Math.pow(2,.002*Ia())*w),i(va.mouse(this),g),a(E.of(this,arguments))}function
l(){g=null}function f(){var
n=va.mouse(this),e=t(n),u=Math.log(w)/Math.LN2;r(Math.pow(2,va.event.shiftKey?Math.ceil(u)-1:Math.floor(u)+1)),i(n,e),a(E.of(this,arguments))}function
s(){var
n=va.touches(this),e=Date.now();if(m=w,g={},p=0,n.forEach(function(n){g[n.identifier]=t(n)}),1===n.length){if(500>e-b){var
u=n[0],o=t(n[0]);r(2*w),i(u,o),a(E.of(this,arguments))}b=e}else if(n.length>1){var
u=n[0],c=n[1],l=u[0]-c[0],f=u[1]-c[1];p=l*l+f*f}}function h(){var
n=va.touches(this),t=n[0],e=g[t.identifier];if(u=n[1]){va
r u,o=g[u.identifier],c=va.event.scale;if(null==c){var
l=(l=u[0]-t[0])*l+(l=u[1]-t[1])*l;c=p&&Math.sqrt(l/p)}t=[(t[0]+u[0])/2,(t[1]+u[1])/2],e=[(e[0]+o[0])/2,(e[1]+o[1])/2],r(c*m)}i(t,e),b=null,a(E.of(this,arguments))}var
g,p,m,v,y,M,x,b,_=[0,0],w=1,S=Va,E=d(n,"zoom");return
n.translate=function(t){return
arguments.length?(_=t.map(Number),u(),n):_},n.scale=function(t){return
arguments.length?(w=+t,u(),n):w},n.scaleExtent=function(t){return
arguments.length?(S=null==t?Va:t.map(Number),n):S},n.x=function(t){return
arguments.length?(y=t,v=t.copy(),_=[0,0],w=1,n):y},n.y=function(t){return
arguments.length?(x=t,M=t.copy(),_=[0,0],w=1,n):x},va.rebind(n,E,"on")};var
Ia,Va=[0,1/0],Xa="onwheel"in
ya?(Ia=function(){return-va.event.deltaY*(va.event.deltaMode?120:1)},"wheel"):"onmousewheel"in
ya?(Ia=function(){return
va.event.wheelDelta},"mousewheel"):(Ia=function(){return-va.event.detail},"MozMousePixelScroll");H.prototype.toString=function(){return
this.rgb()+""},va.hsl=function(n,t,e
){return 1===arguments.length?n instanceof
P?F(n.h,n.s,n.l):ut(""+n,at,F):F(+n,+t,+e)};var Za=P.prototype=new
H;Za.brighter=function(n){return
n=Math.pow(.7,arguments.length?n:1),F(this.h,this.s,this.l/n)},Za.darker=function(n){return
n=Math.pow(.7,arguments.length?n:1),F(this.h,this.s,n*this.l)},Za.rgb=function(){return
O(this.h,this.s,this.l)};var
Ba=Math.PI,$a=1e-6,Wa=$a*$a,Ja=Ba/180,Ga=180/Ba;va.hcl=function(n,t,e){return
1===arguments.length?n instanceof B?Z(n.h,n.c,n.l):n instanceof
J?K(n.l,n.a,n.b):K((n=ot((n=va.rgb(n)).r,n.g,n.b)).l,n.a,n.b):Z(+n,+t,+e)};var
Ka=B.prototype=new H;Ka.brighter=function(n){return
Z(this.h,this.c,Math.min(100,this.l+Qa*(arguments.length?n:1)))},Ka.darker=function(n){return
Z(this.h,this.c,Math.max(0,this.l-Qa*(arguments.length?n:1)))},Ka.rgb=function(){return
$(this.h,this.c,this.l).rgb()},va.lab=function(n,t,e){return 1===arguments.length?n
instanceof J?W(n.l,n.a,n.b):n instanceof
B?$(n.l,n.c,n.h):ot((n=va.rgb(n)).r,n.g,n.b):W(+n,+t,+e)}
;var Qa=18,no=.95047,to=1,eo=1.08883,ro=J.prototype=new H;ro.brighter=function(n){return
W(Math.min(100,this.l+Qa*(arguments.length?n:1)),this.a,this.b)},ro.darker=function(n){return
W(Math.max(0,this.l-Qa*(arguments.length?n:1)),this.a,this.b)},ro.rgb=function(){return
G(this.l,this.a,this.b)},va.rgb=function(n,t,e){return 1===arguments.length?n instanceof
rt?et(n.r,n.g,n.b):ut(""+n,et,O):et(~~n,~~t,~~e)};var io=rt.prototype=new
H;io.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var
t=this.r,e=this.g,r=this.b,i=30;return
t||e||r?(t&&i>t&&(t=i),e&&i>e&&(e=i),r&&i>r&&(r=i),et(Math.min(255,Math.floor(t/n)),Math.min(255,Math.floor(e/n)),Math.min(255,Math.floor(r/n)))):et(i,i,i)},io.darker=function(n){return
n=Math.pow(.7,arguments.length?n:1),et(Math.floor(n*this.r),Math.floor(n*this.g),Math.floor(n*this.b))},io.hsl=function(){return
at(this.r,this.g,this.b)},io.toString=function(){return"#"+it(this.r)+it(this.g)+it(this.b)};var
uo=va.map({aliceblue:"#f0f8ff",antique
white:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#
f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f
5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"});uo.forEach(function(n,t){uo.set(n,ut(t,et,O))}),va.functor=ft,va.x
hr=ht(st),va.dsv=function(n,t){function
e(n,e,u){arguments.length<3&&(u=e,e=null);var a=va.xhr(n,t,u);return
a.row=function(n){return
arguments.length?a.response(null==(e=n)?r:i(n)):e},a.row(e)}function r(n){return
e.parse(n.responseText)}function i(n){return function(t){return
e.parse(t.responseText,n)}}function a(t){return t.map(o).join(n)}function o(n){return
c.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var
c=new RegExp('["'+n+"\n]"),l=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
i=new Function("d","return {"+n.map(function(n,t){return
JSON.stringify(n)+":
d["+t+"]"}).join(",")+"}");r=t?function(n,e){return
t(i(n),e)}:i})},e.parseRows=function(n,t){function e(){if(f>=c)return a;if(i)return
i=!1,u;var t=f;if(34===n.charCodeAt(t)){for(var
e=t;e++<c;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}f=e+2;var
r=n.charCodeAt(e+1);return
13===r?(i=!0,10===n.charCodeAt(e+2)&&++f):10===r&&(i=!0),n.substrin
g(t+1,e).replace(/""/g,'"')}for(;c>f;){var
r=n.charCodeAt(f++),o=1;if(10===r)i=!0;else
if(13===r)i=!0,10===n.charCodeAt(f)&&(++f,++o);else if(r!==l)continue;return
n.substring(t,f-o)}return n.substring(t)}for(var
r,i,u={},a={},o=[],c=n.length,f=0,s=0;(r=e())!==a;){for(var
h=[];r!==u&&r!==a;)h.push(r),r=e();(!t||(h=t(h,s++)))&&o.push(h)}return
o},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new
u,i=[];return t.forEach(function(n){for(var t in
n)r.has(t)||i.push(r.add(t))}),[i.map(o).join(n)].concat(t.map(function(t){return
i.map(function(n){return
o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return
n.map(a).join("\n")},e},va.csv=va.dsv(",","text/csv"),va.tsv=va.dsv(" ","text/tab-separated-values");var
ao,oo,co,lo;va.timer=function(n,t,e){if(arguments.length<3){if(arguments.length<2)t=0;else
if(!isFinite(t))return;e=Date.now()}var
r=e+t,i={callback:n,time:r,next:null};oo?oo.next=i:ao=i,oo=i,co||(lo=clearTimeout(lo),co=1,fo(dt))},va.time
r.flush=function(){mt(),vt()};var
fo=xa[o(xa,"requestAnimationFrame")]||function(n){setTimeout(n,17)},so=".",ho=",",go=[3,3],po=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"].map(yt);va.formatPrefix=function(n,t){var
e=0;return
n&&(0>n&&(n*=-1),t&&(n=va.round(n,Mt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((0>=e?e+1:e-1)/3)))),po[8+e/3]},va.round=function(n,t){return
t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)},va.format=function(n){var
t=mo.exec(n),e=t[1]||"
",r=t[2]||">",i=t[3]||"",u=t[4]||"",a=t[5],o=+t[6],c=t[7],l=t[8],f=t[9],s=1,h="",g=!1;switch(l&&(l=+l.substring(1)),(a||"0"===e&&"="===r)&&(a=e="0",r="=",c&&(o-=Math.floor((o-1)/4))),f){case"n":c=!0,f="g";break;case"%":s=100,h="%",f="f";break;case"p":s=100,h="%",f="r";break;case"b":case"o":case"x":case"X":u&&(u="0"+f.toLowerCase());case"c":case"d":g=!0,l=0;break;case"s":s=-1,f="r"}"#"===u&&(u=""),"r"!=f||l||(f="g"),null!=l&&("g"==f?l=Math.max(
1,Math.min(21,l)):("e"==f||"f"==f)&&(l=Math.max(0,Math.min(20,l)))),f=vo.get(f)||xt;var
p=a&&c;return function(n){if(g&&n%1)return"";var
t=0>n||0===n&&0>1/n?(n=-n,"-"):i;if(0>s){var
d=va.formatPrefix(n,l);n=d.scale(n),h=d.symbol}else
n*=s;n=f(n,l),!a&&c&&(n=yo(n));var
m=u.length+n.length+(p?0:t.length),v=o>m?new Array(m=o-m+1).join(e):"";return
p&&(n=yo(v+n)),so&&n.replace(".",so),t+=u,("<"===r?t+n+v:">"===r?v+t+n:"^"===r?v.substring(0,m>>=1)+t+n+v.substring(m):t+(p?n:v+n))+h}};var
mo=/(?:([^{])?([<>=^]))?([+\-
])?(#)?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,vo=va.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=va.round(n,Mt(n,t))).toFixed(Math.max(0,Math.min(20,Mt(n*(1+1e-15),
t))))}}),yo=st;if(go){var Mo=go.length;yo=function(n){for(var
t=n.lastIndexOf("."),e=t>=0?"."+n.substring(t+1):(t=n.length,""),r=[],i=0,u=go[0];t>0&&u>0;)r.push(n.substring(t-=u,t+u)),u=go[i=(i+1)%Mo];return
r.reverse().join(ho||"")+e}}va.geo={},bt.prototype={s:0,t:0,add:function(n){_t(n,this.t,xo),_t(xo.s,this.s,this),this.s?this.t+=xo.t:this.s=xo.t},reset:function(){this.s=this.t=0},valueOf:function(){return
this.s}};var xo=new
bt;va.geo.stream=function(n,t){n&&bo.hasOwnProperty(n.type)?bo[n.type](n,t):wt(n,t)};var
bo={Feature:function(n,t){wt(n.geometry,t)},FeatureCollection:function(n,t){for(var
e=n.features,r=-1,i=e.length;++r<i;)wt(e[r].geometry,t)}},_o={Sphere:function(n,t){t.sphere()},Point:function(n,t){var
e=n.coordinates;t.point(e[0],e[1])},MultiPoint:function(n,t){for(var
e,r=n.coordinates,i=-1,u=r.length;++i<u;)e=r[i],t.point(e[0],e[1])},LineString:function(n,t){St(n.coordinates,t,0)},MultiLineString:function(n,t){for(var
e=n.coordinates,r=-1,i=e.length;++r<i;)S
t(e[r],t,0)},Polygon:function(n,t){Et(n.coordinates,t)},MultiPolygon:function(n,t){for(var
e=n.coordinates,r=-1,i=e.length;++r<i;)Et(e[r],t)},GeometryCollection:function(n,t){for(var
e=n.geometries,r=-1,i=e.length;++r<i;)wt(e[r],t)}};va.geo.area=function(n){return
wo=0,va.geo.stream(n,Eo),wo};var wo,So=new
bt,Eo={sphere:function(){wo+=4*Ba},point:f,lineStart:f,lineEnd:f,polygonStart:function(){So.reset(),Eo.lineStart=kt},polygonEnd:function(){var
n=2*So;wo+=0>n?4*Ba+n:n,Eo.lineStart=Eo.lineEnd=Eo.point=f}};va.geo.bounds=function(){function
n(n,t){M.push(x=[f=n,h=n]),s>t&&(s=t),t>g&&(g=t)}function t(t,e){var
r=At([t*Ja,e*Ja]);if(v){var i=qt(v,r),u=[i[1],-i[0],0],a=qt(u,i);zt(a),a=Dt(a);var
c=t-p,l=c>0?1:-1,d=a[0]*Ga*l,m=Math.abs(c)>180;if(m^(d>l*p&&l*t>d)){var
y=a[1]*Ga;y>g&&(g=y)}else
if(d=(d+360)%360-180,m^(d>l*p&&l*t>d)){var
y=-a[1]*Ga;s>y&&(s=y)}else
s>e&&(s=e),e>g&&(g=e);m?p>t?o(f,t)>o(f,h)&&(h=t):o(t,h)>o(f,h)&&(f=t):h>=f?(f>t&&(f=t),t>h&&(h=t)):t>p?o(f,t)>o(f,h)&&(h=t)
:o(t,h)>o(f,h)&&(f=t)}else n(t,e);v=r,p=t}function e(){b.point=t}function
r(){x[0]=f,x[1]=h,b.point=n,v=null}function i(n,e){if(v){var
r=n-p;y+=Math.abs(r)>180?r+(r>0?360:-360):r}else
d=n,m=e;Eo.point(n,e),t(n,e)}function u(){Eo.lineStart()}function
a(){i(d,m),Eo.lineEnd(),Math.abs(y)>$a&&(f=-(h=180)),x[0]=f,x[1]=h,v=null}function
o(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return
t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var
f,s,h,g,p,d,m,v,y,M,x,b={point:n,lineStart:e,lineEnd:r,polygonStart:function(){b.point=i,b.lineStart=u,b.lineEnd=a,y=0,Eo.polygonStart()},polygonEnd:function(){Eo.polygonEnd(),b.point=n,b.lineStart=e,b.lineEnd=r,0>So?(f=-(h=180),s=-(g=90)):y>$a?g=90:-$a>y&&(s=-90),x[0]=f,x[1]=h}};return
function(n){g=h=-(f=s=1/0),M=[],va.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var
e,r=1,i=M[0],u=[i];t>r;++r)e=M[r],l(e[0],i)||l(e[1],i)?(o(i[0],e[1])>o(i[0],i[1])&&(i[1]=e[1]),o(e[0],i[1])>o(i[0],i[1])&&(i[0]=e[0])):u.push(i=e
);for(var
a,e,p=-1/0,t=u.length-1,r=0,i=u[t];t>=r;i=e,++r)e=u[r],(a=o(i[1],e[0]))>p&&(p=a,f=e[0],h=i[1])}return
M=x=null,1/0===f||1/0===s?[[0/0,0/0],[0/0,0/0]]:[[f,s],[h,g]]}}(),va.geo.centroid=function(n){ko=Ao=No=qo=To=Co=zo=Do=jo=Lo=Ho=0,va.geo.stream(n,Fo);var
t=jo,e=Lo,r=Ho,i=t*t+e*e+r*r;return
Wa>i&&(t=Co,e=zo,r=Do,$a>Ao&&(t=No,e=qo,r=To),i=t*t+e*e+r*r,Wa>i)?[0/0,0/0]:[Math.atan2(e,t)*Ga,U(r/Math.sqrt(i))*Ga]};var
ko,Ao,No,qo,To,Co,zo,Do,jo,Lo,Ho,Fo={sphere:f,point:Lt,lineStart:Ft,lineEnd:Pt,polygonStart:function(){Fo.lineStart=Ot},polygonEnd:function(){Fo.lineStart=Ft}},Po=It(Rt,$t,Jt,Gt),Oo=[-Ba,0],Ro=1e9;(va.geo.conicEqualArea=function(){return
ee(re)}).raw=re,va.geo.albers=function(){return
va.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},va.geo.albersUsa=function(){function
n(n){var u=n[0],a=n[1];return t=null,e(u,a),t||(r(u,a),t)||i(u,a),t}var
t,e,r,i,u=va.geo.albers(),a=va.geo.conicEqualArea().rotate([154,0]).center([
-2,58.5]).parallels([55,65]),o=va.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=u.scale(),e=u.translate(),r=(n[0]-e[0])/t,i=(n[1]-e[1])/t;return(i>=.12&&.234>i&&r>=-.425&&-.214>r?a:i>=.166&&.234>i&&r>=-.214&&-.115>r?o:u).invert(n)},n.stream=function(n){var
t=u.stream(n),e=a.stream(n),r=o.stream(n);return{point:function(n,i){t.point(n,i),e.point(n,i),r.point(n,i)},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?(u.precision(t),a.precision(t),o.precision(t),n):u.precision()},n.scale=function(t){return
arguments.length?(u.scale(t),a.scale(.35*t),o.scale(t),n.translate(u.tra
nslate())):u.scale()},n.translate=function(t){if(!arguments.length)return
u.translate();var l=u.scale(),f=+t[0],s=+t[1];return
e=u.translate(t).clipExtent([[f-.455*l,s-.238*l],[f+.455*l,s+.238*l]]).stream(c).point,r=a.translate([f-.307*l,s+.201*l]).clipExtent([[f-.425*l+$a,s+.12*l+$a],[f-.214*l-$a,s+.234*l-$a]]).stream(c).point,i=o.translate([f-.205*l,s+.212*l]).clipExtent([[f-.214*l+$a,s+.166*l+$a],[f-.115*l-$a,s+.234*l-$a]]).stream(c).point,n},n.scale(1070)};var
Yo,Uo,Io,Vo,Xo,Zo,Bo={point:f,lineStart:f,lineEnd:f,polygonStart:function(){Uo=0,Bo.lineStart=ie},polygonEnd:function(){Bo.lineStart=Bo.lineEnd=Bo.point=f,Yo+=Math.abs(Uo/2)}},$o={point:ue,lineStart:f,lineEnd:f,polygonStart:f,polygonEnd:f},Wo={point:ce,lineStart:le,lineEnd:fe,polygonStart:function(){Wo.lineStart=se},polygonEnd:function(){Wo.point=ce,Wo.lineStart=le,Wo.lineEnd=fe}};va.geo.path=function(){function
n(n){return n&&("function"==typeof
o&&u.pointRadius(+o.apply(this,arguments)),a&&a.valid||(a=i(u)),va.ge
o.stream(n,a)),u.result()}function t(){return a=null,n}var e,r,i,u,a,o=4.5;return
n.area=function(n){return Yo=0,va.geo.stream(n,i(Bo)),Yo},n.centroid=function(n){return
No=qo=To=Co=zo=Do=jo=Lo=Ho=0,va.geo.stream(n,i(Wo)),Ho?[jo/Ho,Lo/Ho]:Do?[Co/Do,zo/Do]:To?[No/To,qo/To]:[0/0,0/0]},n.bounds=function(n){return
Xo=Zo=-(Io=Vo=1/0),va.geo.stream(n,i($o)),[[Io,Vo],[Xo,Zo]]},n.projection=function(n){return
arguments.length?(i=(e=n)?n.stream||pe(n):st,t()):e},n.context=function(n){return
arguments.length?(u=null==(r=n)?new ae:new he(n),"function"!=typeof
o&&u.pointRadius(o),t()):r},n.pointRadius=function(t){return
arguments.length?(o="function"==typeof
t?t:(u.pointRadius(+t),+t),n):o},n.projection(va.geo.albersUsa()).context(null)},va.geo.projection=de,va.geo.projectionMutator=me,(va.geo.equirectangular=function(){return
de(ye)}).raw=ye.invert=ye,va.geo.rotation=function(n){function t(t){return
t=n(t[0]*Ja,t[1]*Ja),t[0]*=Ga,t[1]*=Ga,t}return
n=Me(n[0]%360*Ja,n[1]*Ja,n.length>2?n[2
]*Ja:0),t.invert=function(t){return
t=n.invert(t[0]*Ja,t[1]*Ja),t[0]*=Ga,t[1]*=Ga,t},t},va.geo.circle=function(){function
n(){var n="function"==typeof
r?r.apply(this,arguments):r,t=Me(-n[0]*Ja,-n[1]*Ja,0).invert,i=[];return
e(null,null,1,{point:function(n,e){i.push(n=t(n,e)),n[0]*=Ga,n[1]*=Ga}}),{type:"Polygon",coordinates:[i]}}var
t,e,r=[0,0],i=6;return n.origin=function(t){return
arguments.length?(r=t,n):r},n.angle=function(r){return
arguments.length?(e=we((t=+r)*Ja,i*Ja),n):t},n.precision=function(r){return
arguments.length?(e=we(t*Ja,(i=+r)*Ja),n):i},n.angle(90)},va.geo.distance=function(n,t){var
e,r=(t[0]-n[0])*Ja,i=n[1]*Ja,u=t[1]*Ja,a=Math.sin(r),o=Math.cos(r),c=Math.sin(i),l=Math.cos(i),f=Math.sin(u),s=Math.cos(u);return
Math.atan2(Math.sqrt((e=s*a)*e+(e=l*f-c*s*o)*e),c*f+l*s*o)},va.geo.graticule=function(){function
n(){return{type:"MultiLineString",coordinates:t()}}function t(){return
va.range(Math.ceil(u/m)*m,i,m).map(h).concat(va.range(Math.ceil(l/v)*v,c,v).map(g))
.concat(va.range(Math.ceil(r/p)*p,e,p).filter(function(n){return
Math.abs(n%m)>$a}).map(f)).concat(va.range(Math.ceil(o/d)*d,a,d).filter(function(n){return
Math.abs(n%v)>$a}).map(s))}var e,r,i,u,a,o,c,l,f,s,h,g,p=10,d=p,m=90,v=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(u).concat(g(c).slice(1),h(i).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return
arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return
arguments.length?(u=+t[0][0],i=+t[1][0],l=+t[0][1],c=+t[1][1],u>i&&(t=u,u=i,i=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[u,l],[i,c]]},n.minorExtent=function(t){return
arguments.length?(r=+t[0][0],e=+t[1][0],o=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),o>a&&(t=o,o=a,a=t),n.precision(y)):[[r,o],[e,a]]},n.step=function(t){return
arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=fu
nction(t){return
arguments.length?(m=+t[0],v=+t[1],n):[m,v]},n.minorStep=function(t){return
arguments.length?(p=+t[0],d=+t[1],n):[p,d]},n.precision=function(t){return
arguments.length?(y=+t,f=Ee(o,a,90),s=ke(r,e,y),h=Ee(l,c,90),g=ke(u,i,y),n):y},n.majorExtent([[-180,-90+$a],[180,90-$a]]).minorExtent([[-180,-80-$a],[180,80+$a]])},va.geo.greatArc=function(){function
n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||i.apply(this,arguments)]}}var
t,e,r=Ae,i=Ne;return n.distance=function(){return
va.geo.distance(t||r.apply(this,arguments),e||i.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?(i=t,e="function"==typeof
t?null:t,n):i},n.precision=function(){return
arguments.length?n:0},n},va.geo.interpolate=function(n,t){return
qe(n[0]*Ja,n[1]*Ja,t[0]*Ja,t[1]*Ja)},va.geo.length=function(n){return
Jo=0,va.geo.stream(n,Go),Jo};var Jo,Go={sphere:f,point:f,line
Start:Te,lineEnd:f,polygonStart:f,polygonEnd:f},Ko=Ce(function(n){return
Math.sqrt(2/(1+n))},function(n){return
2*Math.asin(n/2)});(va.geo.azimuthalEqualArea=function(){return de(Ko)}).raw=Ko;var
Qo=Ce(function(n){var t=Math.acos(n);return
t&&t/Math.sin(t)},st);(va.geo.azimuthalEquidistant=function(){return
de(Qo)}).raw=Qo,(va.geo.conicConformal=function(){return
ee(ze)}).raw=ze,(va.geo.conicEquidistant=function(){return ee(De)}).raw=De;var
nc=Ce(function(n){return 1/n},Math.atan);(va.geo.gnomonic=function(){return
de(nc)}).raw=nc,je.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ba/2]},(va.geo.mercator=function(){return
Le(je)}).raw=je;var tc=Ce(function(){return
1},Math.asin);(va.geo.orthographic=function(){return de(tc)}).raw=tc;var
ec=Ce(function(n){return 1/(1+n)},function(n){return
2*Math.atan(n)});(va.geo.stereographic=function(){return
de(ec)}).raw=ec,He.invert=function(n,t){return[Math.atan2(I(n),Math.cos(t)),U(Math.sin(t)/V(n))]},(va.geo.transverseMercator=
function(){return Le(He)}).raw=He,va.geom={},va.svg={},va.svg.line=function(){return
Fe(st)};var
rc=va.map({linear:Re,"linear-closed":Ye,step:Ue,"step-before":Ie,"step-after":Ve,basis:Je,"basis-open":Ge,"basis-closed":Ke,bundle:Qe,cardinal:Be,"cardinal-open":Xe,"cardinal-closed":Ze,monotone:ur});rc.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)
-});var
ic=[0,2/3,1/3,0],uc=[0,1/3,2/3,0],ac=[0,1/6,2/3,1/6];va.geom.hull=function(n){function
t(n){if(n.length<3)return[];var
t,i,u,a,o,c,l,f,s,h,g,p,d=ft(e),m=ft(r),v=n.length,y=v-1,M=[],x=[],b=0;if(d===Pe&&r===Oe)t=n;else
for(u=0,t=[];v>u;++u)t.push([+d.call(this,i=n[u],u),+m.call(this,i,u)]);for(u=1;v>u;++u)(t[u][1]<t[b][1]||t[u][1]==t[b][1]&&t[u][0]<t[b][0])&&(b=u);for(u=0;v>u;++u)u!==b&&(c=t[u][1]-t[b][1],o=t[u][0]-t[b][0],M.push({angle:Math.atan2(c,o),index:u}));for(M.sort(function(n,t){return
n.angle-t.angle}),g=M[0].angle,h=M[0].index,s=0,u=1;y>u;++u){if(a=M[u].index,g==M[u].angle){if(o=t[h][0]-t[b][0],c=t[h][1]-t[b][1],l=t[a][0]-t[b][0],f=t[a][1]-t[b][1],o*o+c*c>=l*l+f*f){M[u].index=-1;continue}M[s].index=-1}g=M[u].angle,s=u,h=a}for(x.push(b),u=0,a=0;2>u;++a)M[a].index>-1&&(x.push(M[a].index),u++);for(p=x.length;y>a;++a)if(!(M[a].index<0)){for(;!ar(x[p-2],x[p-1],M[a].index,t);)--p;x[p++]=M[a].index}var
_=[];for(u=p-1;u>=0;--u)_.push(n[x[u]]);return _}var e=Pe,r=Oe;r
eturn 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)},va.geom.polygon=function(n){return
n.area=function(){for(var
t=0,e=n.length,r=n[e-1][1]*n[0][0]-n[e-1][0]*n[0][1];++t<e;)r+=n[t-1][1]*n[t][0]-n[t-1][0]*n[t][1];return.5*r},n.centroid=function(t){var
e,r,i=-1,u=n.length,a=0,o=0,c=n[u-1];for(arguments.length||(t=-1/(6*n.area()));++i<u;)e=c,c=n[i],r=e[0]*c[1]-c[0]*e[1],a+=(e[0]+c[0])*r,o+=(e[1]+c[1])*r;return[a*t,o*t]},n.clip=function(t){for(var
e,r,i,u,a,o,c=-1,l=n.length,f=n[l-1];++c<l;){for(e=t.slice(),t.length=0,u=n[c],a=e[(i=e.length)-1],r=-1;++r<i;)o=e[r],or(o,f,u)?(or(a,f,u)||t.push(cr(a,o,f,u)),t.push(o)):or(a,f,u)&&t.push(cr(a,o,f,u)),a=o;f=u}return
t},n},va.geom.delaunay=function(n){var t=n.map(function(){return[]}),e=[];return
lr(n,function(e){t[e.region.l.index].push(n[e.region.r.index])}),t.forEach(function(t,r){var
i=n[r],u=i[0],a=i[1];t.forEach(function(n){n.angle=Math.atan2(n[0]-
u,n[1]-a)}),t.sort(function(n,t){return n.angle-t.angle});for(var
o=0,c=t.length-1;c>o;o++)e.push([i,t[o],t[o+1]])}),e},va.geom.voronoi=function(n){function
t(n){var
t,u,a,o=n.map(function(){return[]}),c=ft(e),l=ft(r),f=n.length,s=1e6;if(c===Pe&&l===Oe)t=n;else
for(t=new
Array(f),a=0;f>a;++a)t[a]=[+c.call(this,u=n[a],a),+l.call(this,u,a)];if(lr(t,function(n){var
t,e,r,i,u,a;1===n.a&&n.b>=0?(t=n.ep.r,e=n.ep.l):(t=n.ep.l,e=n.ep.r),1===n.a?(u=t?t.y:-s,r=n.c-n.b*u,a=e?e.y:s,i=n.c-n.b*a):(r=t?t.x:-s,u=n.c-n.a*r,i=e?e.x:s,a=n.c-n.a*i);var
c=[r,u],l=[i,a];o[n.region.l.index].push(c,l),o[n.region.r.index].push(c,l)}),o=o.map(function(n,e){var
r=t[e][0],i=t[e][1],u=n.map(function(n){return
Math.atan2(n[0]-r,n[1]-i)}),a=va.range(n.length).sort(function(n,t){return
u[n]-u[t]});return
a.filter(function(n,t){return!t||u[n]-u[a[t-1]]>$a}).map(function(t){return
n[t]})}),o.forEach(function(n,e){var r=n.length;if(!r)return
n.push([-s,-s],[-s,s],[s,s],[s,-s]);if(!(r>2)){var i=t[e],u=n[0],a=n
[1],o=i[0],c=i[1],l=u[0],f=u[1],h=a[0],g=a[1],p=Math.abs(h-l),d=g-f;if(Math.abs(d)<$a){var
m=f>c?-s:s;n.push([-s,m],[s,m])}else if($a>p){var
v=l>o?-s:s;n.push([v,-s],[v,s])}else{var
m=(l-o)*(g-f)>(h-l)*(f-c)?s:-s,y=Math.abs(d)-p;Math.abs(y)<$a?n.push([0>d?m:-m,m]):(y>0&&(m*=-1),n.push([-s,m],[s,m]))}}}),i)for(a=0;f>a;++a)i.clip(o[a]);for(a=0;f>a;++a)o[a].point=n[a];return
o}var e=Pe,r=Oe,i=null;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.clipExtent=function(n){if(!arguments.length)return
i&&[i[0],i[2]];if(null==n)i=null;else{var
e=+n[0][0],r=+n[0][1],u=+n[1][0],a=+n[1][1];i=va.geom.polygon([[e,r],[e,a],[u,a],[u,r]])}return
t},t.size=function(n){return
arguments.length?t.clipExtent(n&&[[0,0],n]):i&&i[2]},t.links=function(n){var
t,i,u,a=n.map(function(){return[]}),o=[],c=ft(e),l=ft(r),f=n.length;if(c===Pe&&l===Oe)t=n;else
for(t=new Array(f),u=0;f>u;++u)t[u]=[+c.call(this,i=n[u],u),+l.call
(this,i,u)];return lr(t,function(t){var
e=t.region.l.index,r=t.region.r.index;a[e][r]||(a[e][r]=a[r][e]=!0,o.push({source:n[e],target:n[r]}))}),o},t.triangles=function(n){if(e===Pe&&r===Oe)return
va.geom.delaunay(n);for(var t,i=new
Array(c),u=ft(e),a=ft(r),o=-1,c=n.length;++o<c;)(i[o]=[+u.call(this,t=n[o],o),+a.call(this,t,o)]).data=t;return
va.geom.delaunay(i).map(function(n){return n.map(function(n){return n.data})})},t)};var
oc={l:"r",r:"l"};va.geom.quadtree=function(n,t,e,r,i){function
u(n){function u(n,t,e,r,i,u,a,o){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var
c=n.x,f=n.y;if(null!=c)if(Math.abs(c-e)+Math.abs(f-r)<.01)l(n,t,e,r,i,u,a,o);else{var
s=n.point;n.x=n.y=n.point=null,l(n,s,c,f,i,u,a,o),l(n,t,e,r,i,u,a,o)}else
n.x=e,n.y=r,n.point=t}else l(n,t,e,r,i,u,a,o)}function l(n,t,e,r,i,a,o,c){var
l=.5*(i+o),f=.5*(a+c),s=e>=l,h=r>=f,g=(h<<1)+s;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=hr()),s?i=l:o=l,h?a=f:c=f,u(n,t,e,r,i,a,o,c)}var
f,s,h,g,p,d,m,v,y,M=ft(o),x=ft(c);if(null!=t)d=t,m=e
,v=r,y=i;else
if(v=y=-(d=m=1/0),s=[],h=[],p=n.length,a)for(g=0;p>g;++g)f=n[g],f.x<d&&(d=f.x),f.y<m&&(m=f.y),f.x>v&&(v=f.x),f.y>y&&(y=f.y),s.push(f.x),h.push(f.y);else
for(g=0;p>g;++g){var
b=+M(f=n[g],g),_=+x(f,g);d>b&&(d=b),m>_&&(m=_),b>v&&(v=b),_>y&&(y=_),s.push(b),h.push(_)}var
w=v-d,S=y-m;w>S?y=m+w:v=d+S;var
E=hr();if(E.add=function(n){u(E,n,+M(n,++g),+x(n,g),d,m,v,y)},E.visit=function(n){gr(n,E,d,m,v,y)},g=-1,null==t){for(;++g<p;)u(E,n[g],s[g],h[g],d,m,v,y);--g}else
n.forEach(E.add);return s=h=n=f=null,E}var
a,o=Pe,c=Oe;return(a=arguments.length)?(o=fr,c=sr,3===a&&(i=e,r=t,e=t=0),u(n)):(u.x=function(n){return
arguments.length?(o=n,u):o},u.y=function(n){return
arguments.length?(c=n,u):c},u.extent=function(n){return
arguments.length?(null==n?t=e=r=i=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],i=+n[1][1]),u):null==t?null:[[t,e],[r,i]]},u.size=function(n){return
arguments.length?(null==n?t=e=r=i=null:(t=e=0,r=+n[0],i=+n[1]),u):null==t?null:[r-t,i-e]},u)},va.interpolateRgb=pr,va.t
ransform=function(n){var
t=ya.createElementNS(va.ns.prefix.svg,"g");return(va.transform=function(n){if(null!=n){t.setAttribute("transform",n);var
e=t.transform.baseVal.consolidate()}return new
dr(e?e.matrix:cc)})(n)},dr.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var
cc={a:1,b:0,c:0,d:1,e:0,f:0};va.interpolateNumber=Mr,va.interpolateTransform=xr,va.interpolateObject=br,va.interpolateString=_r;var
lc=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;va.interpolate=wr,va.interpolators=[function(n,t){var
e=typeof t;return("string"===e?uo.has(t)||/^(#|rgb\(|hsl\()/.test(t)?pr:_r:t
instanceof
H?pr:"object"===e?Array.isArray(t)?Er:br:Mr)(n,t)}],va.interpolateArray=Er;var
fc=function(){return st},sc=va.map({linear:fc,poly:zr,quad:function(){return
qr},cubic:function(){return Tr},sin:function(){return Dr},exp:function(){return
jr},circle:function(){return Lr},elastic:Hr,back:Fr,bounce:function(){ret
urn
Pr}}),hc=va.map({"in":st,out:Ar,"in-out":Nr,"out-in":function(n){return
Nr(Ar(n))}});va.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=sc.get(e)||fc,r=hc.get(r)||st,kr(r(e.apply(null,Array.prototype.slice.call(arguments,1))))},va.interpolateHcl=Or,va.interpolateHsl=Rr,va.interpolateLab=Yr,va.interpolateRound=Ur,va.layout={},va.layout.bundle=function(){return
function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Xr(n[e]));return
t}},va.layout.chord=function(){function n(){var
n,l,s,h,g,p={},d=[],m=va.range(u),v=[];for(e=[],r=[],n=0,h=-1;++h<u;){for(l=0,g=-1;++g<u;)l+=i[h][g];d.push(l),v.push(va.range(u)),n+=l}for(a&&m.sort(function(n,t){return
a(d[n],d[t])}),o&&v.forEach(function(n,t){n.sort(function(n,e){return
o(i[t][n],i[t][e])})}),n=(2*Ba-f*u)/n,l=0,h=-1;++h<u;){for(s=l,g=-1;++g<u;){var
y=m[h],M=v[y][g],x=i[y][M],b=l,_=l+=x*n;p[y+"-"+M]={index:y,subindex:M,startAngle:b,endAngle:_,value:x}}r[y]={index:y,startAngle
:s,endAngle:l,value:(l-s)/n},l+=f}for(h=-1;++h<u;)for(g=h-1;++g<u;){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,i,u,a,o,c,l={},f=0;return l.matrix=function(n){return
arguments.length?(u=(i=n)&&i.length,e=r=null,l):i},l.padding=function(n){return
arguments.length?(f=n,e=r=null,l):f},l.sortGroups=function(n){return
arguments.length?(a=n,e=r=null,l):a},l.sortSubgroups=function(n){return
arguments.length?(o=n,e=null,l):o},l.sortChords=function(n){return
arguments.length?(c=n,e&&t(),l):c},l.chords=function(){return
e||n(),e},l.groups=function(){return r||n(),r},l},va.layout.force=function(){function
n(n){return function(t,e,r,i){if(t.point!==n){var
u=t.cx-n.x,a=t.cy-n.y,o=1/Math.sqrt(u*u+a*a);if(d>(i-e)*o){var c=t.charge*o*o;return
n.px-=u*c,n.py-=a*c,!0}if(t.point&&isFinite(o)){var c
=t.pointCharge*o*o;n.px-=u*c,n.py-=a*c}}return!t.charge}}function
t(n){n.px=va.event.x,n.py=va.event.y,o.resume()}var
e,r,i,u,a,o={},c=va.dispatch("start","tick","end"),l=[1,1],f=.9,s=gc,h=pc,g=-30,p=.1,d=.8,m=[],v=[];return
o.tick=function(){if((r*=.99)<.005)return
c.end({type:"end",alpha:r=0}),!0;var
t,e,o,s,h,d,y,M,x,b=m.length,_=v.length;for(e=0;_>e;++e)o=v[e],s=o.source,h=o.target,M=h.x-s.x,x=h.y-s.y,(d=M*M+x*x)&&(d=r*u[e]*((d=Math.sqrt(d))-i[e])/d,M*=d,x*=d,h.x-=M*(y=s.weight/(h.weight+s.weight)),h.y-=x*y,s.x+=M*(y=1-y),s.y+=x*y);if((y=r*p)&&(M=l[0]/2,x=l[1]/2,e=-1,y))for(;++e<b;)o=m[e],o.x+=(M-o.x)*y,o.y+=(x-o.y)*y;if(g)for(Kr(t=va.geom.quadtree(m),r,a),e=-1;++e<b;)(o=m[e]).fixed||t.visit(n(o));for(e=-1;++e<b;)o=m[e],o.fixed?(o.x=o.px,o.y=o.py):(o.x-=(o.px-(o.px=o.x))*f,o.y-=(o.py-(o.py=o.y))*f);c.tick({type:"tick",alpha:r})},o.nodes=function(n){return
arguments.length?(m=n,o):m},o.links=function(n){return
arguments.length?(v=n,o):v},o.size=function(n){return argument
s.length?(l=n,o):l},o.linkDistance=function(n){return
arguments.length?(s="function"==typeof
n?n:+n,o):s},o.distance=o.linkDistance,o.linkStrength=function(n){return
arguments.length?(h="function"==typeof
n?n:+n,o):h},o.friction=function(n){return
arguments.length?(f=+n,o):f},o.charge=function(n){return
arguments.length?(g="function"==typeof n?n:+n,o):g},o.gravity=function(n){return
arguments.length?(p=+n,o):p},o.theta=function(n){return
arguments.length?(d=+n,o):d},o.alpha=function(n){return
arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),va.timer(o.tick)),o):r},o.start=function(){function
n(n,r){for(var i,u=t(e),a=-1,o=u.length;++a<o;)if(!isNaN(i=u[a][n]))return i;return
Math.random()*r}function
t(){if(!c){for(c=[],r=0;p>r;++r)c[r]=[];for(r=0;d>r;++r){var
n=v[r];c[n.source.index].push(n.target),c[n.target.index].push(n.source)}}return c[e]}var
e,r,c,f,p=m.length,d=v.length,y=l[0],M=l[1];for(e=0;p>e;++e)(f=m[e]).index=e,f.weight=0;for(e=0;d>e;++e)
f=v[e],"number"==typeof
f.source&&(f.source=m[f.source]),"number"==typeof
f.target&&(f.target=m[f.target]),++f.source.weight,++f.target.weight;for(e=0;p>e;++e)f=m[e],isNaN(f.x)&&(f.x=n("x",y)),isNaN(f.y)&&(f.y=n("y",M)),isNaN(f.px)&&(f.px=f.x),isNaN(f.py)&&(f.py=f.y);if(i=[],"function"==typeof
s)for(e=0;d>e;++e)i[e]=+s.call(this,v[e],e);else
for(e=0;d>e;++e)i[e]=s;if(u=[],"function"==typeof
h)for(e=0;d>e;++e)u[e]=+h.call(this,v[e],e);else
for(e=0;d>e;++e)u[e]=h;if(a=[],"function"==typeof
g)for(e=0;p>e;++e)a[e]=+g.call(this,m[e],e);else for(e=0;p>e;++e)a[e]=g;return
o.resume()},o.resume=function(){return o.alpha(.1)},o.stop=function(){return
o.alpha(0)},o.drag=function(){return
e||(e=va.behavior.drag().origin(st).on("dragstart.force",$r).on("drag.force",t).on("dragend.force",Wr)),arguments.length?(this.on("mouseover.force",Jr).on("mouseout.force",Gr).call(e),void
0):e},va.rebind(o,c,"on")};var
gc=20,pc=1;va.layout.hierarchy=function(){function n(t,a,o){var c=i.call(e,t,a);if(
t.depth=a,o.push(t),c&&(l=c.length)){for(var
l,f,s=-1,h=t.children=[],g=0,p=a+1;++s<l;)f=n(c[s],p,o),f.parent=t,h.push(f),g+=f.value;r&&h.sort(r),u&&(t.value=g)}else
u&&(t.value=+u.call(e,t,a)||0);return t}function t(n,r){var
i=n.children,a=0;if(i&&(o=i.length))for(var
o,c=-1,l=r+1;++c<o;)a+=t(i[c],l);else u&&(a=+u.call(e,n,r)||0);return
u&&(n.value=a),a}function e(t){var e=[];return n(t,0,e),e}var
r=ei,i=ni,u=ti;return e.sort=function(n){return
arguments.length?(r=n,e):r},e.children=function(n){return
arguments.length?(i=n,e):i},e.value=function(n){return
arguments.length?(u=n,e):u},e.revalue=function(n){return
t(n,0),n},e},va.layout.partition=function(){function n(t,e,r,i){var
u=t.children;if(t.x=e,t.y=t.depth*i,t.dx=r,t.dy=i,u&&(a=u.length)){var
a,o,c,l=-1;for(r=t.value?r/t.value:0;++l<a;)n(o=u[l],e,c=o.value*r,i),e+=c}}function
t(n){var e=n.children,r=0;if(e&&(i=e.length))for(var
i,u=-1;++u<i;)r=Math.max(r,t(e[u]));return 1+r}function e(e,u){var
a=r.call(this,e,u);return
n(a[0],0,i[0],i[1]/t(a[0])),a}var r=va.layout.hierarchy(),i=[1,1];return
e.size=function(n){return
arguments.length?(i=n,e):i},Qr(e,r)},va.layout.pie=function(){function n(u){var
a=u.map(function(e,r){return+t.call(n,e,r)}),o=+("function"==typeof
r?r.apply(this,arguments):r),c=(("function"==typeof
i?i.apply(this,arguments):i)-o)/va.sum(a),l=va.range(u.length);null!=e&&l.sort(e===dc?function(n,t){return
a[t]-a[n]}:function(n,t){return e(u[n],u[t])});var f=[];return l.forEach(function(n){var
t;f[n]={data:u[n],value:t=a[n],startAngle:o,endAngle:o+=t*c}}),f}var
t=Number,e=dc,r=0,i=2*Ba;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?(i=t,n):i},n};var dc={};va.layout.stack=function(){function n(o,c){var
l=o.map(function(e,r){return t.call(n,e,r)}),f=l.map(function(t){return
t.map(function(t,e){return[u.call
(n,t,e),a.call(n,t,e)]})}),s=e.call(n,f,c);l=va.permute(l,s),f=va.permute(f,s);var
h,g,p,d=r.call(n,f,c),m=l.length,v=l[0].length;for(g=0;v>g;++g)for(i.call(n,l[0][g],p=d[g],f[0][g][1]),h=1;m>h;++h)i.call(n,l[h][g],p+=f[h-1][g][1],f[h][g][1]);return
o}var t=st,e=oi,r=ci,i=ai,u=ii,a=ui;return n.values=function(e){return
arguments.length?(t=e,n):t},n.order=function(t){return
arguments.length?(e="function"==typeof
t?t:mc.get(t)||oi,n):e},n.offset=function(t){return
arguments.length?(r="function"==typeof
t?t:vc.get(t)||ci,n):r},n.x=function(t){return
arguments.length?(u=t,n):u},n.y=function(t){return
arguments.length?(a=t,n):a},n.out=function(t){return arguments.length?(i=t,n):i},n};var
mc=va.map({"inside-out":function(n){var
t,e,r=n.length,i=n.map(li),u=n.map(fi),a=va.range(r).sort(function(n,t){return
i[n]-i[t]}),o=0,c=0,l=[],f=[];for(t=0;r>t;++t)e=a[t],c>o?(o+=u[e],l.push(e)):(c+=u[e],f.push(e));return
f.reverse().concat(l)},reverse:function(n){return va.range(n.length).rever
se()},"default":oi}),vc=va.map({silhouette:function(n){var
t,e,r,i=n.length,u=n[0].length,a=[],o=0,c=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];r>o&&(o=r),a.push(r)}for(e=0;u>e;++e)c[e]=(o-a[e])/2;return
c},wiggle:function(n){var
t,e,r,i,u,a,o,c,l,f=n.length,s=n[0],h=s.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,i=0;f>t;++t)i+=n[t][e][1];for(t=0,u=0,o=s[e][0]-s[e-1][0];f>t;++t){for(r=0,a=(n[t][e][1]-n[t][e-1][1])/(2*o);t>r;++r)a+=(n[r][e][1]-n[r][e-1][1])/o;u+=a*n[t][e][1]}g[e]=c-=i?u/i*o:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return
g},expand:function(n){var
t,e,r,i=n.length,u=n[0].length,a=1/i,o=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];if(r)for(t=0;i>t;t++)n[t][e][1]/=r;else
for(t=0;i>t;t++)n[t][e][1]=a}for(e=0;u>e;++e)o[e]=0;return
o},zero:ci});va.layout.histogram=function(){function n(n,u){for(var
a,o,c=[],l=n.map(e,this),f=r.call(this,l,u),s=i.call(this,f,l,u),u=-1,h=l.length,g=s.length-1,p=t?1:1/h;++u<g;)a=c[u]=[],a.dx=s[u+1]-(a.x=s[u]),a.y=0;
if(g>0)for(u=-1;++u<h;)o=l[u],o>=f[0]&&o<=f[1]&&(a=c[va.bisect(s,o,1,g)-1],a.y+=p,a.push(n[u]));return
c}var t=!0,e=Number,r=pi,i=hi;return n.value=function(t){return
arguments.length?(e=t,n):e},n.range=function(t){return
arguments.length?(r=ft(t),n):r},n.bins=function(t){return
arguments.length?(i="number"==typeof t?function(n){return
gi(n,t)}:ft(t),n):i},n.frequency=function(e){return
arguments.length?(t=!!e,n):t},n},va.layout.tree=function(){function n(n,u){function
a(n,t){var r=n.children,i=n._tree;if(r&&(u=r.length)){for(var
u,o,l,f=r[0],s=f,h=-1;++h<u;)l=r[h],a(l,o),s=c(l,o,s),o=l;wi(n);var
g=.5*(f._tree.prelim+l._tree.prelim);t?(i.prelim=t._tree.prelim+e(n,t),i.mod=i.prelim-g):i.prelim=g}else
t&&(i.prelim=t._tree.prelim+e(n,t))}function o(n,t){n.x=n._tree.prelim+t;var
e=n.children;if(e&&(r=e.length)){var
r,i=-1;for(t+=n._tree.mod;++i<r;)o(e[i],t)}}function c(n,t,r){if(t){for(var
i,u=n,a=n,o=t,c=n.parent.children[0],l=u._tree.mod,f=a._tree.mod,s=o._tree.mod,h=c._tree.m
od;o=vi(o),u=mi(u),o&&u;)c=mi(c),a=vi(a),a._tree.ancestor=n,i=o._tree.prelim+s-u._tree.prelim-l+e(o,u),i>0&&(Si(Ei(o,n,r),n,i),l+=i,f+=i),s+=o._tree.mod,l+=u._tree.mod,h+=c._tree.mod,f+=a._tree.mod;o&&!vi(a)&&(a._tree.thread=o,a._tree.mod+=s-f),u&&!mi(c)&&(c._tree.thread=u,c._tree.mod+=l-h,r=n)}return
r}var
l=t.call(this,n,u),f=l[0];_i(f,function(n,t){n._tree={ancestor:n,prelim:0,mod:0,change:0,shift:0,number:t?t._tree.number+1:0}}),a(f),o(f,-f._tree.prelim);var
s=yi(f,xi),h=yi(f,Mi),g=yi(f,bi),p=s.x-e(s,h)/2,d=h.x+e(h,s)/2,m=g.depth||1;return
_i(f,i?function(n){n.x*=r[0],n.y=n.depth*r[1],delete
n._tree}:function(n){n.x=(n.x-p)/(d-p)*r[0],n.y=n.depth/m*r[1],delete n._tree}),l}var
t=va.layout.hierarchy().sort(null).value(null),e=di,r=[1,1],i=!1;return
n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return
arguments.length?(i=null==(r=t),n):i?null:r},n.nodeSize=function(t){return
arguments.length?(i=null!=(r=t),n):i?r:null},Qr(n,t)},va.layout.pac
k=function(){function n(n,u){var
a=e.call(this,n,u),o=a[0],c=i[0],l=i[1],f=t||Math.sqrt;if(o.x=o.y=0,_i(o,function(n){n.r=f(n.value)}),_i(o,Ti),r){var
s=r*(t?1:Math.max(2*o.r/c,2*o.r/l))/2;_i(o,function(n){n.r+=s}),_i(o,Ti),_i(o,function(n){n.r-=s})}return
Di(o,c/2,l/2,t?1:1/Math.max(2*o.r/c,2*o.r/l)),a}var
t,e=va.layout.hierarchy().sort(ki),r=0,i=[1,1];return n.size=function(t){return
arguments.length?(i=t,n):i},n.radius=function(e){return
arguments.length?(t=e,n):t},n.padding=function(t){return
arguments.length?(r=+t,n):r},Qr(n,e)},va.layout.cluster=function(){function n(n,u){var
a,o=t.call(this,n,u),c=o[0],l=0;_i(c,function(n){var
t=n.children;t&&t.length?(n.x=Hi(t),n.y=Li(t)):(n.x=a?l+=e(n,a):0,n.y=0,a=n)});var
f=Fi(c),s=Pi(c),h=f.x-e(f,s)/2,g=s.x+e(s,f)/2;return
_i(c,i?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]}),o}var
t=va.layout.hierarchy().sort(null).value(null),e=di,r=[1,1],i=!1;return n.separat
ion=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return
arguments.length?(i=null==(r=t),n):i?null:r},n.nodeSize=function(t){return
arguments.length?(i=null!=(r=t),n):i?r:null},Qr(n,t)},va.layout.treemap=function(){function
n(n,t){for(var
e,r,i=-1,u=n.length;++i<u;)r=(e=n[i]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function
t(e){var u=e.children;if(u&&u.length){var
a,o,c,l=s(e),f=[],h=u.slice(),p=1/0,d="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),f.area=0;(c=h.length)>0;)f.push(a=h[c-1]),f.area+=a.area,"squarify"!==g||(o=r(f,d))<=p?(h.pop(),p=o):(f.area-=f.pop().area,i(f,d,l,!1),d=Math.min(l.dx,l.dy),f.length=f.area=0,p=1/0);f.length&&(i(f,d,l,!0),f.length=f.area=0),u.forEach(t)}}function
e(t){var r=t.children;if(r&&r.length){var
u,a=s(t),o=r.slice(),c=[];for(n(o,a.dx*a.dy/t.value),c.area=0;u=o.pop();)c.push(u),c.area+=u.area,null!=u.z&&(i(c,u.z?a.dx:a.dy,a,!o.length),c.length=c.are
a=0);r.forEach(e)}}function r(n,t){for(var
e,r=n.area,i=0,u=1/0,a=-1,o=n.length;++a<o;)(e=n[a].area)&&(u>e&&(u=e),e>i&&(i=e));return
r*=r,t*=t,r?Math.max(t*i*p/r,r/(t*u*p)):1/0}function i(n,t,e,r){var
i,u=-1,a=n.length,o=e.x,l=e.y,f=t?c(n.area/t):0;if(t==e.dx){for((r||f>e.dy)&&(f=e.dy);++u<a;)i=n[u],i.x=o,i.y=l,i.dy=f,o+=i.dx=Math.min(e.x+e.dx-o,f?c(i.area/f):0);i.z=!0,i.dx+=e.x+e.dx-o,e.y+=f,e.dy-=f}else{for((r||f>e.dx)&&(f=e.dx);++u<a;)i=n[u],i.x=o,i.y=l,i.dx=f,l+=i.dy=Math.min(e.y+e.dy-l,f?c(i.area/f):0);i.z=!1,i.dy+=e.y+e.dy-l,e.x+=f,e.dx-=f}}function
u(r){var i=a||o(r),u=i[0];return
u.x=0,u.y=0,u.dx=l[0],u.dy=l[1],a&&o.revalue(u),n([u],u.dx*u.dy/u.value),(a?e:t)(u),h&&(a=i),i}var
a,o=va.layout.hierarchy(),c=Math.round,l=[1,1],f=null,s=Oi,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));return
u.size=function(n){return arguments.length?(l=n,u):l},u.padding=function(n){function
t(t){var e=n.call(u,t,t.depth);return null==e?Oi(t):Ri(t,"number"==typeof
e?[e,e,e,e]:e)}function e(t){r
eturn Ri(t,n)}if(!arguments.length)return f;var r;return
s=null==(f=n)?Oi:"function"==(r=typeof
n)?t:"number"===r?(n=[n,n,n,n],e):e,u},u.round=function(n){return
arguments.length?(c=n?Math.round:Number,u):c!=Number},u.sticky=function(n){return
arguments.length?(h=n,a=null,u):h},u.ratio=function(n){return
arguments.length?(p=n,u):p},u.mode=function(n){return
arguments.length?(g=n+"",u):g},Qr(u,o)},va.random={normal:function(n,t){var
e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var
e,r,i;do e=2*Math.random()-1,r=2*Math.random()-1,i=e*e+r*r;while(!i||i>1);return
n+t*e*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var
n=va.random.normal.apply(va,arguments);return function(){return
Math.exp(n())}},irwinHall:function(n){return function(){for(var
t=0,e=0;n>e;e++)t+=Math.random();return t/n}}},va.scale={};var
yc={floor:st,ceil:st};va.scale.linear=function(){return
Bi([0,1],[0,1],wr,!1)},va.scale.log=function(){return
nu(va.scale.linear().domain([0,Math.LN10]),10,t
u,eu,[1,10])};var Mc=va.format(".0e");va.scale.pow=function(){return
uu(va.scale.linear(),1,[0,1])},va.scale.sqrt=function(){return
va.scale.pow().exponent(.5)},va.scale.ordinal=function(){return
ou([],{t:"range",a:[[]]})},va.scale.category10=function(){return
va.scale.ordinal().range(xc)},va.scale.category20=function(){return
va.scale.ordinal().range(bc)},va.scale.category20b=function(){return
va.scale.ordinal().range(_c)},va.scale.category20c=function(){return
va.scale.ordinal().range(wc)};var
xc=["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf"],bc=["#1f77b4","#aec7e8","#ff7f0e","#ffbb78","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5","#8c564b","#c49c94","#e377c2","#f7b6d2","#7f7f7f","#c7c7c7","#bcbd22","#dbdb8d","#17becf","#9edae5"],_c=["#393b79","#5254a3","#6b6ecf","#9c9ede","#637939","#8ca252","#b5cf6b","#cedb9c","#8c6d31","#bd9e39","#e7ba52","#e7cb94","#843c39","#ad494a","#d6616b","#e7969c","#7b4173","#a5
5194","#ce6dbd","#de9ed6"],wc=["#3182bd","#6baed6","#9ecae1","#c6dbef","#e6550d","#fd8d3c","#fdae6b","#fdd0a2","#31a354","#74c476","#a1d99b","#c7e9c0","#756bb1","#9e9ac8","#bcbddc","#dadaeb","#636363","#969696","#bdbdbd","#d9d9d9"];va.scale.quantile=function(){return
cu([],[])},va.scale.quantize=function(){return
lu(0,1,[0,1])},va.scale.threshold=function(){return
fu([.5],[0,1])},va.scale.identity=function(){return
su([0,1])},va.svg.arc=function(){function n(){var
n=t.apply(this,arguments),u=e.apply(this,arguments),a=r.apply(this,arguments)+Sc,o=i.apply(this,arguments)+Sc,c=(a>o&&(c=a,a=o,o=c),o-a),l=Ba>c?"0":"1",f=Math.cos(a),s=Math.sin(a),h=Math.cos(o),g=Math.sin(o);return
c>=Ec?n?"M0,"+u+"A"+u+","+u+" 0 1,1
0,"+-u+"A"+u+","+u+" 0 1,1
0,"+u+"M0,"+n+"A"+n+","+n+" 0 1,0
0,"+-n+"A"+n+","+n+" 0 1,0
0,"+n+"Z":"M0,"+u+"A"+u+","+u+" 0 1,1
0,"+-u+"A"+u+","+u+" 0 1,1
0,"+u+"Z":n?"M"+u*f+","+u*s+"A"+u+","+u+"
0 "+l+",1
"+u*h+","+u*g+"L"+n*h+","+n*g+"A"+n+","+n+"
0 "+l+",0 "+n*f+","+
n*s+"Z":"M"+u*f+","+u*s+"A"+u+","+u+"
0 "+l+",1 "+u*h+","+u*g+"L0,0"+"Z"}var
t=hu,e=gu,r=pu,i=du;return n.innerRadius=function(e){return
arguments.length?(t=ft(e),n):t},n.outerRadius=function(t){return
arguments.length?(e=ft(t),n):e},n.startAngle=function(t){return
arguments.length?(r=ft(t),n):r},n.endAngle=function(t){return
arguments.length?(i=ft(t),n):i},n.centroid=function(){var
n=(t.apply(this,arguments)+e.apply(this,arguments))/2,u=(r.apply(this,arguments)+i.apply(this,arguments))/2+Sc;return[Math.cos(u)*n,Math.sin(u)*n]},n};var
Sc=-Ba/2,Ec=2*Ba-1e-6;va.svg.line.radial=function(){var n=Fe(mu);return
n.radius=n.x,delete n.x,n.angle=n.y,delete
n.y,n},Ie.reverse=Ve,Ve.reverse=Ie,va.svg.area=function(){return
vu(st)},va.svg.area.radial=function(){var n=vu(mu);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},va.svg.chord=function(){function n(n,o){
var
c=t(this,u,n,o),l=t(this,a,n,o);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?i(c.r,c.p1,c.r,c.p0):i(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+i(l.r,l.p1,c.r,c.p0))+"Z"}function
t(n,t,e,r){var
i=t.call(n,e,r),u=o.call(n,i,r),a=c.call(n,i,r)+Sc,f=l.call(n,i,r)+Sc;return{r:u,a0:a,a1:f,p0:[u*Math.cos(a),u*Math.sin(a)],p1:[u*Math.cos(f),u*Math.sin(f)]}}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 i(n,t,e,r){return"Q 0,0 "+r}var
u=Ae,a=Ne,o=yu,c=pu,l=du;return n.radius=function(t){return
arguments.length?(o=ft(t),n):o},n.source=function(t){return
arguments.length?(u=ft(t),n):u},n.target=function(t){return
arguments.length?(a=ft(t),n):a},n.startAngle=function(t){return
arguments.length?(c=ft(t),n):c},n.endAngle=function(t){return
arguments.length?(l=ft(t),n):l},n},va.svg.diagonal=function(){function n(n,i){var
u=t.call(this,n,i),a=e.call(this,n,i),o=(u.y+a.y)/2,c=[u,{x:u.x,y:o},{x:a.x,y:o},a];return
c=c.map(r),
"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var
t=Ae,e=Ne,r=Mu;return n.source=function(e){return
arguments.length?(t=ft(e),n):t},n.target=function(t){return
arguments.length?(e=ft(t),n):e},n.projection=function(t){return
arguments.length?(r=t,n):r},n},va.svg.diagonal.radial=function(){var
n=va.svg.diagonal(),t=Mu,e=n.projection;return n.projection=function(n){return
arguments.length?e(xu(t=n)):t},n},va.svg.symbol=function(){function
n(n,r){return(kc.get(t.call(this,n,r))||wu)(e.call(this,n,r))}var t=_u,e=bu;return
n.type=function(e){return arguments.length?(t=ft(e),n):t},n.size=function(t){return
arguments.length?(e=ft(t),n):e},n};var kc=va.map({circle:wu,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*qc)),e=t*qc;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/Nc),e=t*Nc/2;return"M0,"+e+"L"+t+","+-e+"
"+-t+","+-e+"Z"},"triangle-up":function(n){var
t=Math.sqrt(n/Nc),e=t*Nc/2;return"M0,"+-e+"L"+t+","+e+"
"+-t+","+e+"Z"}});va.svg.symbolTypes=kc.keys();var
Ac,Nc=Math.sqrt(3),qc=Math.tan(30*Ja),Tc=[],Cc=0,zc={ease:Cr,delay:0,duration:250};Tc.call=Ha.call,Tc.empty=Ha.empty,Tc.node=Ha.node,Tc.size=Ha.size,va.transition=function(n){return
arguments.length?Ac?n.transition():n:Oa.transition()},va.transition.prototype=Tc,Tc.select=function(n){var
t,e,r,i=this.id,u=[];"function"!=typeof n&&(n=v(n));for(var
a=-1,o=this.length;++a<o;){u.push(t=[]);for(var
c=this[a],l=-1,f=c.length;++l<f;)(r=c[l])&&(e=n.call(r,r.__data__,l))?("__data__"in
r&&(e.__data__=r.__data__),Au(e,l,i,r.__transition__[i]),t.push(e)):t.push(null)}return
Su(u,i)},Tc.selectAll=function(n){var
t,e,r,i,u,a=this.id,o=[];"function"!=typeof n&&(n=y(n));for(var
c=-1,l=this.length;++c<l;)for(var f=this[c],s=-1,h=f.l
ength;++s<h;)if(r=f[s]){u=r.__transition__[a],e=n.call(r,r.__data__,s),o.push(t=[]);for(var
g=-1,p=e.length;++g<p;)(i=e[g])&&Au(i,g,a,u),t.push(i)}return
Su(o,a)},Tc.filter=function(n){var t,e,r,i=[];"function"!=typeof
n&&(n=A(n));for(var u=0,a=this.length;a>u;u++){i.push(t=[]);for(var
e=this[u],o=0,c=e.length;c>o;o++)(r=e[o])&&n.call(r,r.__data__,o)&&t.push(r)}return
Su(i,this.id,this.time).ease(this.ease())},Tc.tween=function(n,t){var e=this.id;return
arguments.length<2?this.node().__transition__[e].tween.get(n):q(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Tc.attr=function(n,t){function
e(){this.removeAttribute(o)}function r(){this.removeAttributeNS(o.space,o.local)}function
i(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(o);return
e!==n&&(t=a(e,n),function(n){this.setAttribute(o,t(n))})})}function u(n){return
null==n?r:(n+="",function(){var t,e=this.getAttributeNS(o.space,o.local);retur
n
e!==n&&(t=a(e,n),function(n){this.setAttributeNS(o.space,o.local,t(n))})})}if(arguments.length<2){for(t
in n)this.attr(t,n[t]);return this}var a=Sr(n),o=va.ns.qualify(n);return
Eu(this,"attr."+n,t,o.local?u:i)},Tc.attrTween=function(n,t){function e(n,e){var
r=t.call(this,n,e,this.getAttribute(i));return
r&&function(n){this.setAttribute(i,r(n))}}function r(n,e){var
r=t.call(this,n,e,this.getAttributeNS(i.space,i.local));return
r&&function(n){this.setAttributeNS(i.space,i.local,r(n))}}var
i=va.ns.qualify(n);return
this.tween("attr."+n,i.local?r:e)},Tc.style=function(n,t,e){function
r(){this.style.removeProperty(n)}function i(t){return
null==t?r:(t+="",function(){var
r,i=xa.getComputedStyle(this,null).getPropertyValue(n);return
i!==t&&(r=a(i,t),function(t){this.style.setProperty(n,r(t),e)})})}var
u=arguments.length;if(3>u){if("string"!=typeof
n){2>u&&(t="");for(e in n)this.style(e,n[e],t);return
this}e=""}var a=Sr(n);return
Eu(this,"style."+n,t,i)},Tc.styleTween=function(n,t,
e){function r(r,i){var
u=t.call(this,r,i,xa.getComputedStyle(this,null).getPropertyValue(n));return
u&&function(t){this.style.setProperty(n,u(t),e)}}return
arguments.length<3&&(e=""),this.tween("style."+n,r)},Tc.text=function(n){return
Eu(this,"text",n,ku)},Tc.remove=function(){return
this.each("end.transition",function(){var
n;!this.__transition__&&(n=this.parentNode)&&n.removeChild(this)})},Tc.ease=function(n){var
t=this.id;return
arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof
n&&(n=va.ease.apply(va,arguments)),q(this,function(e){e.__transition__[t].ease=n}))},Tc.delay=function(n){var
t=this.id;return q(this,"function"==typeof
n?function(e,r,i){e.__transition__[t].delay=0|n.call(e,e.__data__,r,i)}:(n|=0,function(e){e.__transition__[t].delay=n}))},Tc.duration=function(n){var
t=this.id;return q(this,"function"==typeof
n?function(e,r,i){e.__transition__[t].duration=Math.max(1,0|n.call(e,e.__data__,r,i))}:(n=Math.max(1,0|n),function(e){e.__transition
__[t].duration=n}))},Tc.each=function(n,t){var e=this.id;if(arguments.length<2){var
r=zc,i=Ac;Ac=e,q(this,function(t,r,i){zc=t.__transition__[e],n.call(t,t.__data__,r,i)}),zc=r,Ac=i}else
q(this,function(r){r.__transition__[e].event.on(n,t)});return
this},Tc.transition=function(){for(var
n,t,e,r,i=this.id,u=++Cc,a=[],o=0,c=this.length;c>o;o++){a.push(n=[]);for(var
t=this[o],l=0,f=t.length;f>l;l++)(e=t[l])&&(r=Object.create(e.__transition__[i]),r.delay+=r.duration,Au(e,l,u,r)),n.push(e)}return
Su(a,u)},va.svg.axis=function(){function n(n){n.each(function(){var
n,s=va.select(this),h=null==l?e.ticks?e.ticks.apply(e,c):e.domain():l,g=null==t?e.tickFormat?e.tickFormat.apply(e,c):String:t,p=Tu(e,h,f),d=s.selectAll(".tick.minor").data(p,String),m=d.enter().insert("line",".tick").attr("class","tick
minor").style("opacity",1e-6),v=va.transition(d.exit()).style("opacity",1e-6).remove(),y=va.transition(d).style("opacity",1),M=s.selectAll(".tick.major").data(h,String),x=M.enter().insert(
"g",".domain").attr("class","tick
major").style("opacity",1e-6),b=va.transition(M.exit()).style("opacity",1e-6).remove(),_=va.transition(M).style("opacity",1),w=Ui(e),S=s.selectAll(".domain").data([0]),E=(S.enter().append("path").attr("class","domain"),va.transition(S)),k=e.copy(),A=this.__chart__||k;this.__chart__=k,x.append("line"),x.append("text");
-var
N=x.select("line"),q=_.select("line"),T=M.select("text").text(g),C=x.select("text"),z=_.select("text");switch(r){case"bottom":n=Nu,m.attr("y2",u),y.attr("x2",0).attr("y2",u),N.attr("y2",i),C.attr("y",Math.max(i,0)+o),q.attr("x2",0).attr("y2",i),z.attr("x",0).attr("y",Math.max(i,0)+o),T.attr("dy",".71em").style("text-anchor","middle"),E.attr("d","M"+w[0]+","+a+"V0H"+w[1]+"V"+a);break;case"top":n=Nu,m.attr("y2",-u),y.attr("x2",0).attr("y2",-u),N.attr("y2",-i),C.attr("y",-(Math.max(i,0)+o)),q.attr("x2",0).attr("y2",-i),z.attr("x",0).attr("y",-(Math.max(i,0)+o)),T.attr("dy","0em").style("text-anchor","middle"),E.attr("d","M"+w[0]+","+-a+"V0H"+w[1]+"V"+-a);break;case"left":n=qu,m.attr("x2",-u),y.attr("x2",-u).attr("y2",0),N.attr("x2",-i),C.attr("x",-(Math.max(i,0)+o)),q.attr("x2",-i).attr("y2",0),z.attr("x",-(Math.max(i,0)+o)).attr("y",0),T.attr("dy",".32em").style("text-anchor","end"),E.attr("d","M"+-a+","+w[0]+"H0V"+w[1]+"H"+-a);break;case"right":n=qu,m.attr("x2",u),y.attr(
"x2",u).attr("y2",0),N.attr("x2",i),C.attr("x",Math.max(i,0)+o),q.attr("x2",i).attr("y2",0),z.attr("x",Math.max(i,0)+o).attr("y",0),T.attr("dy",".32em").style("text-anchor","start"),E.attr("d","M"+a+","+w[0]+"H0V"+w[1]+"H"+a)}if(e.ticks)x.call(n,A),_.call(n,k),b.call(n,k),m.call(n,A),y.call(n,k),v.call(n,k);else{var
D=k.rangeBand()/2,j=function(n){return k(n)+D};x.call(n,j),_.call(n,j)}})}var
t,e=va.scale.linear(),r=Dc,i=6,u=6,a=6,o=3,c=[10],l=null,f=0;return
n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return
arguments.length?(r=t in jc?t+"":Dc,n):r},n.ticks=function(){return
arguments.length?(c=arguments,n):c},n.tickValues=function(t){return
arguments.length?(l=t,n):l},n.tickFormat=function(e){return
arguments.length?(t=e,n):t},n.tickSize=function(t,e){if(!arguments.length)return i;var
r=arguments.length-1;return
i=+t,u=r>1?+e:i,a=r>0?+arguments[r]:i,n},n.tickPadding=function(t){return
arguments.length?(o=+t,n):o},n.tickSubdivide=function(t){
return arguments.length?(f=+t,n):f},n};var
Dc="bottom",jc={top:1,right:1,bottom:1,left:1};va.svg.brush=function(){function
n(u){u.each(function(){var
u,a=va.select(this),f=a.selectAll(".background").data([0]),s=a.selectAll(".extent").data([0]),h=a.selectAll(".resize").data(l,String);a.style("pointer-events","all").on("mousedown.brush",i).on("touchstart.brush",i),f.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),s.enter().append("rect").attr("class","extent").style("cursor","move"),h.enter().append("g").attr("class",function(n){return"resize
"+n}).style("cursor",function(n){return
Lc[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"),h.style("display",n.empty()?"none":null),h.exit().remove(),o&&(u=Ui(o),f.attr("x",u[0]).attr("width",u[1]-u[0]),e(a)),c&&(u=Ui(c),f.attr("y",u[0]).attr(
"height",u[1]-u[0]),r(a)),t(a)})}function
t(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)][0]+","+f[+/^s/.test(n)][1]+")"})}function
e(n){n.select(".extent").attr("x",f[0][0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1][0]-f[0][0])}function
r(n){n.select(".extent").attr("y",f[0][1]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",f[1][1]-f[0][1])}function
i(){function i(){var n=va.event.changedTouches;return
n?va.touches(M,n)[0]:va.mouse(M)}function
l(){32==va.event.keyCode&&(k||(v=null,N[0]-=f[1][0],N[1]-=f[1][1],k=2),g())}function
h(){32==va.event.keyCode&&2==k&&(N[0]+=f[1][0],N[1]+=f[1][1],k=0,g())}function
p(){var
n=i(),u=!1;y&&(n[0]+=y[0],n[1]+=y[1]),k||(va.event.altKey?(v||(v=[(f[0][0]+f[1][0])/2,(f[0][1]+f[1][1])/2]),N[0]=f[+(n[0]<v[0])][0],N[1]=f[+(n[1]<v[1])][1]):v=null),S&&d(n,o,0)&&(e(_),u=!0),E&&d(n,c,1)&&(r(_),u=!0),u&&(t(_),b({type:"brush",mode:k?"move":"resize"}))}function
d(n,t,e){var r,i,a=Ui(t),o
=a[0],c=a[1],l=N[e],h=f[1][e]-f[0][e];return
k&&(o-=l,c-=h+l),r=s[e]?Math.max(o,Math.min(c,n[e])):n[e],k?i=(r+=l)+h:(v&&(l=Math.max(o,Math.min(c,2*v[e]-r))),r>l?(i=r,r=l):i=l),f[0][e]!==r||f[1][e]!==i?(u=null,f[0][e]=r,f[1][e]=i,!0):void
0}function
m(){p(),_.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),va.select("body").style("cursor",null),q.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),A(),b({type:"brushend"})}var
v,y,M=this,x=va.select(va.event.target),b=a.of(M,arguments),_=va.select(M),w=x.datum(),S=!/^(n|s)$/.test(w)&&o,E=!/^(e|w)$/.test(w)&&c,k=x.classed("extent"),A=j("brush"),N=i(),q=va.select(xa).on("keydown.brush",l).on("keyup.brush",h);if(va.event.changedTouches?q.on("touchmove.brush",p).on("touchend.brush",m):q.on("mousemove.brush",p).on("mouseup.brush",m),k)N[0]=f[0][0]-N[0],N[1]=f[0][1]-N[1];else
if(w){var T=+/w$
/.test(w),C=+/^n/.test(w);y=[f[1-T][0]-N[0],f[1-C][1]-N[1]],N[0]=f[T][0],N[1]=f[C][1]}else
va.event.altKey&&(v=N.slice());_.style("pointer-events","none").selectAll(".resize").style("display",null),va.select("body").style("cursor",x.style("cursor")),b({type:"brushstart"}),p()}var
u,a=d(n,"brushstart","brush","brushend"),o=null,c=null,l=Hc[0],f=[[0,0],[0,0]],s=[!0,!0];return
n.x=function(t){return
arguments.length?(o=t,l=Hc[!o<<1|!c],n):o},n.y=function(t){return
arguments.length?(c=t,l=Hc[!o<<1|!c],n):c},n.clamp=function(t){return
arguments.length?(o&&c?s=[!!t[0],!!t[1]]:(o||c)&&(s[+!o]=!!t),n):o&&c?s:o||c?s[+!o]:null},n.extent=function(t){var
e,r,i,a,l;return
arguments.length?(u=[[0,0],[0,0]],o&&(e=t[0],r=t[1],c&&(e=e[0],r=r[0]),u[0][0]=e,u[1][0]=r,o.invert&&(e=o(e),r=o(r)),e>r&&(l=e,e=r,r=l),f[0][0]=0|e,f[1][0]=0|r),c&&(i=t[0],a=t[1],o&&(i=i[1],a=a[1]),u[0][1]=i,u[1][1]=a,c.invert&&(i=c(i),a=c(a)),i>a&&(l=i,i=a,a=l),f[0][1]=0|i,f[1][1]=0|a),n):(t=u||f,o&&(e=t[0][0],r=t[1][0
],u||(e=f[0][0],r=f[1][0],o.invert&&(e=o.invert(e),r=o.invert(r)),e>r&&(l=e,e=r,r=l))),c&&(i=t[0][1],a=t[1][1],u||(i=f[0][1],a=f[1][1],c.invert&&(i=c.invert(i),a=c.invert(a)),i>a&&(l=i,i=a,a=l))),o&&c?[[e,i],[r,a]]:o?[e,r]:c&&[i,a])},n.clear=function(){return
u=null,f[0][0]=f[0][1]=f[1][0]=f[1][1]=0,n},n.empty=function(){return
o&&f[0][0]===f[1][0]||c&&f[0][1]===f[1][1]},va.rebind(n,a,"on")};var
Lc={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Hc=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]];va.time={};var
Fc=Date,Pc=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];Cu.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(){r
eturn 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(){Oc.setUTCDate.apply(this._,arguments)},setDay:function(){Oc.setUTCDay.apply(this._,arguments)},setFullYear:function(){Oc.setUTCFullYear.apply(this._,arguments)},setHours:function(){Oc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){Oc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){Oc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){Oc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){Oc.setUTCSeconds.apply(this._,arguments)},setTime:function(){Oc.setTime.apply(this._,arguments)}};var
Oc=Date.prototype,Rc="%a %b %e %X
%Y",Yc="%m/%d/%Y",Uc="%H:%M:%S",Ic=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],Vc=["Sun","Mon","Tue","Wed
","Thu","Fri","Sat"],Xc=["January","February","March","April","May","June","July","August","September","October","November","December"],Zc=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];va.time.year=zu(function(n){return
n=va.time.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return
n.getFullYear()}),va.time.years=va.time.year.range,va.time.years.utc=va.time.year.utc.range,va.time.day=zu(function(n){var
t=new Fc(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}),va.time.days=va.time.day.range,va.time.days.utc=va.time.day.utc.range,va.time.dayOfYear=function(n){var
t=va.time.year(n);return
Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},Pc.forEach(function(n,t){n=n.toLowerCase(),t=7-t;var
e=va.time[n]=zu(function(n){return(n=va.time.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},functio
n(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var
e=va.time.year(n).getDay();return
Math.floor((va.time.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});va.time[n+"s"]=e.range,va.time[n+"s"].utc=e.utc.range,va.time[n+"OfYear"]=function(n){var
e=va.time.year(n).getDay();return
Math.floor((va.time.dayOfYear(n)+(e+t)%7)/7)}}),va.time.week=va.time.sunday,va.time.weeks=va.time.sunday.range,va.time.weeks.utc=va.time.sunday.utc.range,va.time.weekOfYear=va.time.sundayOfYear,va.time.format=function(n){function
t(t){for(var
r,i,u,a=[],o=-1,c=0;++o<e;)37===n.charCodeAt(o)&&(a.push(n.substring(c,o)),null!=(i=el[r=n.charAt(++o)])&&(r=n.charAt(++o)),(u=rl[r])&&(r=u(t,null==i?"e"===r?"
":"0":i)),a.push(r),c=o+1);return
a.push(n.substring(c,o)),a.join("")}var e=n.length;return
t.parse=function(t){var
e={y:1900,m:0,d:1,H:0,M:0,S:0,L:0},r=ju(e,n,t,0);if(r!=t.length)return
null;"p"in e&&(e.H=e.H%12+12*e.p);var i=new Fc;return"j"in
e?i.setFullYear(e.y,0,e.j):"w"in e&&("W"in e||"U"in
e)?(i.setFul
lYear(e.y,0,1),i.setFullYear(e.y,0,"W"in
e?(e.w+6)%7+7*e.W-(i.getDay()+5)%7:e.w+7*e.U-(i.getDay()+6)%7)):i.setFullYear(e.y,e.m,e.d),i.setHours(e.H,e.M,e.S,e.L),i},t.toString=function(){return
n},t};var
Bc=Lu(Ic),$c=Hu(Ic),Wc=Lu(Vc),Jc=Hu(Vc),Gc=Lu(Xc),Kc=Hu(Xc),Qc=Lu(Zc),nl=Hu(Zc),tl=/^%/,el={"-":"",_:"
",0:"0"},rl={a:function(n){return Vc[n.getDay()]},A:function(n){return
Ic[n.getDay()]},b:function(n){return Zc[n.getMonth()]},B:function(n){return
Xc[n.getMonth()]},c:va.time.format(Rc),d:function(n,t){return
Fu(n.getDate(),t,2)},e:function(n,t){return Fu(n.getDate(),t,2)},H:function(n,t){return
Fu(n.getHours(),t,2)},I:function(n,t){return
Fu(n.getHours()%12||12,t,2)},j:function(n,t){return
Fu(1+va.time.dayOfYear(n),t,3)},L:function(n,t){return
Fu(n.getMilliseconds(),t,3)},m:function(n,t){return
Fu(n.getMonth()+1,t,2)},M:function(n,t){return
Fu(n.getMinutes(),t,2)},p:function(n){return
n.getHours()>=12?"PM":"AM"},S:function(n,t){return
Fu(n.getSeconds(),t,2)},U:function(n,t){
return Fu(va.time.sundayOfYear(n),t,2)},w:function(n){return
n.getDay()},W:function(n,t){return
Fu(va.time.mondayOfYear(n),t,2)},x:va.time.format(Yc),X:va.time.format(Uc),y:function(n,t){return
Fu(n.getFullYear()%100,t,2)},Y:function(n,t){return
Fu(n.getFullYear()%1e4,t,4)},Z:ua,"%":function(){return"%"}},il={a:Pu,A:Ou,b:Iu,B:Vu,c:Xu,d:Ku,e:Ku,H:na,I:na,j:Qu,L:ra,m:Gu,M:ta,p:ia,S:ea,U:Yu,w:Ru,W:Uu,x:Zu,X:Bu,y:Wu,Y:$u,"%":aa},ul=/^\s*\d+/,al=va.map({am:0,pm:1});va.time.format.utc=function(n){function
t(n){try{Fc=Cu;var t=new Fc;return t._=n,e(t)}finally{Fc=Date}}var
e=va.time.format(n);return t.parse=function(n){try{Fc=Cu;var t=e.parse(n);return
t&&t._}finally{Fc=Date}},t.toString=e.toString,t};var
ol=va.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");va.time.format.iso=Date.prototype.toISOString&&+new
Date("2000-01-01T00:00:00.000Z")?oa:ol,oa.parse=function(n){var t=new
Date(n);return
isNaN(t)?null:t},oa.toString=ol.toString,va.time.second=zu(function(n){return new
Fc(1e3*Math.floo
r(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return
n.getSeconds()}),va.time.seconds=va.time.second.range,va.time.seconds.utc=va.time.second.utc.range,va.time.minute=zu(function(n){return
new
Fc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return
n.getMinutes()}),va.time.minutes=va.time.minute.range,va.time.minutes.utc=va.time.minute.utc.range,va.time.hour=zu(function(n){var
t=n.getTimezoneOffset()/60;return new
Fc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return
n.getHours()}),va.time.hours=va.time.hour.range,va.time.hours.utc=va.time.hour.utc.range,va.time.month=zu(function(n){return
n=va.time.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return
n.getMonth()}),va.time.months=va.time.month.range,va.time.months.utc=va.time.month.utc.range;var
cl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e
5,1728e5,6048e5,2592e6,7776e6,31536e6],ll=[[va.time.second,1],[va.time.second,5],[va.time.second,15],[va.time.second,30],[va.time.minute,1],[va.time.minute,5],[va.time.minute,15],[va.time.minute,30],[va.time.hour,1],[va.time.hour,3],[va.time.hour,6],[va.time.hour,12],[va.time.day,1],[va.time.day,2],[va.time.week,1],[va.time.month,1],[va.time.month,3],[va.time.year,1]],fl=[[va.time.format("%Y"),Rt],[va.time.format("%B"),function(n){return
n.getMonth()}],[va.time.format("%b %d"),function(n){return
1!=n.getDate()}],[va.time.format("%a %d"),function(n){return
n.getDay()&&1!=n.getDate()}],[va.time.format("%I %p"),function(n){return
n.getHours()}],[va.time.format("%I:%M"),function(n){return
n.getMinutes()}],[va.time.format(":%S"),function(n){return
n.getSeconds()}],[va.time.format(".%L"),function(n){return
n.getMilliseconds()}]],sl=va.scale.linear(),hl=fa(fl);ll.year=function(n,t){return
sl.domain(n.map(ha)).ticks(t).map(sa)},va.time.scale=function(){return
ca(va.scale.linear(),ll
,hl)};var
gl=ll.map(function(n){return[n[0].utc,n[1]]}),pl=[[va.time.format.utc("%Y"),Rt],[va.time.format.utc("%B"),function(n){return
n.getUTCMonth()}],[va.time.format.utc("%b %d"),function(n){return
1!=n.getUTCDate()}],[va.time.format.utc("%a %d"),function(n){return
n.getUTCDay()&&1!=n.getUTCDate()}],[va.time.format.utc("%I
%p"),function(n){return
n.getUTCHours()}],[va.time.format.utc("%I:%M"),function(n){return
n.getUTCMinutes()}],[va.time.format.utc(":%S"),function(n){return
n.getUTCSeconds()}],[va.time.format.utc(".%L"),function(n){return
n.getUTCMilliseconds()}]],dl=fa(pl);return gl.year=function(n,t){return
sl.domain(n.map(pa)).ticks(t).map(ga)},va.time.scale.utc=function(){return
ca(va.scale.linear(),gl,dl)},va.text=ht(function(n){return
n.responseText}),va.json=function(n,t){return
gt(n,"application/json",da,t)},va.html=function(n,t){return
gt(n,"text/html",ma,t)},va.xml=ht(function(n){return n.responseXML}),va}();
\ No newline at end of file
commit 8df7802718bf3b73c7f5c4748cce27d6522d3c8e
Author: John Sanda <jsanda(a)redhat.com>
Date: Fri Dec 20 15:31:58 2013 -0500
[BZ 1042663] upgrade datastax C* to 1.0.5
diff --git a/modules/enterprise/server/server-metrics/pom.xml
b/modules/enterprise/server/server-metrics/pom.xml
index 122d7a5..866582d 100644
--- a/modules/enterprise/server/server-metrics/pom.xml
+++ b/modules/enterprise/server/server-metrics/pom.xml
@@ -70,6 +70,7 @@
<version>2.1</version>
</dependency>
+ <!-- cassandra driver dep -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
diff --git a/pom.xml b/pom.xml
index 77a3dcd..e6ab31a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -181,8 +181,8 @@
<!-- cassandra dependency versions -->
<cassandra.version>1.2.9</cassandra.version>
<cassandra.thrift.version>0.7.0</cassandra.thrift.version>
- <cassandra.driver.version>1.0.2</cassandra.driver.version>
-
<cassandra.driver.netty.version>3.6.3.Final</cassandra.driver.netty.version>
+ <cassandra.driver.version>1.0.5</cassandra.driver.version>
+
<cassandra.driver.netty.version>3.7.0.Final</cassandra.driver.netty.version>
<cassandra.snappy.version>1.0.4.1-rhq-p1</cassandra.snappy.version>
<cassandra.snakeyaml.version>1.6</cassandra.snakeyaml.version>
commit 4b20611ece3aa37ede9b89ca90383eba5647b799
Author: John Sanda <jsanda(a)redhat.com>
Date: Wed Oct 2 17:36:21 2013 -0400
[BZ 1009945] squash commit of jsanda/aggregation branch
commit 1 - Initial commit for new Aggregator class
This is a first pass at computing multiple aggregates concurrently.
Conflicts:
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsServer.java
commit 2 - update 6 hr index after inserting 1 hr data
commit 3 -initial support for generating 6 hr and 24 hr data
Conflicts:
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
commit 4 - delete 1 hr index entries when aggregation of time slice data is finished
commit 5 - handle scenarios for when there is no 1 hr and/or 6 hr data
This commit also includes some major test changes. AggregationTests is a more
thorough set (of not yet complete) tests to provide better coverage.
commit 6 - finishing test for 24 hour data
Conflicts:
modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregationTests.java
commit 7 - adding initial test for failure scenario
This test is for when we fail to fetch the raw data index.
commit 8 - This is a big refactoring of the initial implementation of Aggregator.java
The overall design is the same in terms of the fan out approach for doing the
calculations, but some changes were necessary after an extensive performance
analysis. Initially the aggregation tasks were to granular. Tasks were
submitted to the thread pool to process a single schedule. Schedules are now
processed in batches of 250. I did a lot of performance testing with various
batch sizes, and 250 seems optimal both in terms of execution time as well as
memory consumption. The other major change involves throttling. The initial
implementation had no throttling in place which immediately caused read and/or
write timeouts. Then I put throttling in place using RateLimiters, but there
was separate throttling that is used in MetricsServer for inserting raw data.
The same throttling is now used by both MetricsServer and Aggregator. There
are actually separate rate limiters for reads and for writes. Both are
configurable as well.
Conflicts:
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsServer.java
commit 9 - adding back support for aggregating 6 hour data
commit 10 - fix logic for determining if aggregation has finished
We check the respective counters to see if raw, 1 hr, and 6 hr data aggregation
has finished. Prior to checking the counters though, we need to make sure that
they have been initialized. They do not get initialized until the respective
index entries arrive. I have refactored the logic into a new method,
isAggregationFinished. It first waits for the arrival of all the index entries
and then checks the counters.
commit 11 - set counters for remaining data when we fail to get index entries for 1
and 6 hr data
commit 12 - refactoring some duplicate code and fixing when tasks are scheduled
Aggregation tasks for 1 and 6 hour data were getting schedule too early. They
cannot get scheduled until both their respective index entries have arrived and
aggregation for the previous buckets has completed.
commit 13 - make connection pool sizes and rate limits configurable
Connection pools per host and rate limits are configurable via system
properties. While the connection pool sizes are only set at start up, I plan to
make the rate limits self-tuning.
This commit also adds the missing method body to kick off 6 hour data
aggregation in Aggregate1HourData.java.
Conflicts:
modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsServer.java
commit 14 - add support for running async aggregation in simulator
commit 15 - eliminate a couple possible race condition when processing index entries
commit 16 - cleaning up logging and adding some javadocs
Also moving all aggregation related classes into the
org.rhq.server.metrics.aggregation
package. All classes except Aggregator now have package-level access.
commit 17 - updating test with package refactoring
commit 18 - turn on async aggregation by default
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
index dc8c554..7d390f4 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/storage/StorageClientManagerBean.java
@@ -41,6 +41,8 @@ import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.HostDistance;
+import com.datastax.driver.core.PoolingOptions;
import com.datastax.driver.core.ProtocolOptions;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.exceptions.NoHostAvailableException;
@@ -355,6 +357,16 @@ public class StorageClientManagerBean {
.withRetryPolicy(new
LoggingRetryPolicy(DefaultRetryPolicy.INSTANCE)).withCompression(
ProtocolOptions.Compression.NONE).build();
+ PoolingOptions poolingOptions = cluster.getConfiguration().getPoolingOptions();
+ poolingOptions.setCoreConnectionsPerHost(HostDistance.LOCAL, Integer.parseInt(
+ System.getProperty("rhq.storage.client.local-connections",
"24")));
+ poolingOptions.setCoreConnectionsPerHost(HostDistance.REMOTE, Integer.parseInt(
+ System.getProperty("rhq.storage.client.remote-connections",
"16")));
+ poolingOptions.setMaxConnectionsPerHost(HostDistance.LOCAL, Integer.parseInt(
+ System.getProperty("rhq.storage.client.max-local-connections",
"32")));
+ poolingOptions.setMaxConnectionsPerHost(HostDistance.REMOTE, Integer.parseInt(
+ System.getProperty("rhq.storage.client.max-remote-connections",
"24")));
+
return cluster.connect(RHQ_KEYSPACE);
}
diff --git a/modules/enterprise/server/server-metrics/pom.xml
b/modules/enterprise/server/server-metrics/pom.xml
index 0b4c141..122d7a5 100644
--- a/modules/enterprise/server/server-metrics/pom.xml
+++ b/modules/enterprise/server/server-metrics/pom.xml
@@ -157,6 +157,9 @@
<rhq.storage.cluster.dir>${rhq.storage.cluster.dir}</rhq.storage.cluster.dir>
<rhq.storage.cluster.deploy>${deployCluster}</rhq.storage.cluster.deploy>
</systemPropertyVariables>
+ <excludes>
+ <exclude>**/MetricsPerfTests.java</exclude>
+ </excludes>
</configuration>
</plugin>
</plugins>
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/AbortedException.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/AbortedException.java
new file mode 100644
index 0000000..cab2ab0
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/AbortedException.java
@@ -0,0 +1,23 @@
+package org.rhq.server.metrics;
+
+/**
+ * @author John Sanda
+ */
+public class AbortedException extends Exception {
+
+ public AbortedException() {
+ super();
+ }
+
+ public AbortedException(String message) {
+ super(message);
+ }
+
+ public AbortedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public AbortedException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
index e62545e..66d0493 100644
---
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsDAO.java
@@ -154,17 +154,36 @@ public class MetricsDAO {
return storageSession.execute(statement);
}
+ public StorageResultSetFuture insertOneHourDataAsync(int scheduleId, long timestamp,
AggregateType type,
+ double value) {
+ BoundStatement statement = insertOneHourData.bind(scheduleId, new
Date(timestamp), type.ordinal(), value);
+ return storageSession.executeAsync(statement);
+ }
+
public ResultSet insertSixHourData(int scheduleId, long timestamp, AggregateType
type, double value) {
BoundStatement statement = insertSixHourData.bind(scheduleId, new
Date(timestamp), type.ordinal(), value);
return storageSession.execute(statement);
}
+ public StorageResultSetFuture insertSixHourDataAsync(int scheduleId, long timestamp,
AggregateType type,
+ double value) {
+ BoundStatement statement = insertSixHourData.bind(scheduleId, new
Date(timestamp), type.ordinal(), value);
+ return storageSession.executeAsync(statement);
+ }
+
public ResultSet insertTwentyFourHourData(int scheduleId, long timestamp,
AggregateType type, double value) {
BoundStatement statement = insertTwentyFourHourData.bind(scheduleId, new
Date(timestamp), type.ordinal(),
value);
return storageSession.execute(statement);
}
+ public StorageResultSetFuture insertTwentyFourHourDataAsync(int scheduleId, long
timestamp, AggregateType type,
+ double value) {
+ BoundStatement statement = insertTwentyFourHourData.bind(scheduleId, new
Date(timestamp), type.ordinal(),
+ value);
+ return storageSession.executeAsync(statement);
+ }
+
public Iterable<RawNumericMetric> findRawMetrics(int scheduleId, long
startTime, long endTime) {
try {
BoundStatement boundStatement = rawMetricsQuery.bind(scheduleId, new
Date(startTime), new Date(endTime));
@@ -175,6 +194,11 @@ public class MetricsDAO {
}
}
+ public ResultSet findRawMetricsSync(int scheduleId, long startTime, long endTime) {
+ BoundStatement boundStatement = rawMetricsQuery.bind(scheduleId, new
Date(startTime), new Date(endTime));
+ return storageSession.execute(boundStatement);
+ }
+
public StorageResultSetFuture findRawMetricsAsync(int scheduleId, long startTime,
long endTime) {
BoundStatement boundStatement = rawMetricsQuery.bind(scheduleId, new
Date(startTime), new Date(endTime));
return storageSession.executeAsync(boundStatement);
@@ -212,8 +236,7 @@ public class MetricsDAO {
}
public StorageResultSetFuture findSixHourMetricsAsync(int scheduleId, long startTime,
long endTime) {
- BoundStatement statement = findSixHourMetricsByDateRange.bind(scheduleId, new
Date(startTime),
- new Date(endTime));
+ BoundStatement statement = findSixHourMetricsByDateRange.bind(scheduleId, new
Date(startTime), new Date(endTime));
return storageSession.executeAsync(statement);
}
@@ -260,6 +283,11 @@ public class MetricsDAO {
return new SimplePagedResult<MetricsIndexEntry>(statement, new
MetricsIndexEntryMapper(table), storageSession);
}
+ public StorageResultSetFuture findMetricsIndexEntriesAsync(MetricsTable table, long
timestamp) {
+ BoundStatement statement = findIndexEntries.bind(table.toString(), new
Date(timestamp));
+ return storageSession.executeAsync(statement);
+ }
+
public ResultSet setFindTimeSliceForIndex(MetricsTable table, long timestamp) {
BoundStatement statement = findTimeSliceForIndex.bind(table.toString(), new
Date(timestamp));
return storageSession.execute(statement);
@@ -282,4 +310,9 @@ public class MetricsDAO {
BoundStatement statement = deleteIndexEntries.bind(table.getTableName(), new
Date(timestamp));
storageSession.execute(statement);
}
+
+ public StorageResultSetFuture deleteMetricsIndexEntriesAsync(MetricsTable table, long
timestamp) {
+ BoundStatement statement = deleteIndexEntries.bind(table.getTableName(), new
Date(timestamp));
+ return storageSession.executeAsync(statement);
+ }
}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsServer.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsServer.java
index 33528e6..d319146 100644
---
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsServer.java
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/MetricsServer.java
@@ -32,7 +32,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
-import java.util.concurrent.Semaphore;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -43,6 +43,9 @@ import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.RateLimiter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -52,6 +55,7 @@ import org.joda.time.Duration;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
+import org.rhq.server.metrics.aggregation.Aggregator;
import org.rhq.server.metrics.domain.AggregateNumericMetric;
import org.rhq.server.metrics.domain.AggregateType;
import org.rhq.server.metrics.domain.MetricsIndexEntry;
@@ -71,7 +75,11 @@ public class MetricsServer {
private MetricsConfiguration configuration;
- private Semaphore semaphore = new Semaphore(100);
+ private RateLimiter readPermits = RateLimiter.create(Integer.parseInt(
+ System.getProperty("rhq.storage.read-limit", "1000")), 3,
TimeUnit.MINUTES);
+
+ private RateLimiter writePermits = RateLimiter.create(Integer.parseInt(
+ System.getProperty("rhq.storage.write-limit", "2500")), 3,
TimeUnit.MINUTES);
private boolean pastAggregationMissed;
@@ -79,6 +87,13 @@ public class MetricsServer {
private AtomicLong totalAggregationTime = new AtomicLong();
+ private ListeningExecutorService aggregationWorkers =
MoreExecutors.listeningDecorator(
+ Executors.newFixedThreadPool(5));
+
+ private int aggregationBatchSize;
+
+ private boolean useAsyncAggregation =
Boolean.valueOf(System.getProperty("rhq.metrics.aggregation.async",
"true"));
+
public void setDAO(MetricsDAO dao) {
this.dao = dao;
}
@@ -91,7 +106,34 @@ public class MetricsServer {
this.dateTimeService = dateTimeService;
}
+ public void setAggregationBatchSize(int batchSize) {
+ aggregationBatchSize = batchSize;
+ }
+
+ public void setUseAsyncAggregation(boolean useAsyncAggregation) {
+ this.useAsyncAggregation = useAsyncAggregation;
+ }
+
+ public RateLimiter getReadPermits() {
+ return readPermits;
+ }
+
+ public void setReadPermits(RateLimiter readPermits) {
+ this.readPermits = readPermits;
+ }
+
+ public RateLimiter getWritePermits() {
+ return writePermits;
+ }
+
+ public void setWritePermits(RateLimiter writePermits) {
+ this.writePermits = writePermits;
+ }
+
public void init() {
+ if (log.isDebugEnabled() && useAsyncAggregation) {
+ log.debug("Async aggregation is enabled");
+ }
determineMostRecentRawDataSinceLastShutdown();
}
@@ -131,6 +173,11 @@ public class MetricsServer {
}
}
+ private boolean hasTimeSliceEnded(DateTime startTime, Duration duration) {
+ DateTime endTime = startTime.plus(duration);
+ return DateTimeComparator.getInstance().compare(currentHour(), endTime) >= 0;
+ }
+
protected DateTime currentHour() {
return dateTimeService.getTimeSlice(dateTimeService.now(),
configuration.getRawTimeSliceDuration());
}
@@ -140,6 +187,7 @@ public class MetricsServer {
}
public void shutdown() {
+ aggregationWorkers.shutdown();
}
public RawNumericMetric findLatestValueForResource(int scheduleId) {
@@ -363,7 +411,7 @@ public class MetricsServer {
final AtomicInteger remainingInserts = new AtomicInteger(dataSet.size());
for (final MeasurementDataNumeric data : dataSet) {
- semaphore.acquire();
+ writePermits.acquire();
StorageResultSetFuture resultSetFuture = dao.insertRawData(data);
Futures.addCallback(resultSetFuture, new
FutureCallback<ResultSet>() {
@Override
@@ -381,7 +429,6 @@ public class MetricsServer {
throwable.getClass().getName() + ": " +
throwable.getMessage());
}
callback.onFailure(throwable);
- semaphore.release();
}
});
}
@@ -396,6 +443,7 @@ public class MetricsServer {
long timeSlice = dateTimeService.getTimeSlice(new
DateTime(rawData.getTimestamp()),
configuration.getRawTimeSliceDuration()).getMillis();
+ writePermits.acquire();
StorageResultSetFuture resultSetFuture =
dao.updateMetricsIndex(MetricsTable.ONE_HOUR, rawData.getScheduleId(),
timeSlice);
Futures.addCallback(resultSetFuture, new FutureCallback<ResultSet>() {
@@ -409,7 +457,6 @@ public class MetricsServer {
}
callback.onFinish();
}
- semaphore.release();
}
@Override
@@ -417,7 +464,6 @@ public class MetricsServer {
log.error("An error occurred while trying to update " +
MetricsTable.INDEX + " for raw data " +
rawData);
callback.onFailure(throwable);
- semaphore.release();
}
});
}
@@ -431,14 +477,24 @@ public class MetricsServer {
* for subsequently computing baselines.
*/
public Iterable<AggregateNumericMetric> calculateAggregates() {
- DateTime theHour = currentHour();
+ long start = System.currentTimeMillis();
+ try {
+ DateTime theHour = currentHour();
- if (pastAggregationMissed) {
-
calculateAggregates(roundDownToHour(mostRecentRawDataPriorToStartup).plusHours(1).getMillis());
- pastAggregationMissed = false;
- return calculateAggregates(theHour.getMillis());
- } else {
- return calculateAggregates(theHour.getMillis());
+ if (pastAggregationMissed) {
+ theHour = roundDownToHour(mostRecentRawDataPriorToStartup).plusHours(1);
+ pastAggregationMissed = false;
+ }
+
+ if (useAsyncAggregation) {
+ DateTime timeSlice =
theHour.minus(configuration.getRawTimeSliceDuration());
+ return new Aggregator(aggregationWorkers, dao, configuration,
dateTimeService, timeSlice,
+ aggregationBatchSize, writePermits, readPermits).run();
+ } else {
+ return calculateAggregates(theHour.getMillis());
+ }
+ } finally {
+ log.info("Finished metrics aggregation in " +
(System.currentTimeMillis() - start) + " ms");
}
}
@@ -460,16 +516,6 @@ public class MetricsServer {
long twentyFourHourTimeSlice = dateTimeService.getTimeSlice(lastHour,
configuration.getSixHourTimeSliceDuration()).getMillis();
- // We first query the metrics index table to determine which schedules have data
to
- // be aggregated. Then we retrieve the metric data and aggregate or compress the
- // data, writing the compressed values into the next wider (i.e., longer life
span
- // for data) bucket/table. At this point we remove the index entries for the
data
- // that has already been processed. We purge the entire row in the index table.
- // We can safely do this because the row wi..
- //
- // The last step in the work flow is to update the metrics
- // index for the newly persisted aggregates.
-
List<AggregateNumericMetric> newOneHourAggregates = null;
Stopwatch stopwatch = new Stopwatch().start();
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/SignalingCountDownLatch.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/SignalingCountDownLatch.java
new file mode 100644
index 0000000..2d0d190
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/SignalingCountDownLatch.java
@@ -0,0 +1,34 @@
+package org.rhq.server.metrics;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * @author John Sanda
+ */
+public class SignalingCountDownLatch {
+
+ private boolean aborted;
+
+ private CountDownLatch latch;
+
+ public SignalingCountDownLatch(CountDownLatch latch) {
+ this.latch = latch;
+ }
+
+ public void await() throws InterruptedException, AbortedException {
+ latch.await();
+ if (aborted) {
+ throw new AbortedException();
+ }
+ }
+
+ public void abort() {
+ aborted = true;
+ latch.countDown();
+ }
+
+ public void countDown() {
+ latch.countDown();
+ }
+
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregate1HourData.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregate1HourData.java
new file mode 100644
index 0000000..1698b28
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregate1HourData.java
@@ -0,0 +1,127 @@
+package org.rhq.server.metrics.aggregation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import com.datastax.driver.core.ResultSet;
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.FutureFallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.core.util.exception.ThrowableUtil;
+import org.rhq.server.metrics.AbortedException;
+import org.rhq.server.metrics.MetricsDAO;
+import org.rhq.server.metrics.StorageResultSetFuture;
+
+/**
+ * Generates 6 hour data for a batch of 1 hour data futures. After data is inserted for
the batch, aggregation of 6 hour
+ * data will start immediately for the batch if the 24 hour time slice has finished.
+ *
+ * @see Compute6HourData
+ * @author John Sanda
+ */
+class Aggregate1HourData implements Runnable {
+
+ private final Log log = LogFactory.getLog(Aggregate1HourData.class);
+
+ private MetricsDAO dao;
+
+ private AggregationState state;
+
+ private Set<Integer> scheduleIds;
+
+ private List<StorageResultSetFuture> queryFutures;
+
+ public Aggregate1HourData(MetricsDAO dao, AggregationState state, Set<Integer>
scheduleIds,
+ List<StorageResultSetFuture> queryFutures) {
+ this.dao = dao;
+ this.state = state;
+ this.scheduleIds = scheduleIds;
+ this.queryFutures = queryFutures;
+ }
+
+ @Override
+ public void run() {
+ final Stopwatch stopwatch = new Stopwatch().start();
+ ListenableFuture<List<ResultSet>> queriesFuture =
Futures.successfulAsList(queryFutures);
+ Futures.withFallback(queriesFuture, new
FutureFallback<List<ResultSet>>() {
+ @Override
+ public ListenableFuture<List<ResultSet>> create(Throwable t)
throws Exception {
+ log.error("An error occurred while fetching one hour data",
t);
+ return Futures.immediateFailedFuture(t);
+ }
+ });
+ ListenableFuture<List<ResultSet>> computeFutures =
Futures.transform(queriesFuture,
+ state.getCompute6HourData(), state.getAggregationTasks());
+ Futures.addCallback(computeFutures, new
FutureCallback<List<ResultSet>>() {
+ @Override
+ public void onSuccess(List<ResultSet> result) {
+ stopwatch.stop();
+ log.debug("Finished aggregating 1 hour data for " +
result.size() + " schedules in " +
+ stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
+ start6HourDataAggregationIfNecessary();
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ if (log.isDebugEnabled()) {
+ // TODO should we log the schedule ids?
+ log.debug("Failed to aggregate 1 hour data for " +
scheduleIds.size() + " schedules. An " +
+ "unexpected error occurred.", t);
+ } else {
+ log.warn("Failed to aggregate 1 hour data for " +
scheduleIds.size() + " schedules. An " +
+ "unexpected error occurred: " +
ThrowableUtil.getRootMessage(t));
+ }
+ start6HourDataAggregationIfNecessary();
+ }
+ });
+ }
+
+ private void start6HourDataAggregationIfNecessary() {
+ try {
+ if (state.is24HourTimeSliceFinished()) {
+ update6HourIndexEntries();
+ List<StorageResultSetFuture> queryFutures = new
ArrayList<StorageResultSetFuture>(scheduleIds.size());
+ for (Integer scheduleId : scheduleIds) {
+ queryFutures.add(dao.findSixHourMetricsAsync(scheduleId,
state.getTwentyFourHourTimeSlice().getMillis(),
+ state.getTwentyFourHourTimeSliceEnd().getMillis()));
+ }
+ state.getAggregationTasks().submit(new Aggregate6HourData(dao, state,
scheduleIds, queryFutures));
+ }
+ } catch (InterruptedException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("An interrupt occurred while waiting for 6 hour data index
entries. Aborting data aggregation",
+ e);
+ } else {
+ log.info("An interrupt occurred while waiting for 6 hour data index
entries. Aborting data " +
+ "aggregation: " + e.getMessage());
+ }
+ } finally {
+ state.getRemaining1HourData().addAndGet(-scheduleIds.size());
+ }
+ }
+
+ private void update6HourIndexEntries() throws InterruptedException {
+ try {
+ state.getSixHourIndexEntriesArrival().await();
+ try {
+ state.getSixHourIndexEntriesLock().writeLock().lock();
+ state.getSixHourIndexEntries().removeAll(scheduleIds);
+ } finally {
+ state.getSixHourIndexEntriesLock().writeLock().unlock();
+ }
+ } catch (AbortedException e) {
+ // This means we failed to retrieve the index entries. We can however
+ // continue generating 6 hour data because we do not need the index
+ // here since we already have 6 hour data to aggregate along with the
+ // schedule ids.
+ }
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregate6HourData.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregate6HourData.java
new file mode 100644
index 0000000..fbd5057
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregate6HourData.java
@@ -0,0 +1,84 @@
+package org.rhq.server.metrics.aggregation;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import com.datastax.driver.core.ResultSet;
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.FutureFallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.core.util.exception.ThrowableUtil;
+import org.rhq.server.metrics.MetricsDAO;
+import org.rhq.server.metrics.StorageResultSetFuture;
+
+/**
+ * Generates 24 hour data for a batch of 1 hour data futures. After data is inserted for
the batch, aggregation of 6
+ * hour data will start immediately for the batch if the 24 hour time slice has
finished.
+ *
+ * @see Compute24HourData
+ * @author John Sanda
+ */
+class Aggregate6HourData implements Runnable {
+
+ private final Log log = LogFactory.getLog(Aggregate6HourData.class);
+
+ private MetricsDAO dao;
+
+ private AggregationState state;
+
+ private Set<Integer> scheduleIds;
+
+ private List<StorageResultSetFuture> queryFutures;
+
+ public Aggregate6HourData(MetricsDAO dao, AggregationState state, Set<Integer>
scheduleIds,
+ List<StorageResultSetFuture> queryFutures) {
+ this.dao = dao;
+ this.state = state;
+ this.scheduleIds = scheduleIds;
+ this.queryFutures = queryFutures;
+ }
+
+ @Override
+ public void run() {
+ final Stopwatch stopwatch = new Stopwatch().start();
+ ListenableFuture<List<ResultSet>> queriesFuture =
Futures.successfulAsList(queryFutures);
+ Futures.withFallback(queriesFuture, new
FutureFallback<List<ResultSet>>() {
+ @Override
+ public ListenableFuture<List<ResultSet>> create(Throwable t)
throws Exception {
+ log.error("An error occurred while fetching 6 hour data", t);
+ return Futures.immediateFailedFuture(t);
+ }
+ });
+ ListenableFuture<List<ResultSet>> computeFutures =
Futures.transform(queriesFuture,
+ state.getCompute24HourData(), state.getAggregationTasks());
+ Futures.addCallback(computeFutures, new
FutureCallback<List<ResultSet>>() {
+ @Override
+ public void onSuccess(List<ResultSet> result) {
+ stopwatch.stop();
+ log.debug("Finished aggregating 6 hour data for " +
result.size() + " schedules in " +
+ stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
+ state.getRemaining6HourData().addAndGet(-scheduleIds.size());
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ if (log.isDebugEnabled()) {
+ // TODO should we log the schedule ids?
+ log.debug("Failed to aggregate 6 hour data for " +
scheduleIds.size() + " schedules. An " +
+ "unexpected error occurred.", t);
+ } else {
+ log.warn("Failed to aggregate 6 hour data for " +
scheduleIds.size() + " schedules. An " +
+ "unexpected error occurred: " +
ThrowableUtil.getRootMessage(t));
+ }
+ state.getRemaining6HourData().addAndGet(-scheduleIds.size());
+ }
+ });
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregateIndexEntriesHandler.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregateIndexEntriesHandler.java
new file mode 100644
index 0000000..cb64fcf
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregateIndexEntriesHandler.java
@@ -0,0 +1,73 @@
+package org.rhq.server.metrics.aggregation;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.FutureCallback;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.core.util.exception.ThrowableUtil;
+import org.rhq.server.metrics.SignalingCountDownLatch;
+
+/**
+* @author John Sanda
+*/
+class AggregateIndexEntriesHandler implements FutureCallback<ResultSet> {
+
+ private final Log log = LogFactory.getLog(AggregateIndexEntriesHandler.class);
+
+ private Set<Integer> indexEntries;
+
+ private AtomicInteger remainingData;
+
+ private SignalingCountDownLatch indexEntriesArrival;
+
+ private Stopwatch stopwatch;
+
+ private String src;
+
+ private String dest;
+
+ public AggregateIndexEntriesHandler(Set<Integer> indexEntries, AtomicInteger
remainingData,
+ SignalingCountDownLatch indexEntriesArrival, Stopwatch stopwatch, String src,
String dest) {
+ this.indexEntries = indexEntries;
+ this.remainingData = remainingData;
+ this.indexEntriesArrival = indexEntriesArrival;
+ this.stopwatch = stopwatch;
+ this.src = src;
+ this.dest = dest;
+ }
+
+ @Override
+ public void onSuccess(ResultSet resultSet) {
+ for (Row row : resultSet) {
+ indexEntries.add(row.getInt(1));
+ }
+ remainingData.set(indexEntries.size());
+ indexEntriesArrival.countDown();
+ stopwatch.stop();
+ if (log.isDebugEnabled()) {
+ log.debug("Finished loading " + indexEntries.size() + " "
+ src + " index entries in " +
+ stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ if (log.isDebugEnabled()) {
+ log.debug("Some " + dest + " aggregates may not get computed.
An unexpected error occurred while " +
+ "retrieving " + src + " index entries", t);
+ } else {
+ log.warn("Some " + dest + " aggregates may not get computed.
An unexpected error occurred while " +
+ "retrieving " + src + " index entries: " +
ThrowableUtil.getRootMessage(t));
+ }
+ remainingData.set(0);
+ indexEntriesArrival.abort();
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregateRawData.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregateRawData.java
new file mode 100644
index 0000000..87a7266
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregateRawData.java
@@ -0,0 +1,133 @@
+package org.rhq.server.metrics.aggregation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import com.datastax.driver.core.ResultSet;
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.FutureFallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.core.util.exception.ThrowableUtil;
+import org.rhq.server.metrics.AbortedException;
+import org.rhq.server.metrics.MetricsDAO;
+import org.rhq.server.metrics.StorageResultSetFuture;
+
+/**
+ * Generates 1 hour data for a batch of raw data futures. After data is inserted for the
batch, aggregation of 1 hour
+ * data will start immediately for the batch if the 6 hour time slice has finished.
+ *
+ * @see Compute1HourData
+ * @author John Sanda
+ */
+class AggregateRawData implements Runnable {
+
+ private final Log log = LogFactory.getLog(AggregateRawData.class);
+
+ private MetricsDAO dao;
+
+ private AggregationState state;
+
+ private Set<Integer> scheduleIds;
+
+ private List<StorageResultSetFuture> queryFutures;
+
+ public AggregateRawData(MetricsDAO dao, AggregationState state, Set<Integer>
scheduleIds,
+ List<StorageResultSetFuture> queryFutures) {
+ this.dao = dao;
+ this.state = state;
+ this.scheduleIds = scheduleIds;
+ this.queryFutures = queryFutures;
+ }
+
+ @Override
+ public void run() {
+ final Stopwatch stopwatch = new Stopwatch().start();
+ ListenableFuture<List<ResultSet>> rawDataFutures =
Futures.successfulAsList(queryFutures);
+ Futures.withFallback(rawDataFutures, new
FutureFallback<List<ResultSet>>() {
+ @Override
+ public ListenableFuture<List<ResultSet>> create(Throwable t)
throws Exception {
+ log.error("An error occurred while fetching raw data", t);
+ return Futures.immediateFailedFuture(t);
+ }
+ });
+
+ final ListenableFuture<List<ResultSet>> insert1HourDataFutures =
Futures.transform(rawDataFutures,
+ state.getCompute1HourData(), state.getAggregationTasks());
+ Futures.addCallback(insert1HourDataFutures, new
FutureCallback<List<ResultSet>>() {
+ @Override
+ public void onSuccess(List<ResultSet> resultSets) {
+ stopwatch.stop();
+ log.debug("Finished aggregating raw data for " +
resultSets.size() + " schedules in " +
+ stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
+ start1HourDataAggregationIfNecessary();
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ if (log.isDebugEnabled()) {
+ // TODO should we log the schedule ids?
+ log.debug("Failed to aggregate raw data for " +
scheduleIds.size() + " schedules. An unexpected " +
+ "error occurred.", t);
+ } else {
+ log.warn("Failed to aggregate raw data for " +
scheduleIds.size() + " schedules. An " +
+ "unexpected error occurred: " +
ThrowableUtil.getRootMessage(t));
+ }
+ start1HourDataAggregationIfNecessary();
+ }
+ }, state.getAggregationTasks());
+ }
+
+ private void start1HourDataAggregationIfNecessary() {
+ try {
+ if (state.is6HourTimeSliceFinished()) {
+ update1HourIndexEntries();
+ List<StorageResultSetFuture> oneHourDataQueryFutures = new
ArrayList<StorageResultSetFuture>(
+ scheduleIds.size());
+ for (Integer scheduleId : scheduleIds) {
+ oneHourDataQueryFutures.add(dao.findOneHourMetricsAsync(scheduleId,
+ state.getSixHourTimeSlice().getMillis(),
state.getSixHourTimeSliceEnd().getMillis()));
+ }
+ state.getAggregationTasks().submit(new Aggregate1HourData(dao, state,
scheduleIds,
+ oneHourDataQueryFutures));
+ }
+ } catch (InterruptedException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("An interrupt occurred while waiting for 1 hour data index
entries. Aborting data aggregation",
+ e);
+ } else {
+ log.info("An interrupt occurred while waiting for 1 hour data index
entries. Aborting data " +
+ "aggregation: " + e.getMessage());
+ }
+ } finally {
+ state.getRemainingRawData().addAndGet(-scheduleIds.size());
+ }
+ }
+
+ private void update1HourIndexEntries() throws InterruptedException {
+ try {
+ // Wait for the arrival so that we can remove the schedules ids in this
+ // batch from the one hour index entries. This will prevent duplicate tasks
+ // being submitted to process the same 1 hour data.
+ state.getOneHourIndexEntriesArrival().await();
+ try {
+ state.getOneHourIndexEntriesLock().writeLock().lock();
+ state.getOneHourIndexEntries().removeAll(scheduleIds);
+ } finally {
+ state.getOneHourIndexEntriesLock().writeLock().unlock();
+ }
+ } catch (AbortedException e) {
+ // This means we failed to retrieve the index entries. We can however
+ // continue generating 1 hour data because we do not need the index
+ // here since we already have 1 hour data to aggregate along with the
+ // schedule ids.
+ }
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregationState.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregationState.java
new file mode 100644
index 0000000..345e53a
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/AggregationState.java
@@ -0,0 +1,257 @@
+package org.rhq.server.metrics.aggregation;
+
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+
+import org.joda.time.DateTime;
+
+import org.rhq.server.metrics.SignalingCountDownLatch;
+
+/**
+ * @author John Sanda
+ */
+class AggregationState {
+
+ private ListeningExecutorService aggregationTasks;
+
+ private SignalingCountDownLatch oneHourIndexEntriesArrival;
+
+ private SignalingCountDownLatch sixHourIndexEntriesArrival;
+
+ private AtomicInteger remainingRawData;
+
+ private AtomicInteger remaining1HourData;
+
+ private AtomicInteger remaining6HourData;
+
+ private Set<Integer> oneHourIndexEntries;
+
+ private Set<Integer> sixHourIndexEntries;
+
+ private ReentrantReadWriteLock oneHourIndexEntriesLock;
+
+ private ReentrantReadWriteLock sixHourIndexEntriesLock;
+
+ private DateTime oneHourTimeSlice;
+
+ private DateTime sixHourTimeSlice;
+
+ private DateTime sixHourTimeSliceEnd;
+
+ private DateTime twentyFourHourTimeSlice;
+
+ private DateTime twentyFourHourTimeSliceEnd;
+
+ private boolean sixHourTimeSliceFinished;
+
+ private boolean twentyFourHourTimeSliceFinished;
+
+ private Compute1HourData compute1HourData;
+
+ private Compute6HourData compute6HourData;
+
+ private Compute24HourData compute24HourData;
+
+ public ListeningExecutorService getAggregationTasks() {
+ return aggregationTasks;
+ }
+
+ public AggregationState setAggregationTasks(ListeningExecutorService
aggregationTasks) {
+ this.aggregationTasks = aggregationTasks;
+ return this;
+ }
+
+ /**
+ * @return A {@link SignalingCountDownLatch} to signal the arrival of index entries
for schedules with 1 hour
+ * data to be aggregated
+ */
+ public SignalingCountDownLatch getOneHourIndexEntriesArrival() {
+ return oneHourIndexEntriesArrival;
+ }
+
+ public AggregationState setOneHourIndexEntriesArrival(SignalingCountDownLatch
oneHourIndexEntriesArrival) {
+ this.oneHourIndexEntriesArrival = oneHourIndexEntriesArrival;
+ return this;
+ }
+
+ /**
+ * @return A {@link SignalingCountDownLatch} to signal the arrival of index entries
for schedules with 6 hour
+ * data to be aggregated
+ */
+ public SignalingCountDownLatch getSixHourIndexEntriesArrival() {
+ return sixHourIndexEntriesArrival;
+ }
+
+ public AggregationState setSixHourIndexEntriesArrival(SignalingCountDownLatch
sixHourIndexEntriesArrival) {
+ this.sixHourIndexEntriesArrival = sixHourIndexEntriesArrival;
+ return this;
+ }
+
+ /**
+ * @return The remaining number of schedules with raw data to be aggregated
+ */
+ public AtomicInteger getRemainingRawData() {
+ return remainingRawData;
+ }
+
+ public AggregationState setRemainingRawData(AtomicInteger remainingRawData) {
+ this.remainingRawData = remainingRawData;
+ return this;
+ }
+
+ /**
+ * @return The remaining number of schedules with 1 hour data to be aggregated
+ */
+ public AtomicInteger getRemaining1HourData() {
+ return remaining1HourData;
+ }
+
+ public AggregationState setRemaining1HourData(AtomicInteger remaining1HourData) {
+ this.remaining1HourData = remaining1HourData;
+ return this;
+ }
+
+ /**
+ * @return The remaining number of schedules with 6 hour data to be aggregated
+ */
+ public AtomicInteger getRemaining6HourData() {
+ return remaining6HourData;
+ }
+
+ public AggregationState setRemaining6HourData(AtomicInteger remaining6HourData) {
+ this.remaining6HourData = remaining6HourData;
+ return this;
+ }
+
+ /**
+ * @return The schedule ids with 1 hour data to be aggregated
+ */
+ public Set<Integer> getOneHourIndexEntries() {
+ return oneHourIndexEntries;
+ }
+
+ public AggregationState setOneHourIndexEntries(Set<Integer>
oneHourIndexEntries) {
+ this.oneHourIndexEntries = oneHourIndexEntries;
+ return this;
+ }
+
+ public Set<Integer> getSixHourIndexEntries() {
+ return sixHourIndexEntries;
+ }
+
+ public AggregationState setSixHourIndexEntries(Set<Integer>
sixHourIndexEntries) {
+ this.sixHourIndexEntries = sixHourIndexEntries;
+ return this;
+ }
+
+ public ReentrantReadWriteLock getOneHourIndexEntriesLock() {
+ return oneHourIndexEntriesLock;
+ }
+
+ public AggregationState setOneHourIndexEntriesLock(ReentrantReadWriteLock
oneHourIndexEntriesLock) {
+ this.oneHourIndexEntriesLock = oneHourIndexEntriesLock;
+ return this;
+ }
+
+ public ReentrantReadWriteLock getSixHourIndexEntriesLock() {
+ return sixHourIndexEntriesLock;
+ }
+
+ public AggregationState setSixHourIndexEntriesLock(ReentrantReadWriteLock
sixHourIndexEntriesLock) {
+ this.sixHourIndexEntriesLock = sixHourIndexEntriesLock;
+ return this;
+ }
+
+ public DateTime getOneHourTimeSlice() {
+ return oneHourTimeSlice;
+ }
+
+ public AggregationState setOneHourTimeSlice(DateTime oneHourTimeSlice) {
+ this.oneHourTimeSlice = oneHourTimeSlice;
+ return this;
+ }
+
+ public DateTime getSixHourTimeSlice() {
+ return sixHourTimeSlice;
+ }
+
+ public AggregationState setSixHourTimeSlice(DateTime sixHourTimeSlice) {
+ this.sixHourTimeSlice = sixHourTimeSlice;
+ return this;
+ }
+
+ public DateTime getSixHourTimeSliceEnd() {
+ return sixHourTimeSliceEnd;
+ }
+
+ public AggregationState setSixHourTimeSliceEnd(DateTime sixHourTimeSliceEnd) {
+ this.sixHourTimeSliceEnd = sixHourTimeSliceEnd;
+ return this;
+ }
+
+ public DateTime getTwentyFourHourTimeSlice() {
+ return twentyFourHourTimeSlice;
+ }
+
+ public AggregationState setTwentyFourHourTimeSlice(DateTime twentyFourHourTimeSlice)
{
+ this.twentyFourHourTimeSlice = twentyFourHourTimeSlice;
+ return this;
+ }
+
+ public DateTime getTwentyFourHourTimeSliceEnd() {
+ return twentyFourHourTimeSliceEnd;
+ }
+
+ public AggregationState setTwentyFourHourTimeSliceEnd(DateTime
twentyFourHourTimeSliceEnd) {
+ this.twentyFourHourTimeSliceEnd = twentyFourHourTimeSliceEnd;
+ return this;
+ }
+
+ public boolean is6HourTimeSliceFinished() {
+ return sixHourTimeSliceFinished;
+ }
+
+ public AggregationState set6HourTimeSliceFinished(boolean is6HourTimeSliceFinished)
{
+ this.sixHourTimeSliceFinished = is6HourTimeSliceFinished;
+ return this;
+ }
+
+ public boolean is24HourTimeSliceFinished() {
+ return twentyFourHourTimeSliceFinished;
+ }
+
+ public AggregationState set24HourTimeSliceFinished(boolean is24HourTimeSliceFinished)
{
+ this.twentyFourHourTimeSliceFinished = is24HourTimeSliceFinished;
+ return this;
+ }
+
+ public Compute1HourData getCompute1HourData() {
+ return compute1HourData;
+ }
+
+ public AggregationState setCompute1HourData(Compute1HourData compute1HourData) {
+ this.compute1HourData = compute1HourData;
+ return this;
+ }
+
+ public Compute6HourData getCompute6HourData() {
+ return compute6HourData;
+ }
+
+ public AggregationState setCompute6HourData(Compute6HourData compute6HourData) {
+ this.compute6HourData = compute6HourData;
+ return this;
+ }
+
+ public Compute24HourData getCompute24HourData() {
+ return compute24HourData;
+ }
+
+ public AggregationState setCompute24HourData(Compute24HourData compute24HourData) {
+ this.compute24HourData = compute24HourData;
+ return this;
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregator.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregator.java
new file mode 100644
index 0000000..bf0bc1a
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Aggregator.java
@@ -0,0 +1,378 @@
+package org.rhq.server.metrics.aggregation;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.RateLimiter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeComparator;
+import org.joda.time.Duration;
+
+import org.rhq.core.util.exception.ThrowableUtil;
+import org.rhq.server.metrics.AbortedException;
+import org.rhq.server.metrics.DateTimeService;
+import org.rhq.server.metrics.MetricsConfiguration;
+import org.rhq.server.metrics.MetricsDAO;
+import org.rhq.server.metrics.SignalingCountDownLatch;
+import org.rhq.server.metrics.StorageResultSetFuture;
+import org.rhq.server.metrics.domain.AggregateNumericMetric;
+import org.rhq.server.metrics.domain.MetricsTable;
+
+/**
+ * This class provides the main interface for metric data aggregation.
+ *
+ * @author John Sanda
+ */
+public class Aggregator {
+
+ private static final Comparator<AggregateNumericMetric> AGGREGATE_COMPARATOR =
new Comparator<AggregateNumericMetric>() {
+ @Override
+ public int compare(AggregateNumericMetric left, AggregateNumericMetric right) {
+ return (left.getScheduleId() < right.getScheduleId()) ? -1 :
((left.getScheduleId() == right.getScheduleId()) ? 0 : 1);
+ }
+ };
+
+ private final Log log = LogFactory.getLog(Aggregator.class);
+
+ private MetricsDAO dao;
+
+ private MetricsConfiguration configuration;
+
+ private DateTimeService dtService;
+
+ private DateTime startTime;
+
+ /**
+ * Signals when raw data index entries (in metrics_index) can be deleted. We cannot
delete the row in metrics_index
+ * until we know that it has been read, successfully or otherwise.
+ */
+ private SignalingCountDownLatch rawDataIndexEntriesArrival;
+
+ private RateLimiter readPermits;
+ private RateLimiter writePermits;
+
+ private int batchSize;
+
+ private AggregationState state;
+
+ private Set<AggregateNumericMetric> oneHourData;
+
+ private AtomicInteger remainingIndexEntries;
+
+ public Aggregator(ListeningExecutorService aggregationTasks, MetricsDAO dao,
MetricsConfiguration configuration,
+ DateTimeService dtService, DateTime startTime, int batchSize, RateLimiter
writePermits,
+ RateLimiter readPermits) {
+ this.dao = dao;
+ this.configuration = configuration;
+ this.dtService = dtService;
+ this.startTime = startTime;
+ this.readPermits = readPermits;
+ this.writePermits = writePermits;
+ this.batchSize = batchSize;
+ oneHourData = new
ConcurrentSkipListSet<AggregateNumericMetric>(AGGREGATE_COMPARATOR);
+ rawDataIndexEntriesArrival = new SignalingCountDownLatch(new CountDownLatch(1));
+ remainingIndexEntries = new AtomicInteger(1);
+
+ DateTime sixHourTimeSlice = get6HourTimeSlice();
+ DateTime twentyFourHourTimeSlice = get24HourTimeSlice();
+
+ state = new AggregationState()
+ .setAggregationTasks(aggregationTasks)
+ .setOneHourTimeSlice(startTime)
+ .setSixHourTimeSlice(sixHourTimeSlice)
+
.setSixHourTimeSliceEnd(sixHourTimeSlice.plus(configuration.getOneHourTimeSliceDuration()))
+ .setTwentyFourHourTimeSlice(twentyFourHourTimeSlice)
+
.setTwentyFourHourTimeSliceEnd(twentyFourHourTimeSlice.plus(configuration.getSixHourTimeSliceDuration()))
+ .setCompute1HourData(new Compute1HourData(startTime, sixHourTimeSlice,
writePermits, dao, oneHourData))
+ .setCompute6HourData(new Compute6HourData(sixHourTimeSlice,
twentyFourHourTimeSlice, writePermits, dao))
+ .setCompute24HourData(new Compute24HourData(twentyFourHourTimeSlice,
writePermits, dao))
+ .set6HourTimeSliceFinished(hasTimeSliceEnded(sixHourTimeSlice,
configuration.getOneHourTimeSliceDuration()))
+ .set24HourTimeSliceFinished(hasTimeSliceEnded(twentyFourHourTimeSlice,
+ configuration.getSixHourTimeSliceDuration()))
+ .setRemainingRawData(new AtomicInteger(0))
+ .setRemaining1HourData(new AtomicInteger(0))
+ .setRemaining6HourData(new AtomicInteger(0))
+ .setOneHourIndexEntries(new TreeSet<Integer>())
+ .setSixHourIndexEntries(new TreeSet<Integer>())
+ .setOneHourIndexEntriesLock(new ReentrantReadWriteLock())
+ .setSixHourIndexEntriesLock(new ReentrantReadWriteLock());
+
+ if (state.is6HourTimeSliceFinished()) {
+ state.setOneHourIndexEntriesArrival(new SignalingCountDownLatch(new
CountDownLatch(1)));
+ remainingIndexEntries.incrementAndGet();
+ } else {
+ state.setOneHourIndexEntriesArrival(new SignalingCountDownLatch(new
CountDownLatch(0)));
+ state.setRemaining1HourData(new AtomicInteger(0));
+ }
+
+ if (state.is24HourTimeSliceFinished()) {
+ state.setSixHourIndexEntriesArrival(new SignalingCountDownLatch(new
CountDownLatch(1)));
+ remainingIndexEntries.incrementAndGet();
+ } else {
+ state.setSixHourIndexEntriesArrival(new SignalingCountDownLatch(new
CountDownLatch(0)));
+ state.setRemaining6HourData(new AtomicInteger(0));
+ }
+ }
+
+ private DateTime get24HourTimeSlice() {
+ return dtService.getTimeSlice(startTime,
configuration.getSixHourTimeSliceDuration());
+ }
+
+ private DateTime get6HourTimeSlice() {
+ return dtService.getTimeSlice(startTime,
configuration.getOneHourTimeSliceDuration());
+ }
+
+ private boolean hasTimeSliceEnded(DateTime startTime, Duration duration) {
+ DateTime endTime = startTime.plus(duration);
+ return DateTimeComparator.getInstance().compare(currentHour(), endTime) >= 0;
+ }
+
+ protected DateTime currentHour() {
+ return dtService.getTimeSlice(dtService.now(),
configuration.getRawTimeSliceDuration());
+ }
+
+ public Set<AggregateNumericMetric> run() {
+ log.info("Starting aggregation for time slice " + startTime);
+ readPermits.acquire();
+ StorageResultSetFuture rawFuture =
dao.findMetricsIndexEntriesAsync(MetricsTable.ONE_HOUR,
+ startTime.getMillis());
+ Futures.addCallback(rawFuture, new FutureCallback<ResultSet>() {
+ @Override
+ public void onSuccess(ResultSet result) {
+ List<Row> rows = result.all();
+ state.getRemainingRawData().set(rows.size());
+ rawDataIndexEntriesArrival.countDown();
+
+ Stopwatch stopwatch = new Stopwatch().start();
+
+ final DateTime endTime =
startTime.plus(configuration.getRawTimeSliceDuration());
+ Set<Integer> scheduleIds = new TreeSet<Integer>();
+ List<StorageResultSetFuture> rawDataFutures = new
ArrayList<StorageResultSetFuture>(batchSize);
+ for (final Row row : rows) {
+ scheduleIds.add(row.getInt(1));
+ readPermits.acquire();
+ rawDataFutures.add(dao.findRawMetricsAsync(row.getInt(1),
startTime.getMillis(),
+ endTime.getMillis()));
+ if (rawDataFutures.size() == batchSize) {
+ state.getAggregationTasks().submit(new AggregateRawData(dao,
state, scheduleIds,
+ rawDataFutures));
+ rawDataFutures = new ArrayList<StorageResultSetFuture>();
+ scheduleIds = new TreeSet<Integer>();
+ }
+ }
+ if (!rawDataFutures.isEmpty()) {
+ state.getAggregationTasks().submit(new AggregateRawData(dao, state,
scheduleIds,
+ rawDataFutures));
+ }
+
+ if (log.isDebugEnabled()) {
+ stopwatch.stop();
+ log.debug("Finished scheduling raw data aggregation tasks for
" + rows.size() + " schedules in " +
+ stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms");
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ if (log.isDebugEnabled()) {
+ log.debug("Aggregation for time slice [" + startTime +
"] cannot proceed. There was an " +
+ "unexpected error while retrieving raw data index
entries.", t);
+ } else {
+ log.warn("Aggregation for time slice [" + startTime +
"] cannot proceed. There was an " +
+ "unexpected error while retrieving raw data index entries:
" + ThrowableUtil.getRootMessage(t));
+ }
+ state.setRemainingRawData(new AtomicInteger(0));
+ rawDataIndexEntriesArrival.abort();
+ deleteIndexEntries(MetricsTable.ONE_HOUR);
+ }
+ }, state.getAggregationTasks());
+
+ if (state.is6HourTimeSliceFinished()) {
+ log.debug("Fetching 1 hour index entries");
+ Stopwatch stopwatch = new Stopwatch().start();
+ StorageResultSetFuture oneHourFuture =
dao.findMetricsIndexEntriesAsync(MetricsTable.SIX_HOUR,
+ state.getSixHourTimeSlice().getMillis());
+ Futures.addCallback(oneHourFuture, new
AggregateIndexEntriesHandler(state.getOneHourIndexEntries(),
+ state.getRemaining1HourData(), state.getOneHourIndexEntriesArrival(),
stopwatch, "1 hour", "6 hour"),
+ state.getAggregationTasks());
+ }
+
+ if (state.is24HourTimeSliceFinished()) {
+ log.debug("Fetching 6 hour index entries");
+ Stopwatch stopwatch = new Stopwatch().start();
+ StorageResultSetFuture sixHourFuture =
dao.findMetricsIndexEntriesAsync(MetricsTable.TWENTY_FOUR_HOUR,
+ state.getTwentyFourHourTimeSlice().getMillis());
+ Futures.addCallback(sixHourFuture, new
AggregateIndexEntriesHandler(state.getSixHourIndexEntries(),
+ state.getRemaining6HourData(), state.getSixHourIndexEntriesArrival(),
stopwatch, "6 hour", "24 hour"),
+ state.getAggregationTasks());
+ }
+
+ try {
+ try {
+ rawDataIndexEntriesArrival.await();
+ deleteIndexEntries(MetricsTable.ONE_HOUR);
+ } catch (AbortedException e) {
+ }
+
+ if (state.is6HourTimeSliceFinished()) {
+ waitFor(state.getRemainingRawData());
+ try {
+ state.getOneHourIndexEntriesArrival().await();
+ deleteIndexEntries(MetricsTable.SIX_HOUR);
+
+ List<StorageResultSetFuture> queryFutures = new
ArrayList<StorageResultSetFuture>(batchSize);
+ Set<Integer> scheduleIds = new TreeSet<Integer>();
+ state.getOneHourIndexEntriesLock().writeLock().lock();
+ log.debug("Preparing to submit 1 hour data aggregation tasks for
" +
+ state.getOneHourIndexEntries().size() + " schedules");
+ for (Integer scheduleId : state.getOneHourIndexEntries()) {
+ queryFutures.add(dao.findOneHourMetricsAsync(scheduleId,
state.getSixHourTimeSlice().getMillis(),
+ state.getSixHourTimeSliceEnd().getMillis()));
+ scheduleIds.add(scheduleId);
+ if (queryFutures.size() == batchSize) {
+ state.getAggregationTasks().submit(new
Aggregate1HourData(dao, state, scheduleIds,
+ queryFutures));
+ queryFutures = new
ArrayList<StorageResultSetFuture>(batchSize);
+ scheduleIds = new TreeSet<Integer>();
+ }
+ }
+ if (!queryFutures.isEmpty()) {
+ state.getAggregationTasks().submit(new Aggregate1HourData(dao,
state, scheduleIds,
+ queryFutures));
+ queryFutures = null;
+ scheduleIds = null;
+ }
+ } catch (AbortedException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Some 6 hour aggregates may not get generated.
There was an unexpected error while " +
+ "loading 1 hour index entries", e);
+ } else {
+ log.warn("Some 6 hour aggregates may not get generated.
There was an unexpected error while " +
+ "loading 1 hour index entries: " +
ThrowableUtil.getRootMessage(e));
+ }
+ } finally {
+ state.getOneHourIndexEntriesLock().writeLock().unlock();
+ }
+ }
+
+ if (state.is24HourTimeSliceFinished()) {
+ waitFor(state.getRemaining1HourData());
+ try {
+ state.getSixHourIndexEntriesArrival().await();
+ deleteIndexEntries(MetricsTable.TWENTY_FOUR_HOUR);
+
+ List<StorageResultSetFuture> queryFutures = new
ArrayList<StorageResultSetFuture>(batchSize);
+ Set<Integer> scheduleIds = new TreeSet<Integer>();
+ state.getSixHourIndexEntriesLock().writeLock().lock();
+ log.debug("Preparing to submit 6 hour data aggregation tasks for
" +
+ state.getSixHourIndexEntries().size() + " schedules");
+ for (Integer scheduleId : state.getSixHourIndexEntries()) {
+ queryFutures.add(dao.findSixHourMetricsAsync(scheduleId,
state.getTwentyFourHourTimeSlice().getMillis(),
+ state.getTwentyFourHourTimeSliceEnd().getMillis()));
+ scheduleIds.add(scheduleId);
+ if (queryFutures.size() == batchSize) {
+ state.getAggregationTasks().submit(new
Aggregate6HourData(dao, state, scheduleIds,
+ queryFutures));
+ queryFutures = new
ArrayList<StorageResultSetFuture>(batchSize);
+ scheduleIds = new TreeSet<Integer>();
+ }
+ }
+ if (!queryFutures.isEmpty()) {
+ state.getAggregationTasks().submit(new Aggregate6HourData(dao,
state, scheduleIds,
+ queryFutures));
+ queryFutures = null;
+ scheduleIds = null;
+ }
+ } catch (AbortedException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Some 24 hour aggregates may not get generated.
There was an unexpected error while " +
+ "loading 6 hour index entries", e);
+ } else {
+ log.warn("Some 24 hour aggregates may not get generated.
There was an unexpected error while " +
+ "loading 6 hour index entries: " +
ThrowableUtil.getRootMessage(e));
+ }
+ } finally {
+ state.getSixHourIndexEntriesLock().writeLock().unlock();
+ }
+ }
+
+ while (!isAggregationFinished()) {
+ Thread.sleep(50);
+ }
+ } catch (InterruptedException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("An interrupt occurred while waiting for aggregation to
finish. Aborting remaining work.", e);
+ } else {
+ log.warn("An interrupt occurred while waiting for aggregation to
finish. Aborting remaining work: " +
+ ThrowableUtil.getRootMessage(e));
+ }
+ log.warn("An interrupt occurred while waiting for aggregation to
finish", e);
+ }
+ return oneHourData;
+ }
+
+ private void waitFor(AtomicInteger remainingData) throws InterruptedException {
+ while (remainingData.get() > 0) {
+ Thread.sleep(50);
+ }
+ }
+
+ private boolean isAggregationFinished() {
+ return state.getRemainingRawData().get() <= 0 &&
state.getRemaining1HourData().get() <= 0 &&
+ state.getRemaining6HourData().get() <= 0 &&
remainingIndexEntries.get() <= 0;
+ }
+
+ private void deleteIndexEntries(final MetricsTable table) {
+ final DateTime time;
+ switch (table) {
+ case ONE_HOUR:
+ time = startTime;
+ break;
+ case SIX_HOUR:
+ time = state.getSixHourTimeSlice();
+ break;
+ default:
+ time = state.getTwentyFourHourTimeSlice();
+ break;
+ }
+ log.debug("Deleting " + table + " index entries for time slice
" + time);
+ writePermits.acquire();
+ StorageResultSetFuture future = dao.deleteMetricsIndexEntriesAsync(table,
time.getMillis());
+ Futures.addCallback(future, new FutureCallback<ResultSet>() {
+ @Override
+ public void onSuccess(ResultSet result) {
+ remainingIndexEntries.decrementAndGet();
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ if (log.isDebugEnabled()) {
+ log.debug("Failed to delete index entries for table " +
table + " at time [" + time + "]. An " +
+ "unexpected error occurred.", t);
+ } else {
+ log.warn("Failed to delete index entries for table " +
table + " at time [" + time + "]. An " +
+ "unexpected error occurred: " +
ThrowableUtil.getRootMessage(t));
+ }
+ remainingIndexEntries.decrementAndGet();
+ }
+ });
+ }
+
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute1HourData.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute1HourData.java
new file mode 100644
index 0000000..f130f75
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute1HourData.java
@@ -0,0 +1,113 @@
+package org.rhq.server.metrics.aggregation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.RateLimiter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.DateTime;
+
+import org.rhq.server.metrics.ArithmeticMeanCalculator;
+import org.rhq.server.metrics.MetricsDAO;
+import org.rhq.server.metrics.StorageResultSetFuture;
+import org.rhq.server.metrics.domain.AggregateNumericMetric;
+import org.rhq.server.metrics.domain.AggregateType;
+import org.rhq.server.metrics.domain.MetricsTable;
+
+/**
+ * Computes 1 hour data for a batch of raw data result sets. The generated 1 hour
aggregates are inserted along with
+ * their corresponding index updates.
+ *
+ * @author John Sanda
+ */
+class Compute1HourData implements AsyncFunction<List<ResultSet>,
List<ResultSet>> {
+
+ private final Log log = LogFactory.getLog(Compute1HourData.class);
+
+ private DateTime startTime;
+
+ private RateLimiter writePermits;
+
+ private MetricsDAO dao;
+
+ private DateTime sixHourTimeSlice;
+
+ private Set<AggregateNumericMetric> oneHourData;
+
+ public Compute1HourData(DateTime startTime, DateTime sixHourTimeSlice, RateLimiter
writePermits, MetricsDAO dao,
+ Set<AggregateNumericMetric> oneHourData) {
+ this.startTime = startTime;
+ this.sixHourTimeSlice = sixHourTimeSlice;
+ this.writePermits = writePermits;
+ this.dao = dao;
+ this.oneHourData = oneHourData;
+ }
+
+ @Override
+ public ListenableFuture<List<ResultSet>> apply(List<ResultSet>
rawDataResultSets) throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("Computing and storing 1 hour data for " +
rawDataResultSets.size() + " schedules");
+ }
+ Stopwatch stopwatch = new Stopwatch().start();
+ try {
+ List<StorageResultSetFuture> insertFutures = new
ArrayList<StorageResultSetFuture>(rawDataResultSets.size());
+ for (ResultSet resultSet : rawDataResultSets) {
+ AggregateNumericMetric aggregate = calculateAggregatedRaw(resultSet);
+ oneHourData.add(aggregate);
+ writePermits.acquire(4);
+ insertFutures.add(dao.insertOneHourDataAsync(aggregate.getScheduleId(),
aggregate.getTimestamp(),
+ AggregateType.MIN, aggregate.getMin()));
+ insertFutures.add(dao.insertOneHourDataAsync(aggregate.getScheduleId(),
aggregate.getTimestamp(),
+ AggregateType.MAX, aggregate.getMax()));
+ insertFutures.add(dao.insertOneHourDataAsync(aggregate.getScheduleId(),
aggregate.getTimestamp(),
+ AggregateType.AVG, aggregate.getAvg()));
+ insertFutures.add(dao.updateMetricsIndex(MetricsTable.SIX_HOUR,
aggregate.getScheduleId(),
+ sixHourTimeSlice.getMillis()));
+ }
+ return Futures.successfulAsList(insertFutures);
+ } finally {
+ if (log.isDebugEnabled()) {
+ stopwatch.stop();
+ log.debug("Finished computing and storing 1 hour data for " +
rawDataResultSets.size() +
+ " schedules in " + stopwatch.elapsed(TimeUnit.MILLISECONDS)
+ " ms");
+ }
+ }
+ }
+
+ private AggregateNumericMetric calculateAggregatedRaw(ResultSet resultSet) {
+ double min = Double.NaN;
+ double max = min;
+ int count = 0;
+ ArithmeticMeanCalculator mean = new ArithmeticMeanCalculator();
+ double value;
+ List<Row> rows = resultSet.all();
+
+ for (Row row : rows) {
+ value = row.getDouble(2);
+ if (count == 0) {
+ min = value;
+ max = min;
+ }
+ if (value < min) {
+ min = value;
+ } else if (value > max) {
+ max = value;
+ }
+ mean.add(value);
+ ++count;
+ }
+
+ return new AggregateNumericMetric(rows.get(0).getInt(0),
mean.getArithmeticMean(), min, max,
+ startTime.getMillis());
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute24HourData.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute24HourData.java
new file mode 100644
index 0000000..6fe9d79
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute24HourData.java
@@ -0,0 +1,99 @@
+package org.rhq.server.metrics.aggregation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.RateLimiter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.DateTime;
+
+import org.rhq.server.metrics.ArithmeticMeanCalculator;
+import org.rhq.server.metrics.MetricsDAO;
+import org.rhq.server.metrics.StorageResultSetFuture;
+import org.rhq.server.metrics.domain.AggregateNumericMetric;
+import org.rhq.server.metrics.domain.AggregateType;
+
+/**
+ * Computes 24 hour data for a batch of raw data result sets. The generated 6 hour
aggregates are inserted.
+ *
+ * @author John Sanda
+ */
+class Compute24HourData implements AsyncFunction<List<ResultSet>,
List<ResultSet>> {
+
+ private final Log log = LogFactory.getLog(Compute24HourData.class);
+
+ private DateTime startTime;
+
+ private RateLimiter writePermits;
+
+ private MetricsDAO dao;
+
+ public Compute24HourData(DateTime startTime, RateLimiter writePermits, MetricsDAO
dao) {
+ this.startTime = startTime;
+ this.writePermits = writePermits;
+ this.dao = dao;
+ }
+
+ @Override
+ public ListenableFuture<List<ResultSet>> apply(List<ResultSet>
sixHourDataResultSets) throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("Computing and storing 24 hour data for " +
sixHourDataResultSets.size() + " schedules");
+ }
+ Stopwatch stopwatch = new Stopwatch().start();
+ try {
+ List<StorageResultSetFuture> insertFutures =
+ new
ArrayList<StorageResultSetFuture>(sixHourDataResultSets.size());
+ for (ResultSet resultSet : sixHourDataResultSets) {
+ AggregateNumericMetric aggregate = calculateAggregate(resultSet);
+ writePermits.acquire(3);
+
insertFutures.add(dao.insertTwentyFourHourDataAsync(aggregate.getScheduleId(),
aggregate.getTimestamp(),
+ AggregateType.MIN, aggregate.getMin()));
+
insertFutures.add(dao.insertTwentyFourHourDataAsync(aggregate.getScheduleId(),
aggregate.getTimestamp(),
+ AggregateType.MAX, aggregate.getMax()));
+
insertFutures.add(dao.insertTwentyFourHourDataAsync(aggregate.getScheduleId(),
aggregate.getTimestamp(),
+ AggregateType.AVG, aggregate.getAvg()));
+ }
+ return Futures.successfulAsList(insertFutures);
+ } finally {
+ if (log.isDebugEnabled()) {
+ stopwatch.stop();
+ log.debug("Finished computing and storing 24 hour data for " +
sixHourDataResultSets.size() +
+ " schedules in " + stopwatch.elapsed(TimeUnit.MILLISECONDS)
+ " ms");
+ }
+ }
+ }
+
+ private AggregateNumericMetric calculateAggregate(ResultSet resultSet) {
+ double min = Double.NaN;
+ double max = min;
+ ArithmeticMeanCalculator mean = new ArithmeticMeanCalculator();
+ List<Row> rows = resultSet.all();
+
+ for (int i = 0; i < rows.size(); i += 3) {
+ if (i == 0) {
+ min = rows.get(i + 1).getDouble(3);
+ max = rows.get(i).getDouble(3);
+ } else {
+ if (rows.get(i + 1).getDouble(3) < min) {
+ min = rows.get(i + 1).getDouble(3);
+ }
+ if (rows.get(i).getDouble(3) > max) {
+ max = rows.get(i).getDouble(3);
+ }
+ }
+ mean.add(rows.get(i + 2).getDouble(3));
+ }
+ return new AggregateNumericMetric(rows.get(0).getInt(0),
mean.getArithmeticMean(), min, max,
+ startTime.getMillis());
+ }
+
+}
diff --git
a/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute6HourData.java
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute6HourData.java
new file mode 100644
index 0000000..ec1ee26
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/main/java/org/rhq/server/metrics/aggregation/Compute6HourData.java
@@ -0,0 +1,106 @@
+package org.rhq.server.metrics.aggregation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.RateLimiter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.DateTime;
+
+import org.rhq.server.metrics.ArithmeticMeanCalculator;
+import org.rhq.server.metrics.MetricsDAO;
+import org.rhq.server.metrics.StorageResultSetFuture;
+import org.rhq.server.metrics.domain.AggregateNumericMetric;
+import org.rhq.server.metrics.domain.AggregateType;
+import org.rhq.server.metrics.domain.MetricsTable;
+
+/**
+ * Computes 6 hour data for a batch of raw data result sets. The generated 6 hour
aggregates are inserted along with
+ * their corresponding index updates.
+ *
+ * @author John Sanda
+ */
+class Compute6HourData implements AsyncFunction<List<ResultSet>,
List<ResultSet>> {
+
+ private final Log log = LogFactory.getLog(Compute6HourData.class);
+
+ private DateTime startTime;
+
+ private RateLimiter writePermits;
+
+ private MetricsDAO dao;
+
+ private DateTime twentyFourHourTimeSlice;
+
+ public Compute6HourData(DateTime startTime, DateTime twentyFourHourTimeSlice,
RateLimiter writePermits,
+ MetricsDAO dao) {
+ this.startTime = startTime;
+ this.twentyFourHourTimeSlice = twentyFourHourTimeSlice;
+ this.writePermits = writePermits;
+ this.dao = dao;
+ }
+
+ @Override
+ public ListenableFuture<List<ResultSet>> apply(List<ResultSet>
oneHourDataResultSets) throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("Computing and storing 6 hour data for " +
oneHourDataResultSets.size() + " schedules");
+ }
+ Stopwatch stopwatch = new Stopwatch().start();
+ try {
+ List<StorageResultSetFuture> insertFutures =
+ new
ArrayList<StorageResultSetFuture>(oneHourDataResultSets.size());
+ for (ResultSet resultSet : oneHourDataResultSets) {
+ AggregateNumericMetric aggregate = calculateAggregate(resultSet);
+ writePermits.acquire(4);
+ insertFutures.add(dao.insertSixHourDataAsync(aggregate.getScheduleId(),
aggregate.getTimestamp(),
+ AggregateType.MIN, aggregate.getMin()));
+ insertFutures.add(dao.insertSixHourDataAsync(aggregate.getScheduleId(),
aggregate.getTimestamp(),
+ AggregateType.MAX, aggregate.getMax()));
+ insertFutures.add(dao.insertSixHourDataAsync(aggregate.getScheduleId(),
aggregate.getTimestamp(),
+ AggregateType.AVG, aggregate.getAvg()));
+ insertFutures.add(dao.updateMetricsIndex(MetricsTable.TWENTY_FOUR_HOUR,
aggregate.getScheduleId(),
+ twentyFourHourTimeSlice.getMillis()));
+ }
+ return Futures.successfulAsList(insertFutures);
+ } finally {
+ if (log.isDebugEnabled()) {
+ stopwatch.stop();
+ log.debug("Finished computing and storing 6 hour data for " +
oneHourDataResultSets.size() +
+ " schedules in " + stopwatch.elapsed(TimeUnit.MILLISECONDS)
+ " ms");
+ }
+ }
+ }
+
+ private AggregateNumericMetric calculateAggregate(ResultSet resultSet) {
+ double min = Double.NaN;
+ double max = min;
+ ArithmeticMeanCalculator mean = new ArithmeticMeanCalculator();
+ List<Row> rows = resultSet.all();
+
+ for (int i = 0; i < rows.size(); i += 3) {
+ if (i == 0) {
+ min = rows.get(i + 1).getDouble(3);
+ max = rows.get(i).getDouble(3);
+ } else {
+ if (rows.get(i + 1).getDouble(3) < min) {
+ min = rows.get(i + 1).getDouble(3);
+ }
+ if (rows.get(i).getDouble(3) > max) {
+ max = rows.get(i).getDouble(3);
+ }
+ }
+ mean.add(rows.get(i + 2).getDouble(3));
+ }
+ return new AggregateNumericMetric(rows.get(0).getInt(0),
mean.getArithmeticMean(), min, max,
+ startTime.getMillis());
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregationTests.java
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregationTests.java
new file mode 100644
index 0000000..7d66cef
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/AggregationTests.java
@@ -0,0 +1,498 @@
+package org.rhq.server.metrics;
+
+import static java.util.Arrays.asList;
+import static org.rhq.test.AssertUtils.assertCollectionEqualsNoOrder;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+import com.datastax.driver.core.ResultSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.RateLimiter;
+import com.google.common.util.concurrent.SettableFuture;
+
+import org.joda.time.DateTime;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.rhq.core.domain.measurement.MeasurementDataNumeric;
+import org.rhq.server.metrics.aggregation.Aggregator;
+import org.rhq.server.metrics.domain.AggregateNumericMetric;
+import org.rhq.server.metrics.domain.AggregateType;
+import org.rhq.server.metrics.domain.MetricsIndexEntry;
+import org.rhq.server.metrics.domain.MetricsTable;
+
+/**
+ * @author John Sanda
+ */
+public class AggregationTests extends MetricsTest {
+
+ private Aggregates schedule1 = new Aggregates();
+ private Aggregates schedule2 = new Aggregates();
+ private Aggregates schedule3 = new Aggregates();
+ private Aggregates schedule4 = new Aggregates();
+ private Aggregates schedule5 = new Aggregates();
+
+ private ListeningExecutorService aggregationTasks;
+
+ private DateTime currentHour;
+
+ private RateLimiter writePermits;
+ private RateLimiter readPermits;
+
+ @BeforeClass
+ public void setUp() throws Exception {
+ purgeDB();
+
+ schedule1.id = 100;
+ schedule2.id = 101;
+ schedule3.id = 102;
+ schedule4.id = 104;
+ schedule5.id = 105;
+
+ aggregationTasks =
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
+ writePermits = RateLimiter.create(500);
+ readPermits = RateLimiter.create(350);
+ }
+
+ @Test
+ public void insertRawDataDuringHour16() throws Exception {
+ insertRawData(
+ new MeasurementDataNumeric(hour(16).plusMinutes(20).getMillis(),
schedule1.id, 3.0),
+ new MeasurementDataNumeric(hour(16).plusMinutes(40).getMillis(),
schedule1.id, 5.0),
+ new MeasurementDataNumeric(hour(16).plusMinutes(15).getMillis(),
schedule2.id, 0.0032),
+ new MeasurementDataNumeric(hour(16).plusMinutes(30).getMillis(),
schedule2.id, 0.104),
+ new MeasurementDataNumeric(hour(16).plusMinutes(7).getMillis(), schedule3.id,
3.14)
+ ).await("Failed to insert raw data");
+
+ updateIndex(
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule1.id, hour(16)),
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule2.id, hour(16)),
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule3.id, hour(16))
+ ).await("Failed to update raw data index");
+ }
+
+ @Test(dependsOnMethods = "insertRawDataDuringHour16")
+ public void runAggregationForHour16() throws Exception {
+ currentHour = hour(17);
+ AggregatorTestStub aggregator = new AggregatorTestStub(hour(16));
+
+ Set<AggregateNumericMetric> oneHourData = aggregator.run();
+
+ schedule1.oneHourData.put(hour(16), new AggregateNumericMetric(schedule1.id,
avg(3.0, 5.0), 3.0, 5.0,
+ hour(16).getMillis()));
+ schedule2.oneHourData.put(hour(16), new AggregateNumericMetric(schedule2.id,
avg(0.0032, 0.104), 0.0032, 0.104,
+ hour(16).getMillis()));
+ schedule3.oneHourData.put(hour(16), new AggregateNumericMetric(schedule3.id,
3.14, 3.14, 3.14,
+ hour(16).getMillis()));
+
+ List<AggregateNumericMetric> expected =
asList(schedule1.oneHourData.get(hour(16)),
+ schedule2.oneHourData.get(hour(16)), schedule3.oneHourData.get(hour(16)));
+ assertCollectionEqualsNoOrder(expected, oneHourData, "The returned one hour
aggregates are wrong");
+ // verify values in the db
+ assert1HourDataEquals(schedule1.id, schedule1.oneHourData.get(hour(16)));
+ assert1HourDataEquals(schedule2.id, schedule2.oneHourData.get(hour(16)));
+ assert1HourDataEquals(schedule3.id, schedule3.oneHourData.get(hour(16)));
+ assert6HourIndexEquals(hour(12), schedule1.id, schedule2.id, schedule3.id);
+ assert6HourDataEmpty(schedule1.id);
+ assert6HourDataEmpty(schedule2.id);
+ assert6HourDataEmpty(schedule3.id);
+ assert24HourMetricsIndexEmpty(hour(0));
+ assert24HourMetricsIndexEmpty(hour(0));
+ assert1HourMetricsIndexEmpty(hour(16));
+ }
+
+ @Test(dependsOnMethods = "runAggregationForHour16")
+ public void insertRawDataDuringHour17() throws Exception {
+ insertRawData(
+ new MeasurementDataNumeric(hour(17).plusMinutes(20).getMillis(),
schedule1.id, 11.0),
+ new MeasurementDataNumeric(hour(17).plusMinutes(40).getMillis(),
schedule1.id, 16.0),
+ new MeasurementDataNumeric(hour(17).plusMinutes(30).getMillis(),
schedule2.id, 0.092),
+ new MeasurementDataNumeric(hour(17).plusMinutes(45).getMillis(),
schedule2.id, 0.0733)
+ ).await("Failed to insert raw data");
+
+ updateIndex(
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule1.id, hour(17)),
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule2.id, hour(17))
+ ).await("Failed to update raw data index");
+ }
+
+ @Test(dependsOnMethods = "insertRawDataDuringHour17")
+ public void runAggregationForHour17() throws Exception {
+ currentHour = hour(18);
+ AggregatorTestStub aggregator = new AggregatorTestStub(hour(17));
+
+ Set<AggregateNumericMetric> oneHourData = aggregator.run();
+
+ schedule1.oneHourData.put(hour(17), new AggregateNumericMetric(schedule1.id,
avg(11.0, 16.0), 11.0, 16.0,
+ hour(17).getMillis()));
+ schedule2.oneHourData.put(hour(17), new AggregateNumericMetric(schedule2.id,
avg(0.092, 0.0733), 0.0733, 0.092,
+ hour(17).getMillis()));
+
+ schedule1.sixHourData.put(hour(12), new AggregateNumericMetric(schedule1.id,
+ avg(schedule1.oneHourData, hour(16), hour(17)), min(schedule1.oneHourData,
hour(16), hour(17)),
+ max(schedule1.oneHourData, hour(16), hour(17)), hour(12).getMillis()));
+ schedule2.sixHourData.put(hour(12), new AggregateNumericMetric(schedule2.id,
+ avg(schedule2.oneHourData, hour(16), hour(17)), min(schedule2.oneHourData,
hour(16), hour(17)),
+ max(schedule2.oneHourData, hour(16), hour(17)), hour(12).getMillis()));
+ schedule3.sixHourData.put(hour(12), new AggregateNumericMetric(schedule3.id,
3.14, 3.14, 3.14,
+ hour(12).getMillis()));
+
+ List<AggregateNumericMetric> expected =
asList(schedule1.oneHourData.get(hour(17)),
+ schedule2.oneHourData.get(hour(17)));
+ assertCollectionEqualsNoOrder(expected, oneHourData, "The returned one hour
data is wrong");
+ // verify values in the db
+ assert1HourDataEquals(schedule1.id, schedule1.oneHourData.get(hour(16)),
schedule1.oneHourData.get(hour(17)));
+ assert1HourDataEquals(schedule2.id, schedule2.oneHourData.get(hour(16)),
schedule2.oneHourData.get(hour(17)));
+ assert1HourDataEquals(schedule3.id, schedule3.oneHourData.get(hour(16)));
+ assert6HourDataEquals(schedule1.id, schedule1.sixHourData.get(hour(12)));
+ assert6HourDataEquals(schedule2.id, schedule2.sixHourData.get(hour(12)));
+ assert6HourDataEquals(schedule3.id, schedule3.sixHourData.get(hour(12)));
+ assert24HourDataEmpty(schedule1.id);
+ assert24HourDataEmpty(schedule2.id);
+ assert24HourDataEmpty(schedule3.id);
+ assert1HourMetricsIndexEmpty(hour(17));
+ assert6HourMetricsIndexEmpty(hour(12));
+ assert24HourIndexEquals(hour(0), schedule1.id, schedule2.id, schedule3.id);
+ }
+
+ @Test(dependsOnMethods = "runAggregationForHour17")
+ public void insertRawDataDuringHour18() throws Exception {
+ insertRawData(
+ new MeasurementDataNumeric(hour(18).plusMinutes(20).getMillis(),
schedule1.id, 22.0),
+ new MeasurementDataNumeric(hour(18).plusMinutes(40).getMillis(),
schedule1.id, 26.0),
+ new MeasurementDataNumeric(hour(18).plusMinutes(15).getMillis(),
schedule2.id, 0.205),
+ new MeasurementDataNumeric(hour(18).plusMinutes(15).getMillis(),
schedule3.id, 2.42)
+ ).await("Failed to insert raw data");
+
+ updateIndex(
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule1.id, hour(18)),
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule2.id, hour(18)),
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule3.id, hour(18))
+ ).await("Failed to update raw data index");
+ }
+
+ @Test(dependsOnMethods = "insertRawDataDuringHour18")
+ public void runAggregationForHour18() throws Exception {
+ currentHour = hour(19);
+ AggregatorTestStub aggregator = new AggregatorTestStub(hour(18));
+
+ Set<AggregateNumericMetric> oneHourData = aggregator.run();
+
+ schedule1.oneHourData.put(hour(18), new AggregateNumericMetric(schedule1.id,
avg(22.0, 26.0), 22.0, 26.0,
+ hour(18).getMillis()));
+ schedule2.oneHourData.put(hour(18), new AggregateNumericMetric(schedule2.id,
0.205, 0.205, 0.205,
+ hour(18).getMillis()));
+ schedule3.oneHourData.put(hour(18), new AggregateNumericMetric(schedule3.id,
2.42, 2.42, 2.42,
+ hour(18).getMillis()));
+
+ List<AggregateNumericMetric> expected =
asList(schedule1.oneHourData.get(hour(18)),
+ schedule2.oneHourData.get(hour(18)), schedule3.oneHourData.get(hour(18)));
+ assertCollectionEqualsNoOrder(expected, oneHourData, "The returned one hour
data is wrong");
+ // verify values in db
+ assert1HourDataEquals(schedule1.id, schedule1.oneHourData.get(hour(18)),
schedule1.oneHourData.get(hour(17)),
+ schedule1.oneHourData.get(hour(16)));
+ assert1HourDataEquals(schedule2.id, schedule2.oneHourData.get(hour(18)),
schedule2.oneHourData.get(hour(17)),
+ schedule2.oneHourData.get(hour(16)));
+ assert1HourDataEquals(schedule3.id, schedule3.oneHourData.get(hour(18)),
schedule3.oneHourData.get(hour(16)));
+ assert6HourDataEquals(schedule1.id, schedule1.sixHourData.get(hour(12)));
+ assert6HourDataEquals(schedule2.id, schedule2.sixHourData.get(hour(12)));
+ assert6HourDataEquals(schedule3.id, schedule3.sixHourData.get(hour(12)));
+ assert6HourIndexEquals(hour(18), schedule1.id, schedule2.id, schedule3.id);
+ assert24HourDataEmpty(schedule1.id);
+ assert24HourDataEmpty(schedule2.id);
+ assert24HourDataEmpty(schedule3.id);
+ assert24HourIndexEquals(hour(0), schedule1.id, schedule2.id, schedule3.id);
+ assert1HourMetricsIndexEmpty(hour(18));
+ }
+
+ @Test(dependsOnMethods = "runAggregationForHour18")
+ public void insertRawDataDuringHour23() throws Exception {
+ insertRawData(
+ new MeasurementDataNumeric(hour(23).plusMinutes(25).getMillis(),
schedule1.id, 34.0),
+ new MeasurementDataNumeric(hour(23).plusMinutes(30).getMillis(),
schedule2.id, 0.322)
+ ).await("Failed to insert raw data");
+
+ updateIndex(
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule1.id, hour(23)),
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule2.id, hour(23))
+ ).await("Failed to update raw data index");
+ }
+
+ @Test(dependsOnMethods = "insertRawDataDuringHour23")
+ public void runAggregationForHour24() throws Exception {
+ currentHour = hour(24);
+ AggregatorTestStub aggregator = new AggregatorTestStub(hour(23));
+
+ Set<AggregateNumericMetric> oneHourData = aggregator.run();
+
+ schedule1.oneHourData.put(hour(23), new AggregateNumericMetric(schedule1.id,
34.0, 34.0, 34.0,
+ hour(23).getMillis()));
+ schedule1.sixHourData.put(hour(18), new AggregateNumericMetric(schedule1.id,
+ avg(schedule1.oneHourData, hour(18), hour(23)),
+ min(schedule1.oneHourData, hour(18), hour(23)),
+ max(schedule1.oneHourData, hour(18), hour(23)),
+ hour(18).getMillis()));
+ schedule1.twentyFourHourData.put(hour(0),
+ new AggregateNumericMetric(schedule1.id,
+ avg(schedule1.sixHourData, hour(12), hour(18)),
+ min(schedule1.sixHourData, hour(12), hour(18)),
+ max(schedule1.sixHourData, hour(12), hour(18)),
+ hour(0).getMillis()));
+ schedule2.oneHourData.put(hour(23), new AggregateNumericMetric(schedule2.id,
0.322, 0.322, 0.322,
+ hour(23).getMillis()));
+ schedule2.sixHourData.put(hour(18), new AggregateNumericMetric(schedule2.id,
+ avg(schedule2.oneHourData, hour(18), hour(23)),
+ min(schedule2.oneHourData, hour(18), hour(23)),
+ max(schedule2.oneHourData, hour(18), hour(23)),
+ hour(18).getMillis()));
+ schedule2.twentyFourHourData.put(hour(0), new
AggregateNumericMetric(schedule2.id,
+ avg(schedule2.sixHourData, hour(12), hour(18)),
+ min(schedule2.sixHourData, hour(12), hour(18)),
+ max(schedule2.sixHourData, hour(12), hour(18)),
+ hour(0).getMillis()));
+ schedule3.sixHourData.put(hour(18), new AggregateNumericMetric(schedule3.id,
2.42, 2.42, 2.42,
+ hour(18).getMillis()));
+ schedule3.twentyFourHourData.put(hour(0), new
AggregateNumericMetric(schedule3.id,
+ avg(schedule3.sixHourData, hour(12), hour(18)),
+ min(schedule3.sixHourData, hour(12), hour(18)),
+ max(schedule3.sixHourData, hour(12), hour(18)),
+ hour(0).getMillis()));
+
+ List<AggregateNumericMetric> expected =
asList(schedule1.oneHourData.get(hour(23)),
+ schedule2.oneHourData.get(hour(23)));
+
+ assertCollectionEqualsNoOrder(expected, oneHourData, "The returned one hour
data is wrong");
+ // verify values in db
+ assert1HourDataEquals(schedule1.id, schedule1.oneHourData.get(hour(23)),
schedule1.oneHourData.get(hour(18)),
+ schedule1.oneHourData.get(hour(17)), schedule1.oneHourData.get(hour(16)));
+ assert1HourDataEquals(schedule2.id, schedule2.oneHourData.get(hour(23)),
schedule2.oneHourData.get(hour(18)),
+ schedule2.oneHourData.get(hour(17)), schedule2.oneHourData.get(hour(16)));
+ assert1HourDataEquals(schedule3.id, schedule3.oneHourData.get(hour(18)),
schedule3.oneHourData.get(hour(16)));
+ assert6HourDataEquals(schedule1.id, schedule1.sixHourData.get(hour(12)),
schedule1.sixHourData.get(hour(18)));
+ assert6HourDataEquals(schedule2.id, schedule2.sixHourData.get(hour(12)),
schedule2.sixHourData.get(hour(18)));
+ assert6HourDataEquals(schedule3.id, schedule3.sixHourData.get(hour(12)),
schedule3.sixHourData.get(hour(18)));
+ assert24HourDataEquals(schedule1.id, schedule1.twentyFourHourData.get(hour(0)));
+ assert24HourDataEquals(schedule2.id, schedule2.twentyFourHourData.get(hour(0)));
+ assert24HourDataEquals(schedule3.id, schedule3.twentyFourHourData.get(hour(0)));
+ assert1HourMetricsIndexEmpty(hour(23));
+ assert6HourMetricsIndexEmpty(hour(18));
+ assert24HourMetricsIndexEmpty(hour(0));
+ }
+
+ @Test(dependsOnMethods = "runAggregationForHour24")
+ public void resetDBForFailureScenarios() throws Exception {
+ purgeDB();
+ }
+
+ @Test(dependsOnMethods = "resetDBForFailureScenarios")
+ public void failToFetchRawDataIndexDuringAggregationForHour12() throws Exception {
+ currentHour = hour(12);
+ AggregatorTestStub aggregator = new AggregatorTestStub(hour(11), new
MetricsDAO(storageSession, configuration) {
+ @Override
+ public StorageResultSetFuture findMetricsIndexEntriesAsync(MetricsTable
table, long timestamp) {
+ if (table == MetricsTable.ONE_HOUR) {
+ return new FailedStorageResultSetFuture(new Exception("Failed to
fetch raw data index"));
+ } else {
+ return super.findMetricsIndexEntriesAsync(table,
+ timestamp);
+ }
+ }
+ });
+
+ insertRawData(
+ new MeasurementDataNumeric(hour(12).plusMinutes(10).getMillis(),
schedule4.id, 7.456),
+ new MeasurementDataNumeric(hour(12).plusMinutes(14).getMillis(),
schedule5.id, 29.3)
+ ).await("Failed to insert raw data");
+
+ updateIndex(
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule4.id, hour(12)),
+ new IndexUpdate(MetricsTable.ONE_HOUR, schedule5.id, hour(12))
+ ).await("Failed to update raw data index");
+
+ insert1HourData(
+ new AggregateNumericMetric(schedule4.id, 26.6, 18.33, 29.02,
hour(10).getMillis()),
+ new AggregateNumericMetric(schedule4.id, 25.2, 21.12, 28.05,
hour(11).getMillis())
+ ).await("Failed to insert 1 hour data");
+
+ updateIndex(new IndexUpdate(MetricsTable.SIX_HOUR, schedule4.id, hour(6)))
+ .await("Failed to update 1 hr data index");
+
+ schedule4.oneHourData.put(hour(10), new AggregateNumericMetric(schedule4.id,
26.6, 18.33, 29.02,
+ hour(10).getMillis()));
+ schedule4.oneHourData.put(hour(11), new AggregateNumericMetric(schedule4.id,
25.2, 21.12, 28.05,
+ hour(11).getMillis()));
+ schedule4.sixHourData.put(hour(6), new AggregateNumericMetric(schedule4.id,
+ avg(schedule4.oneHourData, hour(10), hour(11)),
+ min(schedule4.oneHourData, hour(10), hour(11)),
+ max(schedule4.oneHourData, hour(10), hour(11)),
+ hour(6).getMillis()));
+
+ Set<AggregateNumericMetric> oneHourData = aggregator.run();
+ List<AggregateNumericMetric> emptyAggregates = Collections.emptyList();
+
+ assertTrue(oneHourData.isEmpty(), "Did not expect to get back any one hour
aggregates");
+ // verify values in db
+ assert1HourDataEquals(schedule4.id, schedule4.oneHourData.get(hour(10)),
schedule4.oneHourData.get(hour(11)));
+ assert1HourDataEquals(schedule5.id, emptyAggregates);
+ assert6HourDataEquals(schedule4.id, schedule4.sixHourData.get(hour(6)));
+ assert6HourDataEmpty(schedule5.id);
+ assert24HourDataEmpty(schedule4.id);
+ assert24HourDataEmpty(schedule5.id);
+ assert1HourMetricsIndexEmpty(hour(11));
+ assert6HourMetricsIndexEmpty(hour(6));
+ assert24HourIndexEquals(hour(0), schedule4.id);
+ }
+
+ private WaitForWrite insertRawData(MeasurementDataNumeric... data) {
+ WaitForWrite waitForRawInserts = new WaitForWrite(data.length);
+ for (MeasurementDataNumeric raw : data) {
+ StorageResultSetFuture resultSetFuture = dao.insertRawData(raw);
+ Futures.addCallback(resultSetFuture, waitForRawInserts);
+ }
+ return waitForRawInserts;
+ }
+
+ private WaitForWrite insert1HourData(AggregateNumericMetric... data) {
+ WaitForWrite waitForWrite = new WaitForWrite(data.length * 3);
+ for (AggregateNumericMetric datum : data) {
+ StorageResultSetFuture future =
dao.insertOneHourDataAsync(datum.getScheduleId(), datum.getTimestamp(),
+ AggregateType.AVG, datum.getAvg());
+ Futures.addCallback(future, waitForWrite);
+
+ future = dao.insertOneHourDataAsync(datum.getScheduleId(),
datum.getTimestamp(), AggregateType.MIN,
+ datum.getMin());
+ Futures.addCallback(future, waitForWrite);
+
+ future = dao.insertOneHourDataAsync(datum.getScheduleId(),
datum.getTimestamp(), AggregateType.MAX,
+ datum.getMax());
+ Futures.addCallback(future, waitForWrite);
+ }
+ return waitForWrite;
+ }
+
+ private WaitForWrite updateIndex(IndexUpdate... updates) {
+ WaitForWrite waitForWrite = new WaitForWrite(updates.length);
+ for (IndexUpdate update : updates) {
+ StorageResultSetFuture future = dao.updateMetricsIndex(update.table,
update.scheduleId,
+ update.time.getMillis());
+ Futures.addCallback(future, waitForWrite);
+ }
+ return waitForWrite;
+ }
+
+ private double avg(Map<DateTime, AggregateNumericMetric> data, DateTime...
times) {
+ double[] values = new double[times.length];
+ for (int i = 0; i < times.length; ++i) {
+ values[i] = data.get(times[i]).getAvg();
+ }
+ return avg(values);
+ }
+
+ private double min(Map<DateTime, AggregateNumericMetric> data, DateTime...
times) {
+ double min = data.get(times[0]).getMin();
+ for (DateTime time : times) {
+ if (data.get(time).getMin() < min) {
+ min = data.get(time).getMin();
+ }
+ }
+ return min;
+ }
+
+ private double max(Map<DateTime, AggregateNumericMetric> data, DateTime...
times) {
+ double max = data.get(times[0]).getMin();
+ for (DateTime time : times) {
+ if (data.get(time).getMax() > max) {
+ max = data.get(time).getMax();
+ }
+ }
+ return max;
+ }
+
+ protected void assert6HourIndexEquals(DateTime timeSlice, int... scheduleIds) {
+ List<MetricsIndexEntry> indexEntries = new
ArrayList<MetricsIndexEntry>(scheduleIds.length);
+ for (int scheduleId : scheduleIds) {
+ indexEntries.add(new MetricsIndexEntry(MetricsTable.SIX_HOUR, timeSlice,
scheduleId));
+ }
+ assertMetricsIndexEquals(MetricsTable.SIX_HOUR, timeSlice.getMillis(),
indexEntries,
+ "The 6 hour index is wrong");
+ }
+
+ protected void assert24HourIndexEquals(DateTime timeSlice, int... scheduleIds) {
+ List<MetricsIndexEntry> indexEntries = new
ArrayList<MetricsIndexEntry>(scheduleIds.length);
+ for (int scheduleId : scheduleIds) {
+ indexEntries.add(new MetricsIndexEntry(MetricsTable.TWENTY_FOUR_HOUR,
timeSlice, scheduleId));
+ }
+ assertMetricsIndexEquals(MetricsTable.TWENTY_FOUR_HOUR, timeSlice.getMillis(),
indexEntries,
+ "The 24 hour index is wrong");
+ }
+
+ private class AggregatorTestStub extends Aggregator {
+
+ public AggregatorTestStub(DateTime startTime) {
+ super(aggregationTasks, dao, configuration, dateTimeService, startTime, 250,
writePermits, readPermits);
+ }
+
+ public AggregatorTestStub(DateTime startTime, MetricsDAO dao) {
+ super(aggregationTasks, dao, configuration, dateTimeService, startTime, 250,
writePermits, readPermits);
+ }
+
+ @Override
+ protected DateTime currentHour() {
+ return currentHour;
+ }
+ }
+
+ private class IndexUpdate {
+ MetricsTable table;
+ int scheduleId;
+ DateTime time;
+
+ public IndexUpdate(MetricsTable table, int scheduleId, DateTime time) {
+ this.table = table;
+ this.scheduleId = scheduleId;
+ this.time = time;
+ }
+ }
+
+ private class Aggregates {
+ int id; // schedule id
+ Map<DateTime, AggregateNumericMetric> oneHourData = new
HashMap<DateTime, AggregateNumericMetric>();
+ Map<DateTime, AggregateNumericMetric> sixHourData = new
HashMap<DateTime, AggregateNumericMetric>();
+ Map<DateTime, AggregateNumericMetric> twentyFourHourData = new
HashMap<DateTime, AggregateNumericMetric>();
+ }
+
+ private class FailedStorageResultSetFuture extends StorageResultSetFuture implements
ListenableFuture<ResultSet> {
+
+ private SettableFuture future;
+
+ private Throwable t;
+
+ public FailedStorageResultSetFuture(Throwable t) {
+ super(null, null);
+ future = SettableFuture.create();
+ this.t = t;
+ assertTrue(future.setException(t), "Failed to set exception for
future");
+ }
+
+ @Override
+ public void addListener(Runnable listener, Executor executor) {
+ future.addListener(listener, executor);
+ }
+
+ @Override
+ public ResultSet get() {
+ throw new AssertionError();
+ }
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/CassandraIntegrationTest.java
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/CassandraIntegrationTest.java
index f7125e5..4d48cbb 100644
---
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/CassandraIntegrationTest.java
+++
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/CassandraIntegrationTest.java
@@ -28,6 +28,8 @@ import java.util.concurrent.CountDownLatch;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Host;
+import com.datastax.driver.core.HostDistance;
+import com.datastax.driver.core.PoolingOptions;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Session;
@@ -79,6 +81,12 @@ public class CassandraIntegrationTest {
.withCredentialsObfuscated(RHQADMIN, RHQADMIN_PASSWORD)
.build();
+ PoolingOptions poolingOptions = cluster.getConfiguration().getPoolingOptions();
+ poolingOptions.setCoreConnectionsPerHost(HostDistance.LOCAL, 24);
+ poolingOptions.setCoreConnectionsPerHost(HostDistance.REMOTE, 24);
+ poolingOptions.setMaxConnectionsPerHost(HostDistance.LOCAL, 32);
+ poolingOptions.setMaxConnectionsPerHost(HostDistance.REMOTE, 32);
+
cluster.register(new Host.StateListener() {
@Override
public void onAdd(Host host) {
@@ -145,39 +153,6 @@ public class CassandraIntegrationTest {
}
}
- protected static class WaitForWrite implements FutureCallback<ResultSet> {
-
- private final Log log = LogFactory.getLog(WaitForWrite.class);
-
- private CountDownLatch latch;
-
- private Throwable throwable;
-
- public WaitForWrite(int numResults) {
- latch = new CountDownLatch(numResults);
- }
-
- @Override
- public void onSuccess(ResultSet rows) {
- latch.countDown();
- }
-
- @Override
- public void onFailure(Throwable throwable) {
- latch.countDown();
- this.throwable = throwable;
- log.error("An async operation failed", throwable);
- }
-
- public void await(String errorMsg) throws InterruptedException {
- latch.await();
- if (throwable != null) {
- fail(errorMsg, Throwables.getRootCause(throwable));
- }
- }
-
- }
-
protected static class WaitForRead<T> implements
FutureCallback<ResultSet> {
private final Log log = LogFactory.getLog(WaitForRead.class);
diff --git
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsDAOTest.java
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsDAOTest.java
index b06dfda..fff0485 100644
---
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsDAOTest.java
+++
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsDAOTest.java
@@ -29,6 +29,7 @@ import static java.util.Arrays.asList;
import static org.rhq.test.AssertUtils.assertCollectionMatchesNoOrder;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
import java.util.ArrayList;
import java.util.HashMap;
@@ -38,7 +39,9 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
+import com.datastax.driver.core.ResultSet;
import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import org.apache.commons.logging.Log;
@@ -54,6 +57,7 @@ import org.rhq.server.metrics.domain.AggregateNumericMetric;
import org.rhq.server.metrics.domain.AggregateSimpleNumericMetric;
import org.rhq.server.metrics.domain.AggregateType;
import org.rhq.server.metrics.domain.MetricsIndexEntry;
+import org.rhq.server.metrics.domain.MetricsIndexEntryMapper;
import org.rhq.server.metrics.domain.MetricsTable;
import org.rhq.server.metrics.domain.RawNumericMetric;
import org.rhq.server.metrics.domain.RawNumericMetricMapper;
@@ -352,12 +356,24 @@ public class MetricsDAOTest extends CassandraIntegrationTest {
updates.put(scheduleId2, hour0.getMillis());
dao.updateMetricsIndex(MetricsTable.ONE_HOUR, updates);
- List<MetricsIndexEntry> actual =
Lists.newArrayList(dao.findMetricsIndexEntries(MetricsTable.ONE_HOUR,
- hour0.getMillis()));
-
- List<MetricsIndexEntry> expected = asList(new
MetricsIndexEntry(MetricsTable.ONE_HOUR, hour0, scheduleId1),
+ final List<MetricsIndexEntry> expected = asList(new
MetricsIndexEntry(MetricsTable.ONE_HOUR, hour0, scheduleId1),
new MetricsIndexEntry(MetricsTable.ONE_HOUR, hour0, scheduleId2));
- assertCollectionMatchesNoOrder(expected, actual, "Failed to update or
retrieve metrics index entries");
+
+ StorageResultSetFuture future =
dao.findMetricsIndexEntriesAsync(MetricsTable.ONE_HOUR, hour0.getMillis());
+ Futures.addCallback(future, new FutureCallback<ResultSet>() {
+ @Override
+ public void onSuccess(ResultSet result) {
+ MetricsIndexEntryMapper mapper = new
MetricsIndexEntryMapper(MetricsTable.ONE_HOUR);
+ List<MetricsIndexEntry> actual = mapper.mapAll(result);
+
+ assertCollectionMatchesNoOrder(expected, actual, "Failed to update
or retrieve metrics index entries");
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ fail("Failed to retrieve one hour index entries", t);
+ }
+ });
}
@Test(enabled = ENABLED)
diff --git
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsPerfTests.java
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsPerfTests.java
new file mode 100644
index 0000000..6e93fec
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsPerfTests.java
@@ -0,0 +1,191 @@
+package org.rhq.server.metrics;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+import com.datastax.driver.core.ResultSet;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.RateLimiter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.DateTime;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.rhq.core.domain.measurement.MeasurementDataNumeric;
+import org.rhq.server.metrics.domain.AggregateNumericMetric;
+import org.rhq.server.metrics.domain.RawNumericMetric;
+import org.rhq.server.metrics.domain.RawNumericMetricMapper;
+
+/**
+ * @author John Sanda
+ */
+public class MetricsPerfTests extends MetricsTest {
+
+ private class MetricsServerStub extends MetricsServer {
+
+ DateTime currentHour;
+
+ @Override
+ public DateTime currentHour() {
+ return currentHour;
+ }
+
+ public void setCurrentHour(DateTime currentHour) {
+ this.currentHour = currentHour;
+ }
+ }
+
+ private class DateTimeServiceStub extends DateTimeService {
+
+ DateTime currentHour;
+
+ long startTime;
+
+ public DateTimeServiceStub(DateTime currentHour, long startTime) {
+ this.currentHour = currentHour;
+ this.startTime = startTime;
+ }
+
+ @Override
+ public DateTime now() {
+ return currentHour.plus(System.currentTimeMillis() - startTime);
+ }
+
+ @Override
+ public long nowInMillis() {
+ return now().getMillis();
+ }
+ }
+
+ private final Log log = LogFactory.getLog(MetricsPerfTests.class);
+
+ private MetricsServerStub metricsServer;
+
+ private final int NUM_SCHEDULES = 1000;
+
+ private RateLimiter writePermits;
+ private RateLimiter readPermits;
+
+ @BeforeClass
+ public void setupClass() throws Exception {
+ purgeDB();
+ log.info("Sleeping while table truncation completes...");
+ Thread.sleep(3000);
+ metricsServer = new MetricsServerStub();
+ metricsServer.setConfiguration(configuration);
+ metricsServer.setDAO(dao);
+ metricsServer.setDateTimeService(dateTimeService);
+ writePermits = metricsServer.getWritePermits();
+ readPermits = metricsServer.getReadPermits();
+ }
+
+ private void resetRateLimits() {
+ metricsServer.setWritePermits(writePermits);
+ metricsServer.setReadPermits(readPermits);
+ }
+
+ @Test
+ public void insertRawData() throws Exception {
+ Random random = new Random();
+ DateTime currentHour = hour(3);
+ metricsServer.setWritePermits(RateLimiter.create(3500));
+ metricsServer.setCurrentHour(currentHour);
+ Set<MeasurementDataNumeric> data = new
HashSet<MeasurementDataNumeric>();
+ for (int i = 0; i < NUM_SCHEDULES; ++i) {
+ DateTime time = currentHour;
+ for (int j = 0; j < 120; ++j) {
+ data.add(new MeasurementDataNumeric(time.getMillis(), i,
random.nextDouble()));
+ time = time.plusSeconds(30);
+ }
+ }
+ WaitForRawInserts waitForRawInserts = new WaitForRawInserts(data.size());
+ metricsServer.addNumericData(data, waitForRawInserts);
+ waitForRawInserts.await("Failed to add raw data");
+ }
+
+ //@Test(dependsOnMethods = "insertRawData")
+ public void queryRawDataAsync() throws Exception {
+ RateLimiter readPermits = RateLimiter.create(50);
+
+ log.info("Running queryRawDataAsync");
+ long start = System.currentTimeMillis();
+
+ DateTime startTime = hour(3).minusHours(1).minusSeconds(1);
+ DateTime endTime = hour(3);
+ final CountDownLatch rawDataArrival = new CountDownLatch(100);
+ final RawNumericMetricMapper mapper = new RawNumericMetricMapper();
+ final Map<Integer, List<RawNumericMetric>> rawDataMap =
+ new ConcurrentHashMap<Integer, List<RawNumericMetric>>(100);
+
+ for (int i = 0; i < NUM_SCHEDULES; ++i) {
+ final int scheduleId = i;
+// readPermits.acquire();
+ StorageResultSetFuture rawDataFuture = dao.findRawMetricsAsync(scheduleId,
startTime.getMillis(),
+ endTime.getMillis());
+ Futures.addCallback(rawDataFuture, new FutureCallback<ResultSet>() {
+ @Override
+ public void onSuccess(ResultSet result) {
+ List<RawNumericMetric> rawData = mapper.mapAll(result);
+ rawDataMap.put(scheduleId, rawData);
+ rawDataArrival.countDown();
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.warn("Failed to retrieve raw data for schedule id " +
scheduleId, t);
+ }
+ });
+ }
+
+ rawDataArrival.await();
+ log.info("Finished raw data aysnc query in " +
(System.currentTimeMillis() - start) + " ms");
+ }
+
+ //@Test(dependsOnMethods = "insertRawData")
+ public void queryDataSync() throws Exception {
+ log.info("Running queryDataSync");
+
+ long start = System.currentTimeMillis();
+ DateTime startTime = hour(3).minusHours(1).minusSeconds(1);
+ DateTime endTime = hour(3);
+ RawNumericMetricMapper mapper = new RawNumericMetricMapper();
+ Map<Integer, List<RawNumericMetric>> rawDataMp = new
HashMap<Integer, List<RawNumericMetric>>(100);
+
+ for (int i = 0; i < NUM_SCHEDULES; ++i) {
+ ResultSet resultSet = dao.findRawMetricsSync(i, startTime.getMillis(),
endTime.getMillis());
+ rawDataMp.put(i, mapper.mapAll(resultSet));
+ }
+
+ log.info("Finished raw data sync query in " +
(System.currentTimeMillis() - start) + " ms");
+ }
+
+ @Test(dependsOnMethods = "insertRawData")
+ public void runAggregation() {
+ log.info("Running aggregation");
+
+ resetRateLimits();
+
+ long start = System.currentTimeMillis();
+ DateTime currentHour = hour(4);
+ metricsServer.setCurrentHour(currentHour);
+ metricsServer.setAggregationBatchSize(250);
+ metricsServer.setUseAsyncAggregation(false);
+ metricsServer.setDateTimeService(new DateTimeServiceStub(hour(4), start));
+ Collection<AggregateNumericMetric> oneHourData =
+ (Collection<AggregateNumericMetric>)
metricsServer.calculateAggregates();
+
+ log.info("Finished computing " + oneHourData.size() + " one hour
aggregates in " +
+ (System.currentTimeMillis() - start) + " ms");
+ }
+
+}
diff --git
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsServerTest.java
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsServerTest.java
index 95ada4c..b3ffb66 100644
---
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsServerTest.java
+++
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsServerTest.java
@@ -31,7 +31,6 @@ import static org.rhq.test.AssertUtils.assertCollectionMatchesNoOrder;
import static org.rhq.test.AssertUtils.assertPropertiesMatch;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
import java.math.BigDecimal;
import java.math.MathContext;
@@ -40,10 +39,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
-import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
@@ -1011,39 +1008,4 @@ public class MetricsServerTest extends CassandraIntegrationTest {
return new SimplePagedResult<RawNumericMetric>(cql, new
RawNumericMetricMapper(true), storageSession);
}
- private static class WaitForRawInserts implements RawDataInsertedCallback {
-
- private final Log log = LogFactory.getLog(WaitForRawInserts.class);
-
- private CountDownLatch latch;
-
- private Throwable throwable;
-
- public WaitForRawInserts(int numInserts) {
- latch = new CountDownLatch(numInserts);
- }
-
- @Override
- public void onFinish() {
- }
-
- @Override
- public void onSuccess(MeasurementDataNumeric measurementDataNumeric) {
- latch.countDown();
- }
-
- @Override
- public void onFailure(Throwable throwable) {
- latch.countDown();
- this.throwable = throwable;
- log.error("An async operation failed", throwable);
- }
-
- public void await(String errorMsg) throws InterruptedException {
- latch.await();
- if (throwable != null) {
- fail(errorMsg, Throwables.getRootCause(throwable));
- }
- }
- }
}
diff --git
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsTest.java
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsTest.java
new file mode 100644
index 0000000..59e0b77
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/MetricsTest.java
@@ -0,0 +1,138 @@
+package org.rhq.server.metrics;
+
+import static java.util.Arrays.asList;
+import static org.rhq.test.AssertUtils.assertCollectionMatchesNoOrder;
+import static org.testng.Assert.assertEquals;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+import org.joda.time.DateTime;
+import org.testng.annotations.BeforeClass;
+
+import org.rhq.server.metrics.domain.AggregateNumericMetric;
+import org.rhq.server.metrics.domain.MetricsIndexEntry;
+import org.rhq.server.metrics.domain.MetricsTable;
+
+/**
+ * @author John Sanda
+ */
+public class MetricsTest extends CassandraIntegrationTest {
+
+ private static final double TEST_PRECISION = Math.pow(10, -9);
+
+ protected MetricsDAO dao;
+ protected MetricsConfiguration configuration = new MetricsConfiguration();
+ protected DateTimeService dateTimeService;
+
+ @BeforeClass
+ public void initClass() throws Exception {
+ dao = new MetricsDAO(storageSession, configuration);
+ dateTimeService = new DateTimeService();
+ dateTimeService.setConfiguration(configuration);
+ }
+
+ protected DateTime hour(int hourOfDay) {
+ return hour0().plusHours(hourOfDay);
+ }
+
+ protected double avg(double... values) {
+ double sum = 0;
+ for (double value : values) {
+ sum += value;
+ }
+ return divide(sum, values.length);
+ }
+
+ protected double divide(double dividend, int divisor) {
+ return new BigDecimal(Double.toString(dividend)).divide(new
BigDecimal(Integer.toString(divisor)),
+ MathContext.DECIMAL64).doubleValue();
+ }
+
+ protected void purgeDB() {
+ session.execute("TRUNCATE " + MetricsTable.RAW);
+ session.execute("TRUNCATE " + MetricsTable.ONE_HOUR);
+ session.execute("TRUNCATE " + MetricsTable.SIX_HOUR);
+ session.execute("TRUNCATE " + MetricsTable.TWENTY_FOUR_HOUR);
+ session.execute("TRUNCATE " + MetricsTable.INDEX);
+ }
+
+ protected void assert1HourDataEquals(int scheduleId, AggregateNumericMetric...
expected) {
+ assert1HourDataEquals(scheduleId, asList(expected));
+ }
+
+ protected void assert1HourDataEquals(int scheduleId,
Collection<AggregateNumericMetric> expected) {
+ assert1HourDataEquals(scheduleId, new
ArrayList<AggregateNumericMetric>(expected));
+ }
+
+ protected void assert1HourDataEquals(int scheduleId,
List<AggregateNumericMetric> expected) {
+ assertMetricDataEquals(MetricsTable.ONE_HOUR, scheduleId, expected);
+ }
+
+ protected void assert6HourDataEquals(int scheduleId, AggregateNumericMetric...
expected) {
+ assert6HourDataEquals(scheduleId, asList(expected));
+ }
+
+ protected void assert6HourDataEquals(int scheduleId,
List<AggregateNumericMetric> expected) {
+ assertMetricDataEquals(MetricsTable.SIX_HOUR, scheduleId, expected);
+ }
+
+ protected void assert24HourDataEquals(int scheduleId,
List<AggregateNumericMetric> expected) {
+ assertMetricDataEquals(MetricsTable.TWENTY_FOUR_HOUR, scheduleId, expected);
+ }
+
+ protected void assert24HourDataEquals(int scheduleId, AggregateNumericMetric...
expected) {
+ assertMetricDataEquals(MetricsTable.TWENTY_FOUR_HOUR, scheduleId,
asList(expected));
+ }
+
+ private void assertMetricDataEquals(MetricsTable columnFamily, int scheduleId,
+ List<AggregateNumericMetric> expected) {
+ List<AggregateNumericMetric> actual =
Lists.newArrayList(findAggregateMetrics(columnFamily, scheduleId));
+ assertCollectionMatchesNoOrder("Metric data for schedule id " +
scheduleId + " in table " + columnFamily +
+ " does not match expected values", expected, actual,
TEST_PRECISION);
+ }
+
+ protected void assertMetricsIndexEquals(MetricsTable table, long timeSlice,
List<MetricsIndexEntry> expected,
+ String msg) {
+ List<MetricsIndexEntry> actual =
Lists.newArrayList(dao.findMetricsIndexEntries(table, timeSlice));
+ assertCollectionMatchesNoOrder(msg + ": " + table + " index does
not match expected values.",
+ expected, actual);
+ }
+
+ protected void assert6HourDataEmpty(int scheduleId) {
+ assertMetricDataEmpty(scheduleId, MetricsTable.SIX_HOUR);
+ }
+
+ protected void assert24HourDataEmpty(int scheduleId) {
+ assertMetricDataEmpty(scheduleId, MetricsTable.TWENTY_FOUR_HOUR);
+ }
+
+ private void assertMetricDataEmpty(int scheduleId, MetricsTable columnFamily) {
+ List<AggregateNumericMetric> metrics =
Lists.newArrayList(findAggregateMetrics(columnFamily, scheduleId));
+ assertEquals(metrics.size(), 0, "Expected " + columnFamily + " to
be empty for schedule id " + scheduleId +
+ " but found " + metrics);
+ }
+
+ protected void assert1HourMetricsIndexEmpty(DateTime timeSlice) {
+ assertMetricsIndexEmpty(MetricsTable.ONE_HOUR, timeSlice);
+ }
+
+ protected void assert6HourMetricsIndexEmpty(DateTime timeSlice) {
+ assertMetricsIndexEmpty(MetricsTable.SIX_HOUR, timeSlice);
+ }
+
+ protected void assert24HourMetricsIndexEmpty(DateTime timeSlice) {
+ assertMetricsIndexEmpty(MetricsTable.TWENTY_FOUR_HOUR, timeSlice);
+ }
+
+ private void assertMetricsIndexEmpty(MetricsTable table, DateTime timeSlice) {
+ List<MetricsIndexEntry> index =
Lists.newArrayList(dao.findMetricsIndexEntries(table, timeSlice.getMillis()));
+ assertEquals(index.size(), 0, "Expected metrics index for " + table +
" to be empty but found " + index);
+ }
+
+}
diff --git
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/WaitForRawInserts.java
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/WaitForRawInserts.java
new file mode 100644
index 0000000..5feffda
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/WaitForRawInserts.java
@@ -0,0 +1,51 @@
+package org.rhq.server.metrics;
+
+import static org.testng.Assert.fail;
+
+import java.util.concurrent.CountDownLatch;
+
+import com.google.common.base.Throwables;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.core.domain.measurement.MeasurementDataNumeric;
+
+/**
+* @author John Sanda
+*/
+class WaitForRawInserts implements RawDataInsertedCallback {
+
+ private final Log log = LogFactory.getLog(WaitForRawInserts.class);
+
+ private CountDownLatch latch;
+
+ private Throwable throwable;
+
+ public WaitForRawInserts(int numInserts) {
+ latch = new CountDownLatch(numInserts);
+ }
+
+ @Override
+ public void onFinish() {
+ }
+
+ @Override
+ public void onSuccess(MeasurementDataNumeric measurementDataNumeric) {
+ latch.countDown();
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ latch.countDown();
+ this.throwable = throwable;
+ log.error("An async operation failed", throwable);
+ }
+
+ public void await(String errorMsg) throws InterruptedException {
+ latch.await();
+ if (throwable != null) {
+ fail(errorMsg, Throwables.getRootCause(throwable));
+ }
+ }
+}
diff --git
a/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/WaitForWrite.java
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/WaitForWrite.java
new file mode 100644
index 0000000..b67c72d
--- /dev/null
+++
b/modules/enterprise/server/server-metrics/src/test/java/org/rhq/server/metrics/WaitForWrite.java
@@ -0,0 +1,48 @@
+package org.rhq.server.metrics;
+
+import static org.testng.Assert.fail;
+
+import java.util.concurrent.CountDownLatch;
+
+import com.datastax.driver.core.ResultSet;
+import com.google.common.base.Throwables;
+import com.google.common.util.concurrent.FutureCallback;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+* @author John Sanda
+*/
+class WaitForWrite implements FutureCallback<ResultSet> {
+
+ private final Log log = LogFactory.getLog(WaitForWrite.class);
+
+ private CountDownLatch latch;
+
+ private Throwable throwable;
+
+ public WaitForWrite(int numResults) {
+ latch = new CountDownLatch(numResults);
+ }
+
+ @Override
+ public void onSuccess(ResultSet rows) {
+ latch.countDown();
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ latch.countDown();
+ this.throwable = throwable;
+ log.error("An async operation failed", throwable);
+ }
+
+ public void await(String errorMsg) throws InterruptedException {
+ latch.await();
+ if (throwable != null) {
+ fail(errorMsg, Throwables.getRootCause(throwable));
+ }
+ }
+
+}
diff --git a/modules/enterprise/server/server-metrics/src/test/resources/log4j.xml
b/modules/enterprise/server/server-metrics/src/test/resources/log4j.xml
index d93f284..4ce4d9e 100644
--- a/modules/enterprise/server/server-metrics/src/test/resources/log4j.xml
+++ b/modules/enterprise/server/server-metrics/src/test/resources/log4j.xml
@@ -8,7 +8,7 @@
<appender name="CONSOLE"
class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
- <param name="Threshold" value="WARN" />
+ <param name="Threshold" value="DEBUG" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{dd-MM
HH:mm:ss,SSS} (%F:%M:%L) - %m%n" />
</layout>
diff --git
a/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/MeasurementAggregator.java
b/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/MeasurementAggregator.java
index 7a7c6b9..b5f61f3 100644
---
a/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/MeasurementAggregator.java
+++
b/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/MeasurementAggregator.java
@@ -49,12 +49,15 @@ public class MeasurementAggregator implements Runnable {
private ShutdownManager shutdownManager;
+ private int numSchedules;
+
public MeasurementAggregator(MetricsServer metricsServer, ShutdownManager
shutdownManager, Metrics metrics,
- ExecutorService aggregationQueue) {
+ ExecutorService aggregationQueue, int numSchedules) {
this.metricsServer = metricsServer;
this.shutdownManager = shutdownManager;
this.metrics = metrics;
this.aggregationQueue = aggregationQueue;
+ this.numSchedules = numSchedules;
}
public void run() {
@@ -62,6 +65,7 @@ public class MeasurementAggregator implements Runnable {
@Override
public void run() {
Timer.Context context = metrics.totalAggregationTime.time();
+ long start = System.currentTimeMillis();
try {
log.debug("Starting metrics aggregation");
metricsServer.calculateAggregates();
@@ -71,6 +75,7 @@ public class MeasurementAggregator implements Runnable {
shutdownManager.shutdown(1);
} finally {
context.stop();
+ log.debug("Finished metrics aggregation in " +
(System.currentTimeMillis() - start) + " ms");
metrics.totalAggregationRuns.inc();
}
}
diff --git
a/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/Simulator.java
b/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/Simulator.java
index 63bdbea..3e9b4af 100644
---
a/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/Simulator.java
+++
b/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/Simulator.java
@@ -31,6 +31,8 @@ import java.util.concurrent.TimeUnit;
import com.codahale.metrics.ConsoleReporter;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Host;
+import com.datastax.driver.core.HostDistance;
+import com.datastax.driver.core.PoolingOptions;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.exceptions.NoHostAvailableException;
@@ -65,31 +67,39 @@ public class Simulator implements ShutdownManager {
Metrics metrics = new Metrics();
final ConsoleReporter consoleReporter = createConsoleReporter(metrics,
plan.getMetricsReportInterval());
- Runtime.getRuntime().addShutdownHook(new Thread() {
- @Override
- public void run() {
- shutdown(collectors, "collectors", 5);
- shutdown(readers, "readers", 5);
- shutdown(aggregators, "aggregators", 1);
- shutdown(aggregationQueue, "aggregationQueue",
Integer.MAX_VALUE);
- consoleReporter.stop();
- }
- });
-
createSchema(plan.getNodes(), plan.getCqlPort());
Session session = createSession(plan.getNodes(), plan.getCqlPort());
StorageSession storageSession = new StorageSession(session);
MetricsDAO metricsDAO = new MetricsDAO(storageSession,
plan.getMetricsServerConfiguration());
- MetricsServer metricsServer = new MetricsServer();
+ final MetricsServer metricsServer = new MetricsServer();
metricsServer.setDAO(metricsDAO);
metricsServer.setConfiguration(plan.getMetricsServerConfiguration());
+ metricsServer.setAggregationBatchSize(plan.getAggregationBatchSize());
+ metricsServer.setUseAsyncAggregation(plan.getAggregationType() ==
SimulationPlan.AggregationType.ASYNC);
metricsServer.setDateTimeService(plan.getDateTimeService());
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ shutdown(collectors, "collectors", 5);
+ shutdown(readers, "readers", 5);
+ shutdown(aggregators, "aggregators", 1);
+ shutdown(aggregationQueue, "aggregationQueue",
Integer.MAX_VALUE);
+ metricsServer.shutdown();
+ log.info("Wait for console reporter...");
+ try {
+ Thread.sleep(181000);
+ } catch (InterruptedException e) {
+ }
+ consoleReporter.stop();
+ }
+ });
+
MeasurementAggregator measurementAggregator = new
MeasurementAggregator(metricsServer, this, metrics,
- aggregationQueue);
+ aggregationQueue, plan.getNumMeasurementCollectors() * plan.getBatchSize());
for (int i = 0; i < plan.getNumMeasurementCollectors(); ++i) {
collectors.scheduleAtFixedRate(new MeasurementCollector(plan.getBatchSize(),
@@ -169,6 +179,11 @@ public class Simulator implements ShutdownManager {
Cluster cluster = new
ClusterBuilder().addContactPoints(nodes).withPort(cqlPort)
.withCredentials("rhqadmin", "rhqadmin")
.build();
+ PoolingOptions poolingOptions =
cluster.getConfiguration().getPoolingOptions();
+ poolingOptions.setCoreConnectionsPerHost(HostDistance.LOCAL, 24);
+ poolingOptions.setCoreConnectionsPerHost(HostDistance.REMOTE, 24);
+ poolingOptions.setMaxConnectionsPerHost(HostDistance.LOCAL, 32);
+ poolingOptions.setMaxConnectionsPerHost(HostDistance.REMOTE, 32);
log.debug("Created cluster object with " +
cluster.getConfiguration().getProtocolOptions().getCompression()
+ " compression.");
diff --git
a/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlan.java
b/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlan.java
index 33b3bbf..7ad50d1 100644
---
a/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlan.java
+++
b/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlan.java
@@ -56,6 +56,26 @@ public class SimulationPlan {
}
}
+ public static enum AggregationType {
+ SYNC("sync"), ASYNC("async");
+
+ private final String text;
+
+ AggregationType(String text) {
+ this.text = text;
+ }
+
+ public static AggregationType fromText(String text) {
+ if (text.equals("sync")) {
+ return SYNC;
+ }
+ if (text.equals("async")) {
+ return ASYNC;
+ }
+ throw new IllegalArgumentException(text + " is not a valid aggregation
type");
+ }
+ }
+
private long collectionInterval;
private long aggregationInterval;
@@ -84,6 +104,10 @@ public class SimulationPlan {
private long simulationRate;
+ private int aggregationBatchSize;
+
+ private AggregationType aggregationType;
+
public DateTimeService getDateTimeService() {
return dateTimeService;
}
@@ -195,4 +219,20 @@ public class SimulationPlan {
public void setSimulationRate(long simulationRate) {
this.simulationRate = simulationRate;
}
+
+ public int getAggregationBatchSize() {
+ return aggregationBatchSize;
+ }
+
+ public void setAggregationBatchSize(int aggregationBatchSize) {
+ this.aggregationBatchSize = aggregationBatchSize;
+ }
+
+ public AggregationType getAggregationType() {
+ return aggregationType;
+ }
+
+ public void setAggregationType(AggregationType aggregationType) {
+ this.aggregationType = aggregationType;
+ }
}
diff --git
a/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlanner.java
b/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlanner.java
index e601212..ff1d83f 100644
---
a/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlanner.java
+++
b/modules/helpers/metrics-simulator/src/main/java/org/rhq/metrics/simulator/plan/SimulationPlanner.java
@@ -98,6 +98,9 @@ public class SimulationPlanner {
simulation.setNodes(nodes);
simulation.setCqlPort(getInt(root.get("cqlPort"), 9142));
+
simulation.setAggregationBatchSize(getInt(root.get("aggregationBatchSize"),
250));
+
simulation.setAggregationType(SimulationPlan.AggregationType.fromText(getString(root.get("aggregationType"),
+ "sync")));
return simulation;
}
commit c400fed353c5824d3ea3c40a47f05cd9f69d3af0
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Mon Dec 16 19:23:37 2013 +0100
[BZ 970181] - RHQ doesn't work after restart with open GUI in web browser. - if
the server restarts at the background, the session id is lost on the server therefore we
can't allow the logged user to continue sending the requests without a new AuthN. It
would be a security risk to allow it. Now, if the server restarts the UI requires the new
log in (the login form is displayed).
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/util/rpc/TrackingRequestCallback.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/util/rpc/TrackingRequestCallback.java
index 07893f6..b443c1a 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/util/rpc/TrackingRequestCallback.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/util/rpc/TrackingRequestCallback.java
@@ -23,6 +23,7 @@ import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.Response;
import org.rhq.coregui.client.CoreGUI;
+import org.rhq.coregui.client.LoginView;
import org.rhq.coregui.client.UserSessionManager;
import org.rhq.coregui.client.util.Log;
@@ -86,6 +87,11 @@ public class TrackingRequestCallback implements RequestCallback {
switch (statusCode) {
case STATUS_CODE_OK:
+ if (response != null && response.getText() != null &&
response.getText().isEmpty()
+ && !LoginView.isLoginShowing()) { // this happen when the RHQ
server was restarted
+ new LoginView().showLoginDialog();
+ break;
+ }
RPCTracker.getInstance().succeedCall(this);
callback.onResponseReceived(request, response);
break;
commit 27668cb9cfce7eeec83967978f11435c69c86918
Author: Mike Thompson <mithomps(a)redhat.com>
Date: Fri Dec 13 15:51:56 2013 -0800
[BZ 1034512] Update Group Metric Graphs to be more like new Resource Metrics Graphs
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/D3GroupGraphListView.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/D3GroupGraphListView.java
index d0b56a7..f6805e2 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/D3GroupGraphListView.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/D3GroupGraphListView.java
@@ -189,6 +189,7 @@ public final class D3GroupGraphListView extends
AbstractD3GraphListView implemen
private void buildIndividualGraph(MeasurementDefinition measurementDefinition,
List<MeasurementDataNumericHighLowComposite> data) {
+ Log.debug("\n***** D3GroupGraphListView.MD: "+measurementDefinition);
MetricGraphData metricGraphData =
MetricGraphData.createForResourceGroup(resourceGroup.getId(),
resourceGroup.getName(), measurementDefinition, data);
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java
index 9ddbb77..8394217 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java
@@ -63,6 +63,7 @@ import
org.rhq.coregui.client.inventory.groups.detail.configuration.HistoryGroup
import
org.rhq.coregui.client.inventory.groups.detail.inventory.GroupPluginConfigurationEditView;
import
org.rhq.coregui.client.inventory.groups.detail.inventory.HistoryGroupPluginConfigurationView;
import org.rhq.coregui.client.inventory.groups.detail.inventory.MembersView;
+import
org.rhq.coregui.client.inventory.groups.detail.monitoring.metric.MetricsGroupView;
import
org.rhq.coregui.client.inventory.groups.detail.monitoring.schedules.ResourceGroupSchedulesView;
import
org.rhq.coregui.client.inventory.groups.detail.monitoring.table.GroupMonitoringTablesView;
import org.rhq.coregui.client.inventory.groups.detail.monitoring.traits.TraitsView;
@@ -332,7 +333,7 @@ public class ResourceGroupDetailView extends
viewFactory = (!showOnPage) ? null : new ViewFactory() {
@Override
public Canvas createView() {
- return createD3GraphListView();
+ return MetricsGroupView.create(groupComposite.getResourceGroup());
}
};
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupTableView.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupTableView.java
new file mode 100644
index 0000000..89d4f67
--- /dev/null
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupTableView.java
@@ -0,0 +1,408 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.coregui.client.inventory.groups.detail.monitoring.metric;
+
+import static
org.rhq.coregui.client.inventory.resource.detail.monitoring.table.MetricsGridFieldName.METRIC_DEF_ID;
+import static
org.rhq.coregui.client.inventory.resource.detail.monitoring.table.MetricsGridFieldName.RESOURCE_GROUP_ID;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.types.ExpansionMode;
+import com.smartgwt.client.types.SelectionStyle;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.HTMLFlow;
+import com.smartgwt.client.widgets.IButton;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.form.fields.SelectItem;
+import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.grid.events.DataArrivedEvent;
+import com.smartgwt.client.widgets.grid.events.DataArrivedHandler;
+import com.smartgwt.client.widgets.grid.events.RecordCollapseEvent;
+import com.smartgwt.client.widgets.grid.events.RecordCollapseHandler;
+import com.smartgwt.client.widgets.grid.events.RecordExpandEvent;
+import com.smartgwt.client.widgets.grid.events.RecordExpandHandler;
+import com.smartgwt.client.widgets.grid.events.SelectionChangedHandler;
+import com.smartgwt.client.widgets.grid.events.SelectionEvent;
+import com.smartgwt.client.widgets.grid.events.SortChangedHandler;
+import com.smartgwt.client.widgets.grid.events.SortEvent;
+import com.smartgwt.client.widgets.layout.VLayout;
+import com.smartgwt.client.widgets.toolbar.ToolStrip;
+
+import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.domain.criteria.DashboardCriteria;
+import org.rhq.core.domain.dashboard.Dashboard;
+import org.rhq.core.domain.dashboard.DashboardPortlet;
+import org.rhq.core.domain.measurement.MeasurementDefinition;
+import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
+import org.rhq.core.domain.resource.group.GroupCategory;
+import org.rhq.core.domain.resource.group.ResourceGroup;
+import org.rhq.core.domain.util.PageList;
+import org.rhq.coregui.client.CoreGUI;
+import org.rhq.coregui.client.components.table.Table;
+import
org.rhq.coregui.client.dashboard.portlets.inventory.groups.graph.ResourceGroupD3GraphPortlet;
+import org.rhq.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.coregui.client.inventory.common.AbstractD3GraphListView;
+import org.rhq.coregui.client.inventory.common.graph.CustomDateRangeState;
+import org.rhq.coregui.client.inventory.common.graph.MetricGraphData;
+import org.rhq.coregui.client.inventory.common.graph.Refreshable;
+import
org.rhq.coregui.client.inventory.common.graph.graphtype.StackedBarMetricGraphImpl;
+import org.rhq.coregui.client.inventory.resource.detail.monitoring.MetricD3Graph;
+import org.rhq.coregui.client.util.BrowserUtility;
+import org.rhq.coregui.client.util.Log;
+import org.rhq.coregui.client.util.message.Message;
+
+/**
+ * Views a resource's metrics in a tabular view with sparkline graph and optional
detailed d3 graph.
+ *
+ * @author John Mazzitelli
+ * @author Mike Thompson
+ */
+public class MetricsGroupTableView extends Table<MetricsGroupViewDataSource>
implements Refreshable {
+
+ private final ResourceGroup resourceGroup;
+ private final AbstractD3GraphListView abstractD3GraphListView;
+ private ToolStrip toolStrip;
+ private SelectItem dashboardSelectItem;
+ private Dashboard selectedDashboard;
+ private IButton addToDashboardButton;
+ private LinkedHashMap<String, String> dashboardMenuMap;
+ private LinkedHashMap<Integer, Dashboard> dashboardMap;
+ private Set<Integer> expandedRows;
+ private MetricsTableListGrid metricsTableListGrid;
+ private int selectedMetricDefinitionId;
+
+ public MetricsGroupTableView(ResourceGroup resourceGroup, AbstractD3GraphListView
abstractD3GraphListView,
+ Set<Integer> expandedRows) {
+ super();
+ this.resourceGroup = resourceGroup;
+ this.abstractD3GraphListView = abstractD3GraphListView;
+ dashboardMenuMap = new LinkedHashMap<String, String>();
+ dashboardMap = new LinkedHashMap<Integer, Dashboard>();
+ setDataSource(new MetricsGroupViewDataSource(resourceGroup));
+ this.expandedRows = expandedRows;
+ }
+
+ @Override
+ protected void onInit() {
+ super.onInit();
+ }
+
+ /**
+ * Creates this Table's list grid (called by onInit()). Subclasses can override
this if they require a custom
+ * subclass of ListGrid.
+ *
+ * @return this Table's list grid (must be an instance of ListGrid)
+ */
+ @Override
+ protected ListGrid createListGrid() {
+ metricsTableListGrid = new MetricsTableListGrid(this, resourceGroup);
+ metricsTableListGrid.addSelectionChangedHandler(new SelectionChangedHandler() {
+ @Override
+ public void onSelectionChanged(SelectionEvent selectionEvent) {
+ if (resourceGroup.getGroupCategory() == GroupCategory.COMPATIBLE) {
+ addToDashboardButton.enable();
+ ListGridRecord selectedRecord = selectionEvent.getSelectedRecord();
+ if (null != selectedRecord) {
+ selectedMetricDefinitionId =
selectedRecord.getAttributeAsInt(METRIC_DEF_ID.getValue());
+ }
+ }
+ }
+ });
+
+ if (null == toolStrip) {
+ toolStrip = createToolstrip();
+ }
+ addExtraWidget(toolStrip, false);
+ addToDashboardButton.disable();
+ return metricsTableListGrid;
+ }
+
+ protected void configureTable() {
+ ArrayList<ListGridField> fields = getDataSource().getListGridFields();
+ setListGridFields(fields.toArray(new ListGridField[0]));
+ }
+
+ private ToolStrip createToolstrip() {
+ toolStrip = new ToolStrip();
+ toolStrip.setWidth(300);
+ toolStrip.setMembersMargin(15);
+ toolStrip.setPadding(5);
+ toolStrip.addSpacer(10);
+ addToDashboardButton = new IButton(MSG.chart_metrics_add_to_dashboard_button());
+ addToDashboardButton.setWidth(80);
+ dashboardSelectItem = new SelectItem();
+ dashboardSelectItem.setTitle(MSG.chart_metrics_add_to_dashboard_label());
+ dashboardSelectItem.setWidth(240);
+ dashboardSelectItem.setWrapTitle(false);
+ populateDashboardMenu();
+ toolStrip.addFormItem(dashboardSelectItem);
+ toolStrip.addMember(addToDashboardButton);
+
+ dashboardSelectItem.addChangeHandler(new ChangeHandler() {
+ @Override
+ public void onChange(ChangeEvent changeEvent) {
+ Integer selectedDashboardId = Integer.valueOf((String)
changeEvent.getValue());
+ selectedDashboard = dashboardMap.get(selectedDashboardId);
+ }
+ });
+ addToDashboardButton.addClickHandler(new
com.smartgwt.client.widgets.events.ClickHandler() {
+ @Override
+ public void onClick(ClickEvent clickEvent) {
+ for (MeasurementDefinition measurementDefinition :
resourceGroup.getResourceType()
+ .getMetricDefinitions()) {
+ if (measurementDefinition.getId() == selectedMetricDefinitionId) {
+ Log.debug("Add to Dashboard -- Storing: " +
measurementDefinition.getDisplayName() + " in "
+ + selectedDashboard.getName());
+
+ storeDashboardMetric(selectedDashboard, resourceGroup.getId(),
measurementDefinition);
+ break;
+ }
+ }
+ }
+ });
+ return toolStrip;
+ }
+
+ @Override
+ /**
+ * Redraw Graphs in this context means to refresh the table and redraw open graphs.
+ */
+ public void refreshData() {
+ new Timer() {
+ @Override
+ public void run() {
+ metricsTableListGrid.expandOpenedRows();
+ BrowserUtility.graphSparkLines();
+ }
+ }.schedule(150);
+
+ }
+
+ @Override
+ public void refresh() {
+ super.refresh(false);
+ metricsTableListGrid.expandOpenedRows();
+ }
+
+ private void populateDashboardMenu() {
+ dashboardMenuMap.clear();
+ dashboardMap.clear();
+
+ DashboardCriteria criteria = new DashboardCriteria();
+ GWTServiceLookup.getDashboardService().findDashboardsByCriteria(criteria,
+ new AsyncCallback<PageList<Dashboard>>() {
+
+ public void onFailure(Throwable caught) {
+
CoreGUI.getErrorHandler().handleError(MSG.view_tree_common_contextMenu_loadFailed_dashboard(),
+ caught);
+ }
+
+ public void onSuccess(PageList<Dashboard> dashboards) {
+ if (dashboards.size() > 0) {
+ for (final Dashboard dashboard : dashboards) {
+ dashboardMenuMap.put(String.valueOf(dashboard.getId()),
dashboard.getName());
+ dashboardMap.put(dashboard.getId(), dashboard);
+ }
+ selectedDashboard = dashboards.get(0);
+ dashboardSelectItem.setValueMap(dashboardMenuMap);
+ dashboardSelectItem.setValue(selectedDashboard.getId());
+ }
+ }
+ });
+ }
+
+ private void storeDashboardMetric(Dashboard dashboard, int resourceGroupId,
MeasurementDefinition definition) {
+
+ DashboardPortlet dashboardPortlet = new
DashboardPortlet(MSG.view_tree_common_contextMenu_groupGraph(),
+ ResourceGroupD3GraphPortlet.KEY, 260);
+ dashboardPortlet.getConfiguration().put(
+ new PropertySimple(ResourceGroupD3GraphPortlet.CFG_RESOURCE_GROUP_ID,
resourceGroupId));
+ dashboardPortlet.getConfiguration().put(
+ new PropertySimple(ResourceGroupD3GraphPortlet.CFG_DEFINITION_ID,
definition.getId()));
+
+ dashboard.addPortlet(dashboardPortlet);
+
+ GWTServiceLookup.getDashboardService().storeDashboard(dashboard, new
AsyncCallback<Dashboard>() {
+ public void onFailure(Throwable caught) {
+
CoreGUI.getErrorHandler().handleError(MSG.view_tree_common_contextMenu_saveChartToDashboardFailure(),
+ caught);
+ }
+
+ public void onSuccess(Dashboard result) {
+ String msg =
MSG.view_tree_common_contextMenu_saveChartToDashboardSuccessful(result.getName());
+ CoreGUI.getMessageCenter().notify(new Message(msg,
Message.Severity.Info));
+ }
+ });
+ }
+
+ public class MetricsTableListGrid extends ListGrid {
+
+ private static final int TREEVIEW_DETAIL_CHART_HEIGHT = 205;
+ private static final int NUM_METRIC_POINTS = 60;
+ final MetricsGroupTableView metricsTableView;
+ private ResourceGroup group;
+
+ public MetricsTableListGrid(final MetricsGroupTableView metricsTableView, final
ResourceGroup group) {
+ super();
+ this.group = group;
+ this.metricsTableView = metricsTableView;
+ setCanExpandRecords(true);
+ setSelectionType(SelectionStyle.SINGLE);
+ setCanExpandMultipleRecords(true);
+ setExpansionMode(ExpansionMode.DETAIL_FIELD);
+
+ addRecordExpandHandler(new RecordExpandHandler() {
+ @Override
+ public void onRecordExpand(RecordExpandEvent recordExpandEvent) {
+
metricsTableView.expandedRows.add(recordExpandEvent.getRecord().getAttributeAsInt(
+ METRIC_DEF_ID.getValue()));
+ refreshData();
+ }
+
+ });
+ addRecordCollapseHandler(new RecordCollapseHandler() {
+ @Override
+ public void onRecordCollapse(RecordCollapseEvent recordCollapseEvent) {
+
metricsTableView.expandedRows.remove(recordCollapseEvent.getRecord().getAttributeAsInt(
+ METRIC_DEF_ID.getValue()));
+ refresh();
+ new Timer() {
+ @Override
+ public void run() {
+ BrowserUtility.graphSparkLines();
+ }
+ }.schedule(150);
+ }
+ });
+ addSortChangedHandler(new SortChangedHandler() {
+ @Override
+ public void onSortChanged(SortEvent sortEvent) {
+ refreshData();
+ }
+ });
+
+ addDataArrivedHandler(new DataArrivedHandler() {
+ @Override
+ public void onDataArrived(DataArrivedEvent dataArrivedEvent) {
+ expandOpenedRows();
+ }
+ });
+
+ }
+
+ public void expandOpenedRows() {
+ int startRow = 0;
+ int endRow = this.getRecords().length;
+ for (int i = startRow; i < endRow; i++) {
+ ListGridRecord listGridRecord = getRecord(i);
+ if (null != listGridRecord) {
+ int metricDefinitionId =
listGridRecord.getAttributeAsInt(METRIC_DEF_ID.getValue());
+ if (null != metricsTableView && null != expandedRows
+ &&
metricsTableView.expandedRows.contains(metricDefinitionId)) {
+ expandRecord(listGridRecord);
+ }
+ }
+ }
+ }
+
+ @Override
+ /**
+ * If you expand a grid row then create a graph.
+ */
+ protected Canvas getExpansionComponent(final ListGridRecord record) {
+ final Integer definitionId =
record.getAttributeAsInt(METRIC_DEF_ID.getValue());
+ final Integer resourceGroupId =
record.getAttributeAsInt(RESOURCE_GROUP_ID.getValue());
+ VLayout vLayout = new VLayout();
+ vLayout.setPadding(5);
+
+ final String chartId = "rChart-" + resourceGroupId + "-"
+ definitionId;
+ HTMLFlow htmlFlow = new
HTMLFlow(MetricD3Graph.createGraphMarkerTemplate(chartId,
+ TREEVIEW_DETAIL_CHART_HEIGHT));
+ vLayout.addMember(htmlFlow);
+
+ int[] definitionArrayIds = new int[1];
+ definitionArrayIds[0] = definitionId;
+
GWTServiceLookup.getMeasurementDataService().findDataForCompatibleGroup(resourceGroupId,
+ definitionArrayIds, CustomDateRangeState.getInstance().getStartTime(),
+ CustomDateRangeState.getInstance().getEndTime(), NUM_METRIC_POINTS,
+ new
AsyncCallback<List<List<MeasurementDataNumericHighLowComposite>>>() {
+ @Override
+ public void onFailure(Throwable caught) {
+ Log.warn("Error retrieving recent metrics charting data for
resource group [" + resourceGroupId
+ + "]:" + caught.getMessage());
+ }
+
+ @Override
+ public void
onSuccess(List<List<MeasurementDataNumericHighLowComposite>> results) {
+ if (!results.isEmpty()) {
+
+ //load the data results for the given metric definition
+ List<MeasurementDataNumericHighLowComposite>
measurementList = results.get(0);
+
+ MeasurementDefinition measurementDefinition = null;
+ for (MeasurementDefinition definition :
group.getResourceType().getMetricDefinitions()) {
+ if (definition.getId() == definitionId) {
+ measurementDefinition = definition;
+ break;
+ }
+ }
+
+ MetricGraphData metricGraphData =
MetricGraphData.createForResourceGroup(group.getId(),
+ group.getName(), measurementDefinition,
measurementList);
+ metricGraphData.setHideLegend(true);
+
+ StackedBarMetricGraphImpl graph =
GWT.create(StackedBarMetricGraphImpl.class);
+ graph.setMetricGraphData(metricGraphData);
+ final MetricD3Graph graphView = new MetricD3Graph(graph,
abstractD3GraphListView);
+ new Timer() {
+ @Override
+ public void run() {
+ graphView.drawJsniChart();
+ new Timer() {
+ @Override
+ public void run() {
+ BrowserUtility.graphSparkLines();
+ }
+ }.schedule(150);
+ }
+ }.schedule(150);
+
+ } else {
+ Log.warn("No chart data retrieving for resource group
[" + resourceGroupId + "-"
+ + definitionId + "]");
+ }
+ }
+ });
+
+ return vLayout;
+ }
+ }
+
+}
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupView.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupView.java
new file mode 100644
index 0000000..1e07e7a
--- /dev/null
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupView.java
@@ -0,0 +1,193 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.rhq.coregui.client.inventory.groups.detail.monitoring.metric;
+
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.types.Overflow;
+import com.smartgwt.client.types.VerticalAlignment;
+import com.smartgwt.client.widgets.Img;
+import com.smartgwt.client.widgets.events.ClickEvent;
+import com.smartgwt.client.widgets.events.ClickHandler;
+
+import org.rhq.core.domain.common.EntityContext;
+import org.rhq.core.domain.measurement.Availability;
+import org.rhq.core.domain.resource.group.ResourceGroup;
+import org.rhq.coregui.client.CoreGUI;
+import org.rhq.coregui.client.IconEnum;
+import org.rhq.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.coregui.client.inventory.common.AbstractD3GraphListView;
+import org.rhq.coregui.client.inventory.common.detail.AbstractTwoLevelTabSetView;
+import org.rhq.coregui.client.inventory.common.graph.CustomDateRangeState;
+import
org.rhq.coregui.client.inventory.common.graph.graphtype.AvailabilityOverUnderGraphType;
+import org.rhq.coregui.client.inventory.resource.detail.monitoring.ExpandedRowsMomento;
+import
org.rhq.coregui.client.inventory.resource.detail.monitoring.avail.AvailabilityD3GraphView;
+import
org.rhq.coregui.client.inventory.resource.detail.monitoring.table.MetricAvailabilityView;
+import org.rhq.coregui.client.util.BrowserUtility;
+import org.rhq.coregui.client.util.async.CountDownLatch;
+import org.rhq.coregui.client.util.enhanced.EnhancedHLayout;
+
+/**
+ * The consolidated metrics view showing metric graphs and availability data both in
graphical and tabular form.
+ * @author Mike Thompson
+ */
+public class MetricsGroupView extends AbstractD3GraphListView implements
+ AbstractTwoLevelTabSetView.ViewRenderedListener {
+
+ private static final String COLLAPSED_TOOLTIP =
MSG.chart_metrics_collapse_tooltip();
+ private static final String EXPANDED_TOOLTIP = MSG.chart_metrics_expand_tooltip();
+
+ private final ResourceGroup resourceGroup;
+ private EnhancedHLayout expandCollapseHLayout;
+ private MetricsGroupTableView metricsTableView;
+ private static Integer lastResourceGroupId = 0;
+
+ /**
+ * Encapsulate the creation logic and not let it leak out into other objects.
+ * Clear the expanded rows set when changing resources as well.
+ * @see ExpandedRowsMomento
+ * @param group
+ * @return MetricsGroupView
+ */
+ public static MetricsGroupView create(ResourceGroup group ){
+
+ boolean isDifferentResource = (group.getId() != lastResourceGroupId);
+
+ if(isDifferentResource){
+ ExpandedRowsMomento.getInstance().clear();
+ }
+
+ return new MetricsGroupView(group,
ExpandedRowsMomento.getInstance().getExpandedRows());
+
+ }
+
+ private MetricsGroupView(ResourceGroup resourceGroup, Set<Integer>
expandedRows) {
+ super();
+ setOverflow(Overflow.AUTO);
+ setWidth100();
+ setHeight100();
+ this.resourceGroup = resourceGroup;
+ metricsTableView = new MetricsGroupTableView(resourceGroup, this, expandedRows);
+
+ final MetricAvailabilityView availabilityDetails = new
MetricAvailabilityView(resourceGroup.getId());
+ availabilityDetails.hide();
+
+ metricsTableView.setHeight100();
+
+ availabilityGraph = AvailabilityD3GraphView.create( new
AvailabilityOverUnderGraphType(resourceGroup.getId()));
+
+ expandCollapseHLayout = new EnhancedHLayout();
+ //add expand/collapse icon
+ final Img expandCollapseArrow = new
Img(IconEnum.COLLAPSED_ICON.getIcon16x16Path(), 16, 16);
+ expandCollapseArrow.setTooltip(COLLAPSED_TOOLTIP);
+ expandCollapseArrow.setLayoutAlign(VerticalAlignment.BOTTOM);
+ expandCollapseArrow.addClickHandler(new ClickHandler() {
+ private boolean collapsed = true;
+
+ @Override
+ public void onClick(ClickEvent event) {
+ collapsed = !collapsed;
+ if (collapsed) {
+
expandCollapseArrow.setSrc(IconEnum.COLLAPSED_ICON.getIcon16x16Path());
+ expandCollapseArrow.setTooltip(COLLAPSED_TOOLTIP);
+ availabilityDetails.hide();
+ } else {
+
expandCollapseArrow.setSrc(IconEnum.EXPANDED_ICON.getIcon16x16Path());
+ expandCollapseArrow.setTooltip(EXPANDED_TOOLTIP);
+ availabilityDetails.show();
+
+ }
+ drawAvailabilityGraphAndSparklines();
+ }
+ });
+ expandCollapseHLayout.addMember(expandCollapseArrow);
+ addAvailabilityGraph();
+
+ addMember(buttonBarDateTimeRangeEditor);
+ addMember(expandCollapseHLayout);
+ addMember(availabilityDetails);
+ addMember(metricsTableView);
+ lastResourceGroupId = resourceGroup.getId();
+ }
+
+
+ private void addAvailabilityGraph() {
+ expandCollapseHLayout.removeMember(availabilityGraph);
+ availabilityGraph.destroy();
+
+ availabilityGraph = AvailabilityD3GraphView.create(new
AvailabilityOverUnderGraphType(resourceGroup.getId()));
+
+ expandCollapseHLayout.addMember(availabilityGraph);
+
+ queryAvailability(EntityContext.forGroup(resourceGroup.getId()),
CustomDateRangeState.getInstance().getStartTime(),
+ CustomDateRangeState.getInstance().getEndTime(), null);
+ }
+
+
+ @Override
+ protected void queryAvailability(final EntityContext context, Long startTime, Long
endTime, CountDownLatch notUsed) {
+
+ // now return the availability
+
GWTServiceLookup.getAvailabilityService().getAvailabilitiesForResource(context.getGroupId(),
startTime,
+ endTime, new AsyncCallback<List<Availability>>() {
+ @Override
+ public void onFailure(Throwable caught) {
+
CoreGUI.getErrorHandler().handleError(MSG.view_resource_monitor_availability_loadFailed(),
caught);
+ }
+
+ @Override
+ public void onSuccess(List<Availability> availList) {
+ availabilityGraph.setAvailabilityList(availList);
+ new Timer() {
+ @Override
+ public void run() {
+ buttonBarDateTimeRangeEditor.updateTimeRangeToNow();
+ availabilityGraph.drawJsniChart();
+
+ }
+ }.schedule(150);
+ }
+ });
+ }
+
+ private void drawAvailabilityGraphAndSparklines() {
+ new Timer() {
+ @Override
+ public void run() {
+ availabilityGraph.drawJsniChart();
+ BrowserUtility.graphSparkLines();
+ }
+ }.schedule(150);
+ }
+
+ @Override
+ public void refreshData() {
+ addAvailabilityGraph();
+ metricsTableView.refresh();
+ }
+
+ @Override
+ public void onViewRendered() {
+ // refresh the graphs on subtab nav because we are a cached view not new
+ refreshData();
+ }
+}
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupViewDataSource.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupViewDataSource.java
new file mode 100644
index 0000000..a5f1353
--- /dev/null
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/groups/detail/monitoring/metric/MetricsGroupViewDataSource.java
@@ -0,0 +1,314 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.coregui.client.inventory.groups.detail.monitoring.metric;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.data.DSRequest;
+import com.smartgwt.client.data.DSResponse;
+import com.smartgwt.client.data.Record;
+import com.smartgwt.client.widgets.grid.CellFormatter;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.ListGridRecord;
+
+import org.rhq.core.domain.criteria.Criteria;
+import org.rhq.core.domain.measurement.MeasurementDefinition;
+import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
+import org.rhq.core.domain.measurement.ui.MetricDisplaySummary;
+import org.rhq.core.domain.measurement.ui.MetricDisplayValue;
+import org.rhq.core.domain.resource.group.ResourceGroup;
+import org.rhq.coregui.client.CoreGUI;
+import org.rhq.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.coregui.client.inventory.common.graph.CustomDateRangeState;
+import org.rhq.coregui.client.util.BrowserUtility;
+import org.rhq.coregui.client.util.Log;
+import org.rhq.coregui.client.util.MeasurementUtility;
+import org.rhq.coregui.client.util.RPCDataSource;
+import org.rhq.coregui.client.util.async.Command;
+import org.rhq.coregui.client.util.async.CountDownLatch;
+
+import static org.rhq.core.domain.measurement.DataType.COMPLEX;
+import static org.rhq.core.domain.measurement.DataType.MEASUREMENT;
+import static
org.rhq.coregui.client.inventory.resource.detail.monitoring.table.MetricsGridFieldName.*;
+
+/**
+ * A simple data source to read in metric data summaries for a resource.
+ * This doesn't support paging - everything is returned in one query. Since
+ * the number of metrics per resource is relatively small (never more than tens of
them),
+ * we just load them all in at once.
+ *
+ * @author John Mazzitelli
+ * @author Mike Thompson
+ */
+public class MetricsGroupViewDataSource extends RPCDataSource<MetricDisplaySummary,
Criteria> {
+
+ private static final int NUMBER_OF_METRIC_POINTS = 60;
+
+ private final ResourceGroup resourceGroup;
+ private List<MetricDisplaySummary> metricDisplaySummaries;
+ private List<List<MeasurementDataNumericHighLowComposite>>
metricsDataList;
+ private int[] definitionArrayIds;
+
+ public MetricsGroupViewDataSource(ResourceGroup resourceGroup) {
+ this.resourceGroup = resourceGroup;
+ }
+
+ /**
+ * The view that contains the list grid which will display this datasource's data
will call this
+ * method to get the field information which is used to control the display of the
data.
+ *
+ * @return list grid fields used to display the datasource data
+ */
+ public ArrayList<ListGridField> getListGridFields() {
+ ArrayList<ListGridField> fields = new ArrayList<ListGridField>(7);
+
+ ListGridField sparklineField = new ListGridField(SPARKLINE.getValue(),
MSG.chart_metrics_sparkline_header());
+ sparklineField.setCellFormatter(new CellFormatter() {
+ @Override
+ public String format(Object value, ListGridRecord record, int rowNum, int
colNum) {
+ if (value == null) {
+ return "";
+ }
+ String contents = "<span id='sparkline_" +
resourceGroup.getId() + "-"
+ + record.getAttributeAsInt(METRIC_DEF_ID.getValue()) + "'
class='dynamicsparkline' width='70' "
+ + "values='" +
record.getAttribute(SPARKLINE.getValue()) + "'></span>";
+ return contents;
+
+ }
+ });
+
+ sparklineField.setWidth(80);
+ fields.add(sparklineField);
+
+ ListGridField nameField = new ListGridField(METRIC_LABEL.getValue(),
METRIC_LABEL.getLabel());
+ nameField.setWidth("30%");
+ fields.add(nameField);
+
+ ListGridField minField = new ListGridField(MIN_VALUE.getValue(),
MIN_VALUE.getLabel());
+ minField.setWidth("15%");
+ fields.add(minField);
+
+ ListGridField maxField = new ListGridField(MAX_VALUE.getValue(),
MAX_VALUE.getLabel());
+ maxField.setWidth("15%");
+ fields.add(maxField);
+
+ ListGridField avgField = new ListGridField(AVG_VALUE.getValue(),
AVG_VALUE.getLabel());
+ avgField.setWidth("15%");
+ fields.add(avgField);
+
+ ListGridField alertsField = new ListGridField(ALERT_COUNT.getValue(),
ALERT_COUNT.getLabel());
+ alertsField.setWidth("10%");
+ fields.add(alertsField);
+
+ return fields;
+ }
+
+ @Override
+ public MetricDisplaySummary copyValues(Record from) {
+ // we should never need this method - we only go in one direction
+ // if we ever need this, just have copyValues store an "object"
attribute whose value is "from"
+ // which this method then just reads out. Since we don't need this now, save
memory by not
+ // keeping the MetricDisplayValue around
+ return null;
+ }
+
+ @Override
+ public ListGridRecord copyValues(MetricDisplaySummary from) {
+ MeasurementUtility.formatSimpleMetrics(from);
+
+ ListGridRecord record = new ListGridRecord();
+ record.setAttribute(SPARKLINE.getValue(),
getCsvMetricsForSparkline(from.getDefinitionId()));
+ record.setAttribute(METRIC_LABEL.getValue(), from.getLabel());
+ record.setAttribute(ALERT_COUNT.getValue(),
String.valueOf(from.getAlertCount()));
+ record.setAttribute(MIN_VALUE.getValue(),
getMetricStringValue(from.getMinMetric()));
+ record.setAttribute(MAX_VALUE.getValue(),
getMetricStringValue(from.getMaxMetric()));
+ record.setAttribute(AVG_VALUE.getValue(),
getMetricStringValue(from.getAvgMetric()));
+ record.setAttribute(METRIC_DEF_ID.getValue(), from.getDefinitionId());
+ record.setAttribute(METRIC_SCHEDULE_ID.getValue(), from.getScheduleId());
+ record.setAttribute(METRIC_UNITS.getValue(), from.getUnits());
+ record.setAttribute(METRIC_NAME.getValue(), from.getMetricName());
+ record.setAttribute(RESOURCE_GROUP_ID.getValue(), resourceGroup.getId());
+ return record;
+ }
+
+ private String getCsvMetricsForSparkline(int definitionId) {
+ StringBuilder sb = new StringBuilder();
+ List<MeasurementDataNumericHighLowComposite> selectedMetricsList =
getMeasurementsForMeasurementDefId(definitionId);
+
+ for (MeasurementDataNumericHighLowComposite measurementData :
selectedMetricsList) {
+ if (!Double.isNaN(measurementData.getValue())) {
+ sb.append((int) measurementData.getValue());
+ sb.append(",");
+ }
+ }
+
+ if (sb.toString().endsWith(",")) {
+ sb.setLength(sb.length() - 1);
+ }
+ // handle the case where we have just installed the server so not much history
+ // and our date range is set such that only one value returns which the
+ // sparkline graph will not plot anything, so we need at least 2 values
+ if (!sb.toString().contains(",")) {
+ // append another value just so we have 2 values and it will graph
+ return "0," + sb.toString();
+ }
+
+ return sb.toString();
+ }
+
+ private List<MeasurementDataNumericHighLowComposite>
getMeasurementsForMeasurementDefId(int definitionId) {
+ int selectedIndex = 0;
+
+ // find the ordinal position as specified when querying the metrics
+ for (int i = 0; i < definitionArrayIds.length; i++) {
+ if (definitionArrayIds[i] == definitionId) {
+ selectedIndex = i;
+ break;
+ }
+ }
+
+ return metricsDataList.get(selectedIndex);
+ }
+
+ protected String getMetricStringValue(MetricDisplayValue value) {
+ return (value != null) ? value.toString() : "";
+ }
+
+ @Override
+ protected Criteria getFetchCriteria(DSRequest request) {
+ // NOTE: we don't use criterias for this datasource, just return null
+ return null;
+ }
+
+ @Override
+ protected void executeFetch(final DSRequest request, final DSResponse response, final
Criteria unused) {
+
+ // This latch is the last thing that gets executed after we have executed the
+ // 1 query
+ final CountDownLatch countDownLatch = CountDownLatch.create(1, new Command() {
+
+ @Override
+ public void execute() {
+
+ // NOTE: this runs after the queryMetricDisplaySummaries is complete
+ queryGroupMetrics(resourceGroup, request, response);
+ }
+ });
+
+ organizeMeasurementDefinitionOrder(resourceGroup);
+ queryMetricDisplaySummaries(definitionArrayIds,
CustomDateRangeState.getInstance().getStartTime(),
+ CustomDateRangeState.getInstance().getEndTime(), countDownLatch);
+
+ }
+
+ private void queryGroupMetrics(final ResourceGroup resourceGroup, final DSRequest
request, final DSResponse response) {
+
+
GWTServiceLookup.getMeasurementDataService().findDataForCompatibleGroup(resourceGroup.getId(),
+ definitionArrayIds, CustomDateRangeState.getInstance().getStartTime(),
+ CustomDateRangeState.getInstance().getEndTime(), NUMBER_OF_METRIC_POINTS,
+ new
AsyncCallback<List<List<MeasurementDataNumericHighLowComposite>>>() {
+ @Override
+ public void onFailure(Throwable caught) {
+ Log.warn("Error retrieving recent metrics charting data for
resource [" + resourceGroup.getId()
+ + "]:" + caught.getMessage());
+ }
+
+ @Override
+ public void
onSuccess(List<List<MeasurementDataNumericHighLowComposite>>
measurementDataList) {
+ if (null != measurementDataList &&
!measurementDataList.isEmpty()) {
+ metricsDataList = measurementDataList;
+ response.setData(buildRecords(metricDisplaySummaries));
+ processResponse(request.getRequestId(), response);
+ new Timer() {
+ @Override
+ public void run() {
+ BrowserUtility.graphSparkLines();
+ }
+ }.schedule(150);
+ }
+ }
+ });
+
+ }
+
+ private void organizeMeasurementDefinitionOrder(ResourceGroup resourceGroup) {
+ Set<MeasurementDefinition> definitions =
getMetricDefinitions(resourceGroup);
+
+ //build id mapping for measurementDefinition instances Ex. Free Memory ->
MeasurementDefinition[100071]
+ final HashMap<String, MeasurementDefinition> measurementDefMap = new
HashMap<String, MeasurementDefinition>();
+ for (MeasurementDefinition definition : definitions) {
+ measurementDefMap.put(definition.getDisplayName(), definition);
+ }
+ //bundle definition ids for asynch call.
+ definitionArrayIds = new int[definitions.size()];
+ final String[] displayOrder = new String[definitions.size()];
+ measurementDefMap.keySet().toArray(displayOrder);
+ //sort the charting data ex. Free Memory, Free Swap Space,..System Load
+ Arrays.sort(displayOrder);
+
+ //organize definitionArrayIds for ordered request on server.
+ int index = 0;
+ for (String definitionToDisplay : displayOrder) {
+ definitionArrayIds[index++] =
measurementDefMap.get(definitionToDisplay).getId();
+ }
+ }
+
+ private void queryMetricDisplaySummaries(int[] measurementDefIds, Long startTime,
Long endTime,
+ final CountDownLatch countDownLatch) {
+
GWTServiceLookup.getMeasurementChartsService().getMetricDisplaySummariesForCompatibleGroup(
+ resourceGroup.getId(), measurementDefIds, startTime, endTime, false,
+ new AsyncCallback<ArrayList<MetricDisplaySummary>>() {
+ @Override
+ public void onSuccess(ArrayList<MetricDisplaySummary>
metricDisplaySummaries) {
+ setMetricDisplaySummaries(metricDisplaySummaries);
+ countDownLatch.countDown();
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ CoreGUI.getErrorHandler().handleError("Cannot load
metrics", caught);
+ countDownLatch.countDown();
+ }
+ }
+
+ );
+ }
+
+ private void setMetricDisplaySummaries(List<MetricDisplaySummary>
metricDisplaySummaries) {
+ this.metricDisplaySummaries = metricDisplaySummaries;
+ }
+
+ private Set<MeasurementDefinition> getMetricDefinitions(ResourceGroup
resourceGroup) {
+ Set<MeasurementDefinition> definitions = new
HashSet<MeasurementDefinition>();
+ for (MeasurementDefinition measurementDefinition :
resourceGroup.getResourceType().getMetricDefinitions()) {
+ if (measurementDefinition.getDataType() == MEASUREMENT ||
measurementDefinition.getDataType() == COMPLEX) {
+ definitions.add(measurementDefinition);
+ }
+ }
+ return definitions;
+ }
+}
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricAvailabilityView.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricAvailabilityView.java
new file mode 100644
index 0000000..4b542c9
--- /dev/null
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricAvailabilityView.java
@@ -0,0 +1,223 @@
+/*
+ * RHQ Management Platform
+ * Copyright 2012, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.coregui.client.inventory.resource.detail.monitoring.table;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.FormItem;
+import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+
+import org.rhq.core.domain.measurement.AvailabilityType;
+import org.rhq.core.domain.measurement.MeasurementUnits;
+import org.rhq.core.domain.resource.composite.ResourceAvailabilitySummary;
+import org.rhq.coregui.client.CoreGUI;
+import org.rhq.coregui.client.components.table.TimestampCellFormatter;
+import org.rhq.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.coregui.client.util.MeasurementConverterClient;
+import org.rhq.coregui.client.util.enhanced.EnhancedVLayout;
+
+/**
+ * This shows the availability history for a resource.
+ *
+ * @author Jay Shaughnessy
+ * @author John Mazzitelli
+ * @author Mike Thompson
+ */
+public class MetricAvailabilityView extends EnhancedVLayout {
+
+ private int resourceId;
+ private StaticTextItem currentField;
+ private StaticTextItem availField;
+ private StaticTextItem availTimeField;
+ private StaticTextItem downField;
+ private StaticTextItem downTimeField;
+ private StaticTextItem disabledField;
+ private StaticTextItem disabledTimeField;
+ private StaticTextItem failureCountField;
+ private StaticTextItem disabledCountField;
+ private StaticTextItem mtbfField;
+ private StaticTextItem mttrField;
+ private StaticTextItem unknownField;
+ private StaticTextItem currentTimeField;
+
+ public MetricAvailabilityView(int resourceId) {
+ super();
+
+ this.resourceId = resourceId;
+
+ setWidth100();
+ setHeight(165);
+ }
+
+ @Override
+ protected void onInit() {
+ super.onInit();
+
+ addMember(createSummaryForm());
+ }
+
+ private DynamicForm createSummaryForm() {
+ DynamicForm form = new DynamicForm();
+ form.setWidth100();
+ form.setAutoHeight();
+ form.setMargin(10);
+ form.setNumCols(4);
+
+ // row 1
+ currentField = new StaticTextItem("current",
MSG.view_resource_monitor_availability_currentStatus());
+ currentField.setWrapTitle(false);
+ currentField.setColSpan(4);
+
+ // row 2
+ availField = new StaticTextItem("avail",
MSG.common_title_availability());
+ availField.setWrapTitle(false);
+ prepareTooltip(availField, MSG.view_resource_monitor_availability_tooltip_up());
+
+ availTimeField = new StaticTextItem("availTime",
MSG.view_resource_monitor_availability_uptime());
+ availTimeField.setWrapTitle(false);
+ prepareTooltip(availTimeField,
MSG.view_resource_monitor_availability_uptime_tooltip());
+
+ // row 3
+ downField = new StaticTextItem("down",
MSG.common_status_avail_down_lower());
+ downField.setWrapTitle(false);
+ prepareTooltip(downField,
MSG.view_resource_monitor_availability_tooltip_down());
+
+ downTimeField = new StaticTextItem("downTime",
MSG.view_resource_monitor_availability_downtime());
+ downTimeField.setWrapTitle(false);
+ prepareTooltip(downTimeField,
MSG.view_resource_monitor_availability_downtime_tooltip());
+
+ // row 4
+ disabledField = new StaticTextItem("disabled",
MSG.common_status_avail_disabled_lower());
+ disabledField.setWrapTitle(false);
+ prepareTooltip(disabledField,
MSG.view_resource_monitor_availability_tooltip_disabled());
+
+ disabledTimeField = new StaticTextItem("disabledTime",
MSG.view_resource_monitor_availability_disabledTime());
+ disabledTimeField.setWrapTitle(false);
+ prepareTooltip(disabledTimeField,
MSG.view_resource_monitor_availability_disabledTime_tooltip());
+
+ // row 5
+ failureCountField = new StaticTextItem("failureCount",
MSG.view_resource_monitor_availability_numFailures());
+ failureCountField.setWrapTitle(false);
+ prepareTooltip(failureCountField,
MSG.view_resource_monitor_availability_numFailures_tooltip());
+
+ disabledCountField = new StaticTextItem("disabledCount",
MSG.view_resource_monitor_availability_numDisabled());
+ disabledCountField.setWrapTitle(false);
+ prepareTooltip(disabledCountField,
MSG.view_resource_monitor_availability_numDisabled_tooltip());
+
+ // row 6
+ mtbfField = new StaticTextItem("mtbf",
MSG.view_resource_monitor_availability_mtbf());
+ mtbfField.setWrapTitle(false);
+ prepareTooltip(mtbfField,
MSG.view_resource_monitor_availability_mtbf_tooltip());
+
+ mttrField = new StaticTextItem("mttr",
MSG.view_resource_monitor_availability_mttr());
+ mttrField.setWrapTitle(false);
+ prepareTooltip(mttrField,
MSG.view_resource_monitor_availability_mttr_tooltip());
+
+ // row 7
+ unknownField = new StaticTextItem("unknown");
+ unknownField.setWrapTitle(false);
+ unknownField.setColSpan(4);
+ unknownField.setShowTitle(false);
+
+ // row 8
+ currentTimeField = new StaticTextItem("currentTime");
+ currentTimeField.setWrapTitle(false);
+ currentTimeField.setColSpan(4);
+ currentTimeField.setShowTitle(false);
+
+ form.setItems(currentField, availField, availTimeField, downField, downTimeField,
disabledField,
+ disabledTimeField, failureCountField, disabledCountField, mtbfField,
mttrField, unknownField,
+ currentTimeField);
+
+ reloadSummaryData();
+
+ return form;
+ }
+
+ private void reloadSummaryData() {
+ GWTServiceLookup.getResourceService().getResourceAvailabilitySummary(resourceId,
+ new AsyncCallback<ResourceAvailabilitySummary>() {
+
+ @Override
+ public void onSuccess(ResourceAvailabilitySummary result) {
+
+
currentField.setValue(MSG.view_resource_monitor_availability_currentStatus_value(
+ getAvailabilityTypeMessage(result.getCurrent()),
+
TimestampCellFormatter.format(result.getLastChange().getTime())));
+
availField.setValue(MeasurementConverterClient.format(result.getUpPercentage(),
+ MeasurementUnits.PERCENTAGE, true));
+ availTimeField.setValue(MeasurementConverterClient.format((double)
result.getUpTime(),
+ MeasurementUnits.MILLISECONDS, true));
+
downField.setValue(MeasurementConverterClient.format(result.getDownPercentage(),
+ MeasurementUnits.PERCENTAGE, true));
+ downTimeField.setValue(MeasurementConverterClient.format((double)
result.getDownTime(),
+ MeasurementUnits.MILLISECONDS, true));
+
disabledField.setValue(MeasurementConverterClient.format(result.getDisabledPercentage(),
+ MeasurementUnits.PERCENTAGE, true));
+ disabledTimeField.setValue(MeasurementConverterClient.format((double)
result.getDisabledTime(),
+ MeasurementUnits.MILLISECONDS, true));
+ failureCountField.setValue(result.getFailures());
+ disabledCountField.setValue(result.getDisabled());
+ mtbfField.setValue(MeasurementConverterClient.format((double)
result.getMTBF(),
+ MeasurementUnits.MILLISECONDS, true));
+ mttrField.setValue(MeasurementConverterClient.format((double)
result.getMTTR(),
+ MeasurementUnits.MILLISECONDS, true));
+
+ if (result.getUnknownTime() > 0L) {
+
unknownField.setValue(MSG.view_resource_monitor_availability_unknown(MeasurementConverterClient
+ .format((double) result.getUnknownTime(),
MeasurementUnits.MILLISECONDS, true)));
+ } else {
+ unknownField.setValue("");
+ }
+
+
currentTimeField.setValue(MSG.view_resource_monitor_availability_currentAsOf(TimestampCellFormatter
+ .format(result.getCurrentTime())));
+ }
+
+ @Override
+ public void onFailure(Throwable caught) {
+ currentField.setValue(MSG.common_label_error());
+ CoreGUI.getErrorHandler()
+
.handleError(MSG.view_resource_monitor_availability_summaryError(), caught);
+ }
+ });
+ }
+
+ private String getAvailabilityTypeMessage(AvailabilityType availabilityType) {
+ switch (availabilityType) {
+ case UP:
+ return MSG.common_status_avail_up();
+ case DOWN:
+ return MSG.common_status_avail_down();
+ case DISABLED:
+ return MSG.common_status_avail_disabled();
+ case UNKNOWN:
+ default:
+ return MSG.common_status_avail_unknown();
+ }
+ }
+
+ private void prepareTooltip(FormItem item, String tooltip) {
+ item.setHoverWidth(400);
+ item.setPrompt(tooltip);
+ }
+
+}
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsGridFieldName.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsGridFieldName.java
new file mode 100644
index 0000000..f912dee
--- /dev/null
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsGridFieldName.java
@@ -0,0 +1,63 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2014 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.rhq.coregui.client.inventory.resource.detail.monitoring.table;
+
+import static org.rhq.core.domain.measurement.ui.MetricDisplayConstants.AVERAGE_KEY;
+import static org.rhq.core.domain.measurement.ui.MetricDisplayConstants.MAX_KEY;
+import static org.rhq.core.domain.measurement.ui.MetricDisplayConstants.MIN_KEY;
+
+import org.rhq.coregui.client.CoreGUI;
+
+/**
+ * Typesafe field names used in consolidated metrics screen grids for Resource and
ResourceGroup.
+ * Also associates the proper label with the value.
+ *
+ * @author Mike Thompson
+ */
+@SuppressWarnings("GwtInconsistentSerializableClass")
+public enum MetricsGridFieldName {
+
+ SPARKLINE("sparkline"), METRIC_LABEL("label",
CoreGUI.getMessages().common_title_name()), ALERT_COUNT("alertCount",
+ CoreGUI.getMessages().common_title_alerts()), MAX_VALUE(MAX_KEY,
CoreGUI.getMessages()
+ .common_title_monitor_maximum()), MIN_VALUE(MIN_KEY,
CoreGUI.getMessages().common_title_monitor_minimum()), AVG_VALUE(
+ AVERAGE_KEY, CoreGUI.getMessages().common_title_monitor_average()),
METRIC_DEF_ID("defId"), METRIC_SCHEDULE_ID(
+ "schedId"), METRIC_UNITS("units"),
METRIC_NAME("name"), RESOURCE_GROUP_ID("resourceGroupId"),
+ RESOURCE_ID("resourceId"), LIVE_VALUE("live",
CoreGUI.getMessages().view_resource_monitor_table_live());
+
+ private final String value;
+ private final String label;
+
+ MetricsGridFieldName(String value, String label) {
+ this.value = value;
+ this.label = label;
+ }
+
+ MetricsGridFieldName(String value) {
+ this.value = value;
+ this.label = "";
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+}
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
index efba122..7e84c3d 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsResourceView.java
@@ -41,7 +41,6 @@ import
org.rhq.coregui.client.inventory.common.graph.graphtype.AvailabilityOverU
import org.rhq.coregui.client.inventory.resource.detail.monitoring.ExpandedRowsMomento;
import
org.rhq.coregui.client.inventory.resource.detail.monitoring.avail.AvailabilityD3GraphView;
import org.rhq.coregui.client.util.BrowserUtility;
-import org.rhq.coregui.client.util.Log;
import org.rhq.coregui.client.util.async.CountDownLatch;
import org.rhq.coregui.client.util.enhanced.EnhancedHLayout;
@@ -87,7 +86,7 @@ public class MetricsResourceView extends AbstractD3GraphListView
implements
this.resource = resource;
metricsTableView = new MetricsTableView(resource, this, expandedRows);
- final ResourceMetricAvailabilityView availabilityDetails = new
ResourceMetricAvailabilityView(resource);
+ final MetricAvailabilityView availabilityDetails = new
MetricAvailabilityView(resource.getId());
availabilityDetails.hide();
metricsTableView.setHeight100();
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java
index 63a6619..6f0f7f7 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsTableView.java
@@ -74,6 +74,8 @@ import org.rhq.coregui.client.util.BrowserUtility;
import org.rhq.coregui.client.util.Log;
import org.rhq.coregui.client.util.message.Message;
+import static
org.rhq.coregui.client.inventory.resource.detail.monitoring.table.MetricsGridFieldName.*;
+
/**
* Views a resource's metrics in a tabular view with sparkline graph and optional
detailed d3 graph.
*
@@ -125,10 +127,8 @@ public class MetricsTableView extends
Table<MetricsViewDataSource> implements Re
addToDashboardButton.enable();
ListGridRecord selectedRecord = selectionEvent.getSelectedRecord();
if (null != selectedRecord) {
- //Log.debug("Selected Metric Label: "
- // +
selectedRecord.getAttribute(MetricsViewDataSource.FIELD_METRIC_LABEL));
- selectedMetricDefinitionId = selectedRecord
- .getAttributeAsInt(MetricsViewDataSource.FIELD_METRIC_DEF_ID);
+ selectedMetricDefinitionId =
selectedRecord.getAttributeAsInt(METRIC_DEF_ID
+ .getValue());
}
}
});
@@ -176,7 +176,7 @@ public class MetricsTableView extends
Table<MetricsViewDataSource> implements Re
if (measurementDefinition.getId() == selectedMetricDefinitionId) {
Log.debug("Add to Dashboard -- Storing: " +
measurementDefinition.getDisplayName() + " in "
+ selectedDashboard.getName());
- storeDashboardMetric(selectedDashboard, resource,
measurementDefinition);
+ storeDashboardMetric(selectedDashboard, resource.getId(),
measurementDefinition);
break;
}
}
@@ -233,11 +233,11 @@ public class MetricsTableView extends
Table<MetricsViewDataSource> implements Re
});
}
- private void storeDashboardMetric(Dashboard dashboard, Resource resource,
MeasurementDefinition definition) {
+ private void storeDashboardMetric(Dashboard dashboard, int resourceId,
MeasurementDefinition definition) {
DashboardPortlet dashboardPortlet = new
DashboardPortlet(MSG.view_tree_common_contextMenu_resourceGraph(),
- ResourceD3GraphPortlet.KEY, 200);
+ ResourceD3GraphPortlet.KEY, 260);
dashboardPortlet.getConfiguration().put(
- new PropertySimple(ResourceD3GraphPortlet.CFG_RESOURCE_ID,
resource.getId()));
+ new PropertySimple(ResourceD3GraphPortlet.CFG_RESOURCE_ID, resourceId));
dashboardPortlet.getConfiguration().put(
new PropertySimple(ResourceD3GraphPortlet.CFG_DEFINITION_ID,
definition.getId()));
@@ -278,7 +278,7 @@ public class MetricsTableView extends
Table<MetricsViewDataSource> implements Re
@Override
public void onRecordExpand(RecordExpandEvent recordExpandEvent) {
metricsTableView.expandedRows.add(recordExpandEvent.getRecord().getAttributeAsInt(
- MetricsViewDataSource.FIELD_METRIC_DEF_ID));
+ METRIC_DEF_ID.getValue()));
refreshData();
}
@@ -287,7 +287,7 @@ public class MetricsTableView extends
Table<MetricsViewDataSource> implements Re
@Override
public void onRecordCollapse(RecordCollapseEvent recordCollapseEvent) {
metricsTableView.expandedRows.remove(recordCollapseEvent.getRecord().getAttributeAsInt(
- MetricsViewDataSource.FIELD_METRIC_DEF_ID));
+ METRIC_DEF_ID.getValue()));
refresh();
new Timer() {
@Override
@@ -321,7 +321,7 @@ public class MetricsTableView extends
Table<MetricsViewDataSource> implements Re
ListGridRecord listGridRecord = getRecord(i);
if (null != listGridRecord) {
int metricDefinitionId = listGridRecord
- .getAttributeAsInt(MetricsViewDataSource.FIELD_METRIC_DEF_ID);
+ .getAttributeAsInt(METRIC_DEF_ID.getValue());
if (null != metricsTableView && null != expandedRows
&&
metricsTableView.expandedRows.contains(metricDefinitionId)) {
expandRecord(listGridRecord);
@@ -330,18 +330,14 @@ public class MetricsTableView extends
Table<MetricsViewDataSource> implements Re
}
}
- public void expandOpenedRows(Set<Integer> selectedRows) {
- expandedRows = selectedRows;
- expandOpenedRows();
- }
@Override
/**
* If you expand a grid row then create a graph.
*/
protected Canvas getExpansionComponent(final ListGridRecord record) {
- final Integer definitionId =
record.getAttributeAsInt(MetricsViewDataSource.FIELD_METRIC_DEF_ID);
- final Integer resourceId =
record.getAttributeAsInt(MetricsViewDataSource.FIELD_RESOURCE_ID);
+ final Integer definitionId =
record.getAttributeAsInt(METRIC_DEF_ID.getValue());
+ final Integer resourceId = record.getAttributeAsInt(RESOURCE_ID.getValue());
VLayout vLayout = new VLayout();
vLayout.setPadding(5);
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsViewDataSource.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsViewDataSource.java
index 4c9c7c1..248eee0 100644
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsViewDataSource.java
+++
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/MetricsViewDataSource.java
@@ -61,6 +61,7 @@ import org.rhq.coregui.client.util.RPCDataSource;
import org.rhq.coregui.client.util.async.Command;
import org.rhq.coregui.client.util.async.CountDownLatch;
import org.rhq.coregui.client.util.preferences.MeasurementUserPreferences;
+import static
org.rhq.coregui.client.inventory.resource.detail.monitoring.table.MetricsGridFieldName.*;
/**
* A simple data source to read in metric data summaries for a resource.
@@ -75,19 +76,6 @@ public class MetricsViewDataSource extends
RPCDataSource<MetricDisplaySummary, C
private static final int NUMBER_OF_METRIC_POINTS = 60;
- public static final String FIELD_SPARKLINE = "sparkline";
- public static final String FIELD_METRIC_LABEL = "label";
- public static final String FIELD_ALERT_COUNT = "alertCount";
- public static final String FIELD_MIN_VALUE = "min";
- public static final String FIELD_MAX_VALUE = "max";
- public static final String FIELD_AVG_VALUE = "avg";
- public static final String FIELD_LIVE_VALUE = "live";
- public static final String FIELD_METRIC_DEF_ID = "defId";
- public static final String FIELD_METRIC_SCHED_ID = "schedId";
- public static final String FIELD_METRIC_UNITS = "units";
- public static final String FIELD_METRIC_NAME = "name";
- public static final String FIELD_RESOURCE_ID = "resourceId";
-
private final Resource resource;
private List<MetricDisplaySummary> metricDisplaySummaries;
private List<List<MeasurementDataNumericHighLowComposite>>
metricsDataList;
@@ -111,7 +99,7 @@ public class MetricsViewDataSource extends
RPCDataSource<MetricDisplaySummary, C
public ArrayList<ListGridField> getListGridFields() {
ArrayList<ListGridField> fields = new ArrayList<ListGridField>(7);
- ListGridField sparklineField = new ListGridField(FIELD_SPARKLINE,
MSG.chart_metrics_sparkline_header());
+ ListGridField sparklineField = new ListGridField(SPARKLINE.getValue(),
MSG.chart_metrics_sparkline_header());
sparklineField.setCellFormatter(new CellFormatter() {
@Override
public String format(Object value, ListGridRecord record, int rowNum, int
colNum) {
@@ -119,8 +107,8 @@ public class MetricsViewDataSource extends
RPCDataSource<MetricDisplaySummary, C
return "";
}
String contents = "<span id='sparkline_" +
resource.getId() + "-"
- + record.getAttributeAsInt(FIELD_METRIC_DEF_ID) + "'
class='dynamicsparkline' width='70' "
- + "values='" + record.getAttribute(FIELD_SPARKLINE)
+ "'></span>";
+ + record.getAttributeAsInt(METRIC_DEF_ID.getValue()) +
"' class='dynamicsparkline' width='70' "
+ + "values='" +
record.getAttribute(SPARKLINE.getValue()) + "'></span>";
return contents;
}
@@ -129,27 +117,27 @@ public class MetricsViewDataSource extends
RPCDataSource<MetricDisplaySummary, C
sparklineField.setWidth(80);
fields.add(sparklineField);
- ListGridField nameField = new ListGridField(FIELD_METRIC_LABEL,
MSG.common_title_name());
+ ListGridField nameField = new ListGridField(METRIC_LABEL.getValue(),
METRIC_LABEL.getLabel());
nameField.setWidth("30%");
fields.add(nameField);
- ListGridField minField = new ListGridField(FIELD_MIN_VALUE,
MSG.common_title_monitor_minimum());
+ ListGridField minField = new ListGridField(MIN_VALUE.getValue(),
MIN_VALUE.getLabel());
minField.setWidth("15%");
fields.add(minField);
- ListGridField maxField = new ListGridField(FIELD_MAX_VALUE,
MSG.common_title_monitor_maximum());
+ ListGridField maxField = new ListGridField(MAX_VALUE.getValue(),
MAX_VALUE.getLabel());
maxField.setWidth("15%");
fields.add(maxField);
- ListGridField avgField = new ListGridField(FIELD_AVG_VALUE,
MSG.common_title_monitor_average());
+ ListGridField avgField = new ListGridField(AVG_VALUE.getValue(),
AVG_VALUE.getLabel());
avgField.setWidth("15%");
fields.add(avgField);
- ListGridField liveField = new ListGridField(FIELD_LIVE_VALUE,
MSG.view_resource_monitor_table_live());
+ ListGridField liveField = new ListGridField(LIVE_VALUE.getValue(),
LIVE_VALUE.getLabel());
liveField.setWidth("15%");
fields.add(liveField);
- ListGridField alertsField = new ListGridField(FIELD_ALERT_COUNT,
MSG.common_title_alerts());
+ ListGridField alertsField = new ListGridField(ALERT_COUNT.getValue(),
ALERT_COUNT.getLabel());
alertsField.setWidth("10%");
fields.add(alertsField);
@@ -170,18 +158,18 @@ public class MetricsViewDataSource extends
RPCDataSource<MetricDisplaySummary, C
MeasurementUtility.formatSimpleMetrics(from);
ListGridRecord record = new ListGridRecord();
- record.setAttribute(FIELD_SPARKLINE,
getCsvMetricsForSparkline(from.getDefinitionId()));
- record.setAttribute(FIELD_METRIC_LABEL, from.getLabel());
- record.setAttribute(FIELD_ALERT_COUNT, String.valueOf(from.getAlertCount()));
- record.setAttribute(FIELD_MIN_VALUE, getMetricStringValue(from.getMinMetric()));
- record.setAttribute(FIELD_MAX_VALUE, getMetricStringValue(from.getMaxMetric()));
- record.setAttribute(FIELD_AVG_VALUE, getMetricStringValue(from.getAvgMetric()));
- record.setAttribute(FIELD_LIVE_VALUE, buildLiveValue(from));
- record.setAttribute(FIELD_METRIC_DEF_ID, from.getDefinitionId());
- record.setAttribute(FIELD_METRIC_SCHED_ID, from.getScheduleId());
- record.setAttribute(FIELD_METRIC_UNITS, from.getUnits());
- record.setAttribute(FIELD_METRIC_NAME, from.getMetricName());
- record.setAttribute(FIELD_RESOURCE_ID, resource.getId());
+ record.setAttribute(SPARKLINE.getValue(),
getCsvMetricsForSparkline(from.getDefinitionId()));
+ record.setAttribute(METRIC_LABEL.getValue(), from.getLabel());
+ record.setAttribute(ALERT_COUNT.getValue(),
String.valueOf(from.getAlertCount()));
+ record.setAttribute(MIN_VALUE.getValue(),
getMetricStringValue(from.getMinMetric()));
+ record.setAttribute(MAX_VALUE.getValue(),
getMetricStringValue(from.getMaxMetric()));
+ record.setAttribute(AVG_VALUE.getValue(),
getMetricStringValue(from.getAvgMetric()));
+ record.setAttribute(LIVE_VALUE.getValue(), buildLiveValue(from));
+ record.setAttribute(METRIC_DEF_ID.getValue(), from.getDefinitionId());
+ record.setAttribute(METRIC_SCHEDULE_ID.getValue(), from.getScheduleId());
+ record.setAttribute(METRIC_UNITS.getValue(), from.getUnits());
+ record.setAttribute(METRIC_NAME.getValue(), from.getMetricName());
+ record.setAttribute(RESOURCE_ID.getValue(), resource.getId());
return record;
}
diff --git
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/ResourceMetricAvailabilityView.java
b/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/ResourceMetricAvailabilityView.java
deleted file mode 100644
index 5919f83..0000000
---
a/modules/enterprise/gui/coregui/src/main/java/org/rhq/coregui/client/inventory/resource/detail/monitoring/table/ResourceMetricAvailabilityView.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright 2012, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.coregui.client.inventory.resource.detail.monitoring.table;
-
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.smartgwt.client.widgets.form.DynamicForm;
-import com.smartgwt.client.widgets.form.fields.FormItem;
-import com.smartgwt.client.widgets.form.fields.StaticTextItem;
-
-import org.rhq.core.domain.measurement.AvailabilityType;
-import org.rhq.core.domain.measurement.MeasurementUnits;
-import org.rhq.core.domain.resource.Resource;
-import org.rhq.core.domain.resource.composite.ResourceAvailabilitySummary;
-import org.rhq.coregui.client.CoreGUI;
-import org.rhq.coregui.client.components.table.TimestampCellFormatter;
-import org.rhq.coregui.client.gwt.GWTServiceLookup;
-import org.rhq.coregui.client.util.MeasurementConverterClient;
-import org.rhq.coregui.client.util.enhanced.EnhancedVLayout;
-
-/**
- * This shows the availability history for a resource.
- *
- * @author Jay Shaughnessy
- * @author John Mazzitelli
- * @author Mike Thompson
- */
-public class ResourceMetricAvailabilityView extends EnhancedVLayout {
-
- private Resource resource;
- private StaticTextItem currentField;
- private StaticTextItem availField;
- private StaticTextItem availTimeField;
- private StaticTextItem downField;
- private StaticTextItem downTimeField;
- private StaticTextItem disabledField;
- private StaticTextItem disabledTimeField;
- private StaticTextItem failureCountField;
- private StaticTextItem disabledCountField;
- private StaticTextItem mtbfField;
- private StaticTextItem mttrField;
- private StaticTextItem unknownField;
- private StaticTextItem currentTimeField;
-
- public ResourceMetricAvailabilityView(Resource resource) {
- super();
-
- this.resource = resource;
-
- setWidth100();
- setHeight(165);
- }
-
- @Override
- protected void onInit() {
- super.onInit();
-
- addMember(createSummaryForm());
- }
-
- private DynamicForm createSummaryForm() {
- DynamicForm form = new DynamicForm();
- form.setWidth100();
- form.setAutoHeight();
- form.setMargin(10);
- form.setNumCols(4);
-
- // row 1
- currentField = new StaticTextItem("current",
MSG.view_resource_monitor_availability_currentStatus());
- currentField.setWrapTitle(false);
- currentField.setColSpan(4);
-
- // row 2
- availField = new StaticTextItem("avail",
MSG.common_title_availability());
- availField.setWrapTitle(false);
- prepareTooltip(availField, MSG.view_resource_monitor_availability_tooltip_up());
-
- availTimeField = new StaticTextItem("availTime",
MSG.view_resource_monitor_availability_uptime());
- availTimeField.setWrapTitle(false);
- prepareTooltip(availTimeField,
MSG.view_resource_monitor_availability_uptime_tooltip());
-
- // row 3
- downField = new StaticTextItem("down",
MSG.common_status_avail_down_lower());
- downField.setWrapTitle(false);
- prepareTooltip(downField,
MSG.view_resource_monitor_availability_tooltip_down());
-
- downTimeField = new StaticTextItem("downTime",
MSG.view_resource_monitor_availability_downtime());
- downTimeField.setWrapTitle(false);
- prepareTooltip(downTimeField,
MSG.view_resource_monitor_availability_downtime_tooltip());
-
- // row 4
- disabledField = new StaticTextItem("disabled",
MSG.common_status_avail_disabled_lower());
- disabledField.setWrapTitle(false);
- prepareTooltip(disabledField,
MSG.view_resource_monitor_availability_tooltip_disabled());
-
- disabledTimeField = new StaticTextItem("disabledTime",
MSG.view_resource_monitor_availability_disabledTime());
- disabledTimeField.setWrapTitle(false);
- prepareTooltip(disabledTimeField,
MSG.view_resource_monitor_availability_disabledTime_tooltip());
-
- // row 5
- failureCountField = new StaticTextItem("failureCount",
MSG.view_resource_monitor_availability_numFailures());
- failureCountField.setWrapTitle(false);
- prepareTooltip(failureCountField,
MSG.view_resource_monitor_availability_numFailures_tooltip());
-
- disabledCountField = new StaticTextItem("disabledCount",
MSG.view_resource_monitor_availability_numDisabled());
- disabledCountField.setWrapTitle(false);
- prepareTooltip(disabledCountField,
MSG.view_resource_monitor_availability_numDisabled_tooltip());
-
- // row 6
- mtbfField = new StaticTextItem("mtbf",
MSG.view_resource_monitor_availability_mtbf());
- mtbfField.setWrapTitle(false);
- prepareTooltip(mtbfField,
MSG.view_resource_monitor_availability_mtbf_tooltip());
-
- mttrField = new StaticTextItem("mttr",
MSG.view_resource_monitor_availability_mttr());
- mttrField.setWrapTitle(false);
- prepareTooltip(mttrField,
MSG.view_resource_monitor_availability_mttr_tooltip());
-
- // row 7
- unknownField = new StaticTextItem("unknown");
- unknownField.setWrapTitle(false);
- unknownField.setColSpan(4);
- unknownField.setShowTitle(false);
-
- // row 8
- currentTimeField = new StaticTextItem("currentTime");
- currentTimeField.setWrapTitle(false);
- currentTimeField.setColSpan(4);
- currentTimeField.setShowTitle(false);
-
- form.setItems(currentField, availField, availTimeField, downField, downTimeField,
disabledField,
- disabledTimeField, failureCountField, disabledCountField, mtbfField,
mttrField, unknownField,
- currentTimeField);
-
- reloadSummaryData();
-
- return form;
- }
-
- private void reloadSummaryData() {
-
GWTServiceLookup.getResourceService().getResourceAvailabilitySummary(resource.getId(),
- new AsyncCallback<ResourceAvailabilitySummary>() {
-
- @Override
- public void onSuccess(ResourceAvailabilitySummary result) {
-
-
currentField.setValue(MSG.view_resource_monitor_availability_currentStatus_value(
- getAvailabilityTypeMessage(result.getCurrent()),
-
TimestampCellFormatter.format(result.getLastChange().getTime())));
-
availField.setValue(MeasurementConverterClient.format(result.getUpPercentage(),
- MeasurementUnits.PERCENTAGE, true));
- availTimeField.setValue(MeasurementConverterClient.format((double)
result.getUpTime(),
- MeasurementUnits.MILLISECONDS, true));
-
downField.setValue(MeasurementConverterClient.format(result.getDownPercentage(),
- MeasurementUnits.PERCENTAGE, true));
- downTimeField.setValue(MeasurementConverterClient.format((double)
result.getDownTime(),
- MeasurementUnits.MILLISECONDS, true));
-
disabledField.setValue(MeasurementConverterClient.format(result.getDisabledPercentage(),
- MeasurementUnits.PERCENTAGE, true));
- disabledTimeField.setValue(MeasurementConverterClient.format((double)
result.getDisabledTime(),
- MeasurementUnits.MILLISECONDS, true));
- failureCountField.setValue(result.getFailures());
- disabledCountField.setValue(result.getDisabled());
- mtbfField.setValue(MeasurementConverterClient.format((double)
result.getMTBF(),
- MeasurementUnits.MILLISECONDS, true));
- mttrField.setValue(MeasurementConverterClient.format((double)
result.getMTTR(),
- MeasurementUnits.MILLISECONDS, true));
-
- if (result.getUnknownTime() > 0L) {
-
unknownField.setValue(MSG.view_resource_monitor_availability_unknown(MeasurementConverterClient
- .format((double) result.getUnknownTime(),
MeasurementUnits.MILLISECONDS, true)));
- } else {
- unknownField.setValue("");
- }
-
-
currentTimeField.setValue(MSG.view_resource_monitor_availability_currentAsOf(TimestampCellFormatter
- .format(result.getCurrentTime())));
- }
-
- @Override
- public void onFailure(Throwable caught) {
- currentField.setValue(MSG.common_label_error());
- CoreGUI.getErrorHandler()
-
.handleError(MSG.view_resource_monitor_availability_summaryError(), caught);
- }
- });
- }
-
- private String getAvailabilityTypeMessage(AvailabilityType availabilityType) {
- switch (availabilityType) {
- case UP:
- return MSG.common_status_avail_up();
- case DOWN:
- return MSG.common_status_avail_down();
- case DISABLED:
- return MSG.common_status_avail_disabled();
- case UNKNOWN:
- default:
- return MSG.common_status_avail_unknown();
- }
- }
-
- private void prepareTooltip(FormItem item, String tooltip) {
- item.setHoverWidth(400);
- item.setPrompt(tooltip);
- }
-
-}
commit 20fccd49f29550e39fa89918f7e0c03aef65fb17
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Fri Dec 13 17:39:57 2013 +0100
[BZ 1042892] Don't use ${} notation for shell variables in CLI scripts.
As of BZ 959603, the files are subject to maven resource filtering and
so it can happen that the build server passes a variable to the build
process that clashes with the variable name defined in the script.
(Yes, this actually happened on our Jenkins server that passed
"-DCLASSPATH=" to the maven process for some reason, which resulted in
wonderful corruption of the rhq-cli.sh script).
diff --git a/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.sh
b/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.sh
index 112ec66..80f24c5 100755
--- a/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.sh
+++ b/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.sh
@@ -3,6 +3,14 @@
#===========================================================================
#
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# IMPORTANT: Avoid enclosing shell variables in braces using the ${XXX}
+# notation. This file is subject to maven resource variable expansion
+# during the build and so it can happen that the build environment
+# could corrupt this file by expanding variables that clash with
+# the names defined herein.
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
# RHQ_CLI_DEBUG - If this is defined, the script will emit debug
# messages. It will also enable debug
# messages to be emitted from the cli itself.
@@ -41,7 +49,7 @@
# to the CLI's defaults, then you will want to
# use RHQ_CLI_ADDITIONAL_JAVA_OPTS instead.
#
-#RHQ_CLI_JAVA_OPTS="-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-Drhq.scripting.modules.root-dir=${RHQ_CLI_MODULES_DIR}"
+#RHQ_CLI_JAVA_OPTS="-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-Drhq.scripting.modules.root-dir=$RHQ_CLI_MODULES_DIR"
# RHQ_CLI_JAVA_ENDORSED_DIRS - Java VM command line option to set the
# endorsed dirs for the CLI's VM. If this
diff --git a/modules/enterprise/remoting/cli/src/etc/rhq-cli.sh
b/modules/enterprise/remoting/cli/src/etc/rhq-cli.sh
index 8399b50..b0980e6 100644
--- a/modules/enterprise/remoting/cli/src/etc/rhq-cli.sh
+++ b/modules/enterprise/remoting/cli/src/etc/rhq-cli.sh
@@ -11,6 +11,14 @@
# set via rhq-client-env.sh, which is sourced by this script.
# =============================================================================
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# IMPORTANT: Avoid enclosing shell variables in braces using the ${XXX}
+# notation. This file is subject to maven resource variable expansion
+# during the build and so it can happen that the build environment
+# could corrupt this file by expanding variables that clash with
+# the names defined herein.
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
# ----------------------------------------------------------------------
# Subroutine that simply dumps a message iff debug mode is enabled
# ----------------------------------------------------------------------
@@ -42,16 +50,17 @@ esac
_DOLLARZERO=`readlink "$0" 2>/dev/null || echo "$0"`
RHQ_CLI_BIN_DIR_PATH=`dirname "$_DOLLARZERO"`
-if [ -f "${RHQ_CLI_BIN_DIR_PATH}/rhq-cli-env.sh" ]; then
- debug_msg "Loading environment script:
${RHQ_CLI_BIN_DIR_PATH}/rhq-cli-env.sh"
- . "${RHQ_CLI_BIN_DIR_PATH}/rhq-cli-env.sh" $*
+if [ -f "$RHQ_CLI_BIN_DIR_PATH/rhq-cli-env.sh" ]; then
+ debug_msg "Loading environment script:
$RHQ_CLI_BIN_DIR_PATH/rhq-cli-env.sh"
+ . "$RHQ_CLI_BIN_DIR_PATH/rhq-cli-env.sh" $*
else
- debug_msg "No environment script found at:
${RHQ_CLI_BIN_DIR_PATH}/rhq-cli-env.sh"
+ debug_msg "No environment script found at:
$RHQ_CLI_BIN_DIR_PATH/rhq-cli-env.sh"
fi
# this variable is set during the build and defines the desired default behavior for
directory changing
# we do want to change the dir in RHQ, but possibly don't want to do that in JBoss ON
for backwards compatibility
# reasons.
+# (yes, this USES ${} in the source (not in the distribution) because we seed the default
value from the build)
RHQ_CLI_CHANGE_DIR_ON_START_DEFAULT=${rhq.cli.change-dir-on-start-default}
if [ -z "$RHQ_CLI_CHANGE_DIR_ON_START" ]; then
RHQ_CLI_CHANGE_DIR_ON_START="$RHQ_CLI_CHANGE_DIR_ON_START_DEFAULT"
@@ -61,24 +70,24 @@ fi
# Previous versions always changed directory.
if [ -n "$RHQ_CLI_CHANGE_DIR_ON_START" -a
"$RHQ_CLI_CHANGE_DIR_ON_START" != "false" ]; then
if [ -z "$RHQ_CLI_HOME" ]; then
- cd "${RHQ_CLI_BIN_DIR_PATH}/.."
+ cd "$RHQ_CLI_BIN_DIR_PATH/.."
else
- cd "${RHQ_CLI_HOME}" || {
- echo "Cannot go to the RHQ_CLI_HOME directory: ${RHQ_CLI_HOME}"
+ cd "$RHQ_CLI_HOME" || {
+ echo "Cannot go to the RHQ_CLI_HOME directory: $RHQ_CLI_HOME"
exit 1
}
fi
RHQ_CLI_HOME=`pwd`
else
if [ -z "$RHQ_CLI_HOME" ]; then
- RHQ_CLI_HOME="${RHQ_CLI_BIN_DIR_PATH}/.."
+ RHQ_CLI_HOME="$RHQ_CLI_BIN_DIR_PATH/.."
fi
#get an absolute path
RHQ_CLI_HOME=`readlink -f "$RHQ_CLI_HOME"`
if [ ! -d "$RHQ_CLI_HOME" ]; then
- echo "RHQ_CLI_HOME detected or defined as [${RHQ_CLI_HOME}] doesn't seem
to exist or is not a directory"
+ echo "RHQ_CLI_HOME detected or defined as [$RHQ_CLI_HOME] doesn't seem
to exist or is not a directory"
exit 1
fi
fi
@@ -90,7 +99,7 @@ debug_msg "RHQ_CLI_HOME: $RHQ_CLI_HOME"
# sample modules.
# ----------------------------------------------------------------------
if [ -z "$RHQ_CLI_MODULES_DIR" ]; then
- RHQ_CLI_MODULES_DIR="${RHQ_CLI_HOME}/samples/modules"
+ RHQ_CLI_MODULES_DIR="$RHQ_CLI_HOME/samples/modules"
fi
# ----------------------------------------------------------------------
@@ -110,7 +119,7 @@ fi
if [ -z "$RHQ_CLI_JAVA_EXE_FILE_PATH" ]; then
if [ -z "$RHQ_CLI_JAVA_HOME" ]; then
- RHQ_CLI_JAVA_HOME="${RHQ_CLI_HOME}/jre"
+ RHQ_CLI_JAVA_HOME="$RHQ_CLI_HOME/jre"
if [ -d "$RHQ_CLI_JAVA_HOME" ]; then
debug_msg "Using the embedded JRE"
else
@@ -119,7 +128,7 @@ if [ -z "$RHQ_CLI_JAVA_EXE_FILE_PATH" ]; then
fi
fi
debug_msg "RHQ_CLI_JAVA_HOME: $RHQ_CLI_JAVA_HOME"
- RHQ_CLI_JAVA_EXE_FILE_PATH=${RHQ_CLI_JAVA_HOME}/bin/java
+ RHQ_CLI_JAVA_EXE_FILE_PATH="$RHQ_CLI_JAVA_HOME/bin/java"
fi
debug_msg "RHQ_CLI_JAVA_EXE_FILE_PATH: $RHQ_CLI_JAVA_EXE_FILE_PATH"
@@ -133,14 +142,14 @@ fi
# Prepare the classpath (take into account possible spaces in dir names)
# ----------------------------------------------------------------------
-CLASSPATH="${RHQ_CLI_HOME}/conf"
-_JAR_FILES=`cd "${RHQ_CLI_HOME}/lib";ls -1 *.jar`
+CLASSPATH="$RHQ_CLI_HOME/conf"
+_JAR_FILES=`cd "$RHQ_CLI_HOME/lib";ls -1 *.jar`
for _JAR in $_JAR_FILES ; do
- _JAR="${RHQ_CLI_HOME}/lib/${_JAR}"
+ _JAR="$RHQ_CLI_HOME/lib/$_JAR"
if [ -z "$CLASSPATH" ]; then
- CLASSPATH="${_JAR}"
+ CLASSPATH="$_JAR"
else
- CLASSPATH="${CLASSPATH}:${_JAR}"
+ CLASSPATH="$CLASSPATH:$_JAR"
fi
debug_msg "CLASSPATH entry: $_JAR"
done
@@ -151,7 +160,7 @@ debug_msg "CLASSPATH entry: $_JAR"
# ----------------------------------------------------------------------
if [ -z "$RHQ_CLI_JAVA_OPTS" ]; then
- RHQ_CLI_JAVA_OPTS="-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-Drhq.scripting.modules.root-dir=${RHQ_CLI_MODULES_DIR}"
+ RHQ_CLI_JAVA_OPTS="-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-Drhq.scripting.modules.root-dir=$RHQ_CLI_MODULES_DIR"
fi
debug_msg "RHQ_CLI_JAVA_OPTS: $RHQ_CLI_JAVA_OPTS"
@@ -159,7 +168,7 @@ if [ "$RHQ_CLI_JAVA_ENDORSED_DIRS" = "none" ];
then
debug_msg "Not explicitly setting java.endorsed.dirs"
else
if [ -z "$RHQ_CLI_JAVA_ENDORSED_DIRS" ]; then
- RHQ_CLI_JAVA_ENDORSED_DIRS="${RHQ_CLI_HOME}/lib/endorsed"
+ RHQ_CLI_JAVA_ENDORSED_DIRS="$RHQ_CLI_HOME/lib/endorsed"
fi
# convert the path if on Windows
@@ -167,14 +176,14 @@ else
RHQ_CLI_JAVA_ENDORSED_DIRS=`cygpath --windows --path
"$RHQ_CLI_JAVA_ENDORSED_DIRS"`
fi
debug_msg "RHQ_CLI_JAVA_ENDORSED_DIRS: $RHQ_CLI_JAVA_ENDORSED_DIRS"
-
_JAVA_ENDORSED_DIRS_OPT="-Djava.endorsed.dirs=\"${RHQ_CLI_JAVA_ENDORSED_DIRS}\""
+
_JAVA_ENDORSED_DIRS_OPT="-Djava.endorsed.dirs=\"$RHQ_CLI_JAVA_ENDORSED_DIRS\""
fi
if [ "$RHQ_CLI_JAVA_LIBRARY_PATH" = "none" ]; then
debug_msg "Not explicitly setting java.library.path"
else
if [ -z "$RHQ_CLI_JAVA_LIBRARY_PATH" ]; then
- RHQ_CLI_JAVA_LIBRARY_PATH="${RHQ_CLI_HOME}/lib"
+ RHQ_CLI_JAVA_LIBRARY_PATH="$RHQ_CLI_HOME/lib"
fi
# convert the path if on Windows
@@ -182,7 +191,7 @@ else
RHQ_CLI_JAVA_LIBRARY_PATH=`cygpath --windows --path
"$RHQ_CLI_JAVA_LIBRARY_PATH"`
fi
debug_msg "RHQ_CLI_JAVA_LIBRARY_PATH: $RHQ_CLI_JAVA_LIBRARY_PATH"
-
_JAVA_LIBRARY_PATH_OPT="-Djava.library.path=\"${RHQ_CLI_JAVA_LIBRARY_PATH}\""
+
_JAVA_LIBRARY_PATH_OPT="-Djava.library.path=\"$RHQ_CLI_JAVA_LIBRARY_PATH\""
fi
debug_msg "RHQ_CLI_ADDITIONAL_JAVA_OPTS: $RHQ_CLI_ADDITIONAL_JAVA_OPTS"
@@ -201,8 +210,8 @@ if [ -n "$RHQ_CLI_DEBUG" ]; then
fi
# create the logs directory
-if [ ! -d "${RHQ_CLI_HOME}/logs" ]; then
- mkdir "${RHQ_CLI_HOME}/logs"
+if [ ! -d "$RHQ_CLI_HOME/logs" ]; then
+ mkdir "$RHQ_CLI_HOME/logs"
fi
# convert some of the paths if we are on Windows
@@ -220,15 +229,15 @@ fi
debug_msg "Executing the CLI with this command line:"
exit_code=0
if [ -z "$RHQ_CLI_CMDLINE_OPTS" ]; then
- debug_msg "${RHQ_CLI_JAVA_EXE_FILE_PATH} ${_JAVA_ENDORSED_DIRS_OPT}
${_JAVA_LIBRARY_PATH_OPT} ${RHQ_CLI_JAVA_OPTS} ${RHQ_CLI_ADDITIONAL_JAVA_OPTS}
${_LOG_CONFIG} -cp ${CLASSPATH} org.rhq.enterprise.client.ClientMain $@"
- "${RHQ_CLI_JAVA_EXE_FILE_PATH}" ${_JAVA_ENDORSED_DIRS_OPT}
${_JAVA_LIBRARY_PATH_OPT} ${RHQ_CLI_JAVA_OPTS} ${RHQ_CLI_ADDITIONAL_JAVA_OPTS}
${_LOG_CONFIG} -cp "${CLASSPATH}" org.rhq.enterprise.client.ClientMain
"$@"
+ debug_msg "$RHQ_CLI_JAVA_EXE_FILE_PATH $_JAVA_ENDORSED_DIRS_OPT
$_JAVA_LIBRARY_PATH_OPT $RHQ_CLI_JAVA_OPTS $RHQ_CLI_ADDITIONAL_JAVA_OPTS $_LOG_CONFIG -cp
$CLASSPATH org.rhq.enterprise.client.ClientMain $@"
+ "$RHQ_CLI_JAVA_EXE_FILE_PATH" $_JAVA_ENDORSED_DIRS_OPT
$_JAVA_LIBRARY_PATH_OPT $RHQ_CLI_JAVA_OPTS $RHQ_CLI_ADDITIONAL_JAVA_OPTS $_LOG_CONFIG -cp
"$CLASSPATH" org.rhq.enterprise.client.ClientMain "$@"
exit_code=$?
else
- debug_msg "${RHQ_CLI_JAVA_EXE_FILE_PATH} ${_JAVA_ENDORSED_DIRS_OPT}
${_JAVA_LIBRARY_PATH_OPT} ${RHQ_CLI_JAVA_OPTS} ${RHQ_CLI_ADDITIONAL_JAVA_OPTS}
${_LOG_CONFIG} -cp ${CLASSPATH} org.rhq.enterprise.client.ClientMain
${RHQ_CLI_CMDLINE_OPTS}"
- "${RHQ_CLI_JAVA_EXE_FILE_PATH}" ${_JAVA_ENDORSED_DIRS_OPT}
${_JAVA_LIBRARY_PATH_OPT} ${RHQ_CLI_JAVA_OPTS} ${RHQ_CLI_ADDITIONAL_JAVA_OPTS}
${_LOG_CONFIG} -cp "${CLASSPATH}" org.rhq.enterprise.client.ClientMain
${RHQ_CLI_CMDLINE_OPTS}
+ debug_msg "$RHQ_CLI_JAVA_EXE_FILE_PATH $_JAVA_ENDORSED_DIRS_OPT
$_JAVA_LIBRARY_PATH_OPT $RHQ_CLI_JAVA_OPTS $RHQ_CLI_ADDITIONAL_JAVA_OPTS $_LOG_CONFIG -cp
$CLASSPATH org.rhq.enterprise.client.ClientMain $RHQ_CLI_CMDLINE_OPTS"
+ "$RHQ_CLI_JAVA_EXE_FILE_PATH" $_JAVA_ENDORSED_DIRS_OPT
$_JAVA_LIBRARY_PATH_OPT $RHQ_CLI_JAVA_OPTS $RHQ_CLI_ADDITIONAL_JAVA_OPTS $_LOG_CONFIG -cp
"$CLASSPATH" org.rhq.enterprise.client.ClientMain $RHQ_CLI_CMDLINE_OPTS
exit_code=$?
fi
debug_msg "$0 done."
-exit ${exit_code}
+exit $exit_code
commit 38128d7a3a983f5ab2b41a8c8d159c6900f92508
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Dec 13 10:08:04 2013 +0100
No need to print the stack trace here - many systems do not have libvirt installed.
diff --git
a/modules/plugins/virt/src/main/java/org/rhq/plugins/virt/VirtualizationHostDiscoveryComponent.java
b/modules/plugins/virt/src/main/java/org/rhq/plugins/virt/VirtualizationHostDiscoveryComponent.java
index 749c4c1..98aca93 100644
---
a/modules/plugins/virt/src/main/java/org/rhq/plugins/virt/VirtualizationHostDiscoveryComponent.java
+++
b/modules/plugins/virt/src/main/java/org/rhq/plugins/virt/VirtualizationHostDiscoveryComponent.java
@@ -35,7 +35,7 @@ import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.plugins.virt.LibVirtConnection.HVInfo;
/**
- * Discovers Host and Guest information using
+ * Discovers Host and Guest information using
*/
public class VirtualizationHostDiscoveryComponent implements ResourceDiscoveryComponent,
ManualAddFacet {
@@ -68,7 +68,12 @@ public class VirtualizationHostDiscoveryComponent implements
ResourceDiscoveryCo
res.getPluginConfiguration().put(new
PropertySimple("connectionURI", virt.getConnectionURI()));
virt.close();
} catch (Throwable t) {
- log.warn("Can not load libvirt: " + t.getMessage(), t);
+ String message = t.getMessage();
+ if (t.getCause()!=null) {
+ message += ": " + t.getCause().getMessage();
+ }
+ log.warn("Can not load libvirt: " + message);
+
}
return res;
commit 5c69dea30c85ec9ce20510626775143113d6baea
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Thu Dec 12 22:17:25 2013 +0100
Check if the parent can be cast to JMXComponent before doing so.
diff --git
a/modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheDiscoveryComponent.java
b/modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheDiscoveryComponent.java
index 4d1eecf..b3fabfa 100644
---
a/modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheDiscoveryComponent.java
+++
b/modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheDiscoveryComponent.java
@@ -23,6 +23,7 @@
package org.rhq.plugins.jbosscache;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@@ -43,10 +44,10 @@ import org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent;
/**
* Discover JBossCache instances. The only way to detect them are to
* look for "*:cache-interceptor=CacheMgmtInterceptor,*" or
"*:treecache-interceptor=CacheMgmtInterceptor,*"
- * This is done in {@link MBeanResourceDiscoveryComponent}. We postprocess the result
here to
+ * This is done in {@link MBeanResourceDiscoveryComponent}. We postprocess the result
here to
* get the base MBean name (without the property for detection) to be able to use this
later and also
* for display purposes, as this is the MBean name the user set up in his MBean.
- *
+ *
* @author Heiko W. Rupp
*/
public class JBossCacheDiscoveryComponent extends
MBeanResourceDiscoveryComponent<JMXComponent<?>> {
@@ -60,6 +61,11 @@ public class JBossCacheDiscoveryComponent extends
MBeanResourceDiscoveryComponen
public Set<DiscoveredResourceDetails>
discoverResources(ResourceDiscoveryContext<JMXComponent<?>> context) {
ResourceContext parentCtx = context.getParentResourceContext();
+
+ if (!(parentCtx.getParentResourceComponent() instanceof JMXComponent)) {
+ return Collections.emptySet();
+ }
+
JMXComponent<JBossASServerComponent<?>> gparentComponent =
(JMXComponent<JBossASServerComponent<?>>)
parentCtx.getParentResourceComponent();
Set<DiscoveredResourceDetails> discovered =
super.performDiscovery(context.getDefaultPluginConfiguration(), gparentComponent,
context.getResourceType(), false);
commit 0eccf7d3e33e319d08a5dfcf56bbe0d67af16bcd
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Dec 12 22:43:55 2013 +0100
Better testability in the ModulesDirectoryScriptSourceProvider.
Also changed the default module path from "./samples/modules" to
"./modules". This should be safe with the fix for BZ 959603 which
causes the CLI to always pass the system property to load the modules
from. The new default path is less coupled with the FS layout of the CLI
distribution.
diff --git
a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProvider.java
b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProvider.java
index 0e46abe..6040e8e 100644
---
a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProvider.java
+++
b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProvider.java
@@ -30,13 +30,38 @@ import java.net.URI;
*/
public class ModulesDirectoryScriptSourceProvider extends FileSystemScriptSourceProvider
{
- private static final File ROOT_DIR = new
File(System.getProperty("rhq.scripting.modules.root-dir",
"./samples/modules"));
private static final String SCHEME = "modules";
-
+
+ private File rootDir;
+
+ /**
+ * Creates a new instance of module script source provider that looks for the module
sources in a directory
+ * specified by the "rhq.scripting.modules.root-dir" system property. If
none such exists, the default value
+ * is assumed to be "./modules".
+ */
public ModulesDirectoryScriptSourceProvider() {
+ this(new File(System.getProperty("rhq.scripting.modules.root-dir",
"./modules")));
+ }
+
+ /**
+ * Provided for testing purposes. A script source provider is only instantiated
through its no-arg constructor
+ * in the scripting environment.
+ *
+ * @param rootDir the root directory under which to locate module sources
+ */
+ public ModulesDirectoryScriptSourceProvider(File rootDir) {
super(SCHEME);
+ this.rootDir = rootDir;
}
-
+
+ public File getRootDir() {
+ return rootDir;
+ }
+
+ public void setRootDir(File rootDir) {
+ this.rootDir = rootDir;
+ }
+
@Override
protected File getFile(URI location) {
String path = location.getPath();
@@ -44,6 +69,6 @@ public class ModulesDirectoryScriptSourceProvider extends
FileSystemScriptSource
//remove the leading /
path = path.substring(1);
- return new File(ROOT_DIR, path);
+ return new File(rootDir, path);
}
}
diff --git
a/modules/enterprise/remoting/cli/src/test/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProviderTest.java
b/modules/enterprise/remoting/cli/src/test/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProviderTest.java
new file mode 100644
index 0000000..4060d07
--- /dev/null
+++
b/modules/enterprise/remoting/cli/src/test/java/org/rhq/enterprise/client/script/ModulesDirectoryScriptSourceProviderTest.java
@@ -0,0 +1,67 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.enterprise.client.script;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.junit.BeforeClass;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lukas Krejci
+ * @since 4.10.0
+ */
+@Test
+public class ModulesDirectoryScriptSourceProviderTest {
+
+ private File scriptFile;
+
+ @BeforeClass
+ public void createScriptFile() throws IOException {
+ scriptFile = File.createTempFile("modules-test", ".js", new
File("."));
+ PrintWriter wrt = new PrintWriter(new FileOutputStream(scriptFile));
+ try {
+ wrt.write("var a = 2;");
+ } finally {
+ wrt.close();
+ }
+ }
+
+ @AfterClass
+ public void deleteScriptFile() {
+ scriptFile.delete();
+ }
+
+ public void testLoad() throws URISyntaxException {
+ ModulesDirectoryScriptSourceProvider provider = new
ModulesDirectoryScriptSourceProvider(new File("."));
+
+ File f = provider.getFile(new URI("modules:/" +
scriptFile.getName()));
+
+ assertEquals(f, scriptFile, "Unexpected file loaded");
+ }
+}
commit cb4a44d91636ff2fb298b7b9dff8dfed723bf2fc
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Dec 12 23:10:14 2013 +0100
[BZ 959603] - Don't change CWD on CLI startup.
Since the very beginning of CLI, RHQ always changed the CWD to
$RHQ_CLI_HOME when starting up, which is rather strange and
non-standard.
To keep the backwards compatibility, the behavior can be toggled on
or off.
The default behavior can be changed in the build by setting the
rhq.cli.change-dir-on-start-default
property. In RHQ, this defaults to "false", causing RHQ to NOT change
directories when starting up the CLI anymore.
Further, the behavior can be toggled by the user by setting the
RHQ_CLI_CHANGE_DIR_ON_START environment variable to "true" (or any
other value but "false" actually) or "false" explicitly.
Additionally, a new environment variable called "RHQ_CLI_MODULES_DIR"
was added. This was necessary to not break the loading of the
provided CommonJS modules available in the
$RHQ_CLI_HOME/samples/modules directory if the CLI was started from
another directory.
By adding the new RHQ_CLI_MODULES_DIR, which is initialized to the
correct value if not provided externally, we correctly load the
sample modules with the additional benefit of easier change of the
modules location for the user (previously this was only possible
through
RHQ_CLI_ADDITIONAL_JAVA_OPTS="-Drhq.scripting.modules.root-dir=..."
, while now one only needs RHQ_CLI_MODULES_DIR=...).
diff --git a/modules/enterprise/remoting/cli/pom.xml
b/modules/enterprise/remoting/cli/pom.xml
index 7515110..296b490 100644
--- a/modules/enterprise/remoting/cli/pom.xml
+++ b/modules/enterprise/remoting/cli/pom.xml
@@ -13,7 +13,11 @@
<name>RHQ Enterprise Remote CLI</name>
<description>RHQ Enterprise Remote Command Line Interface</description>
-
+
+ <properties>
+
<rhq.cli.change-dir-on-start-default>false</rhq.cli.change-dir-on-start-default>
+ </properties>
+
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
@@ -78,7 +82,18 @@
</dependencies>
<build>
- <plugins>
+ <resources>
+ <resource>
+ <directory>src/etc</directory>
+ <filtering>true</filtering>
+
<targetPath>${project.build.outputDirectory}/../etc</targetPath>
+ </resource>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ </resources>
+
+ <plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
diff --git a/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.bat
b/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.bat
index d5d1189..dcf1ec8 100644
--- a/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.bat
+++ b/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.bat
@@ -37,7 +37,7 @@ rem CLI's defaults. If you only want to add
options
rem to the CLI's defaults, then you will want to
rem use RHQ_CLI_ADDITIONAL_JAVA_OPTS instead.
rem
-rem set RHQ_CLI_JAVA_OPTS=-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
+rem set RHQ_CLI_JAVA_OPTS=-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-Drhq.scripting.modules.root-dir="%RHQ_CLI_MODULES_DIR%"
rem RHQ_CLI_JAVA_ENDORSED_DIRS - Java VM command line option to set the
rem endorsed dirs for the CLI's VM. If this
@@ -74,3 +74,33 @@ rem line options and the ones specified
here will
rem be passed to the CLI.
rem
rem set RHQ_CLI_CMDLINE_OPTS=
+
+rem RHQ_CLI_CHANGE_DIR_ON_START - By setting this variable to true (or any
+rem other value than "false") you can make
RHQ
+rem change the directory to $RHQ_CLI_HOME when
+rem starting the CLI. When this variable is set
+rem to false, the current working directory is
+rem NOT changed when starting the CLI.
+rem
+rem If not set, this variable is understood
+rem to be: ${rhq.cli.change-dir-on-start-default}
+rem set RHQ_CLI_CHANGE_DIR_ON_START=true
+
+rem RHQ_CLI_MODULES_DIR - The default location from which to load CommonJS
+rem modules available through the "modules:/" scheme
+rem is $RHQ_CLI_HOME/samples/modules.
+rem Setting this variable to another value, causes
+rem the modules to be loaded from another location.
+rem
+rem Notice that this can be a relative path, too.
+rem For example, setting:
+rem RHQ_CLI_MODULES_DIR=./modules
+rem would cause the CLI to load modules from the
+rem "modules" subdirectory of whichever current
+rem working directory it is started from.
+rem (See RHQ_CLI_JAVA_OPTS and
+rem RHQ_CLI_CHANGE_DIR_ON_START variables above for
+rem further details of this approach).
+rem
+rem set RHQ_CLI_MODULE_DIR=Z:\company-wide\rhq\cli\modules
+
diff --git a/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.sh
b/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.sh
index 2c0affa..112ec66 100755
--- a/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.sh
+++ b/modules/enterprise/remoting/cli/src/etc/rhq-cli-env.sh
@@ -41,7 +41,7 @@
# to the CLI's defaults, then you will want to
# use RHQ_CLI_ADDITIONAL_JAVA_OPTS instead.
#
-#RHQ_CLI_JAVA_OPTS="-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true"
+#RHQ_CLI_JAVA_OPTS="-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-Drhq.scripting.modules.root-dir=${RHQ_CLI_MODULES_DIR}"
# RHQ_CLI_JAVA_ENDORSED_DIRS - Java VM command line option to set the
# endorsed dirs for the CLI's VM. If this
@@ -78,3 +78,33 @@
# be passed to the CLI.
#
#RHQ_CLI_CMDLINE_OPTS=""
+
+# RHQ_CLI_CHANGE_DIR_ON_START - By setting this variable to true (or any
+# other value than "false") you can make RHQ
+# change the directory to $RHQ_CLI_HOME when
+# starting the CLI. When this variable is set
+# to false, the current working directory is
+# NOT changed when starting the CLI.
+#
+# If not set, this variable is understood
+# to be: ${rhq.cli.change-dir-on-start-default}
+#RHQ_CLI_CHANGE_DIR_ON_START=true
+
+# RHQ_CLI_MODULES_DIR - The default location from which to load CommonJS
+# modules available through the "modules:/" scheme
+# is $RHQ_CLI_HOME/samples/modules.
+# Setting this variable to another value, causes
+# the modules to be loaded from another location.
+#
+# Notice that this can be a relative path, too.
+# For example, setting:
+# RHQ_CLI_MODULES_DIR=./modules
+# would cause the CLI to load modules from the
+# "modules" subdirectory of whichever current
+# working directory it is started from.
+# (See RHQ_CLI_JAVA_OPTS and
+# RHQ_CLI_CHANGE_DIR_ON_START variables above for
+# further details of this approach).
+#
+#RHQ_CLI_MODULE_DIR=/opt/company-wide/rhq/cli/modules
+
diff --git a/modules/enterprise/remoting/cli/src/etc/rhq-cli.bat
b/modules/enterprise/remoting/cli/src/etc/rhq-cli.bat
index 8c96ed7..13dd762 100644
--- a/modules/enterprise/remoting/cli/src/etc/rhq-cli.bat
+++ b/modules/enterprise/remoting/cli/src/etc/rhq-cli.bat
@@ -20,13 +20,6 @@ if "%RHQ_CLI_DEBUG%" == "false" (
set RHQ_CLI_DEBUG=
)
-rem ----------------------------------------------------------------------
-rem Change directory so the current directory is the CLI home.
-rem Here we assume this script is a child directory of the CLI home
-rem We also assume our custom environment script is located in the same
-rem place as this script.
-rem ----------------------------------------------------------------------
-
set RHQ_CLI_BIN_DIR_PATH=%~dp0
if exist "%RHQ_CLI_BIN_DIR_PATH%\rhq-cli-env.bat" (
@@ -36,11 +29,38 @@ if exist "%RHQ_CLI_BIN_DIR_PATH%\rhq-cli-env.bat" (
if defined RHQ_CLI_DEBUG echo No environment script found at:
%RHQ_CLI_BIN_DIR_PATH%\rhq-cli-env.bat
)
-rem if debug variable is set, it is assumed to be on, unless its value is false
+rem this variable is set during the build and defines the desired default behavior for
directory changing
+rem we do want to change the dir in RHQ, but possibly don't want to do that in JBoss
ON for backwards compatibility
+rem reasons.
+set RHQ_CLI_CHANGE_DIR_ON_START_DEFAULT=${rhq.cli.change-dir-on-start-default}
+
+if not defined RHQ_CLI_CHANGE_DIR_ON_START (
+ set RHQ_CLI_CHANGE_DIR_ON_START=%RHQ_CLI_CHANGE_DIR_ON_START_DEFAULT%
+)
+
+rem RHQ_CLI_CHANGE_DIR_ON_START behaves the same as RHQ_CLI_DEBUG - if set, it is assumed
on, unless equal to false
+if "%RHQ_CLI_CHANGE_DIR_ON_START%" == "false" (
+ set RHQ_CLI_CHANGE_DIR_ON_START=
+)
+
+rem if debug variable is set, it is assumed to be on, unless its value is false (do this
again after we've loaded
+rem the env script)
if "%RHQ_CLI_DEBUG%" == "false" (
set RHQ_CLI_DEBUG=
)
+rem ----------------------------------------------------------------------
+rem Change directory so the current directory is the CLI home.
+rem Here we assume this script is a child directory of the CLI home
+rem We also assume our custom environment script is located in the same
+rem place as this script.
+rem ----------------------------------------------------------------------
+
+rem since RHQ 4.10.0 we don't change the directory to the RHQ_CLI_HOME by default
+if not defined RHQ_CLI_CHANGE_DIR_ON_START (
+ pushd .
+)
+
if not defined RHQ_CLI_HOME (
cd "%RHQ_CLI_BIN_DIR_PATH%\.."
) else (
@@ -52,9 +72,22 @@ if not defined RHQ_CLI_HOME (
set RHQ_CLI_HOME=%CD%
+rem since RHQ 4.10.0 we don't change the directory to the RHQ_CLI_HOME by default
+if not defined RHQ_CLI_CHANGE_DIR_ON_START (
+ popd
+)
+
if defined RHQ_CLI_DEBUG echo RHQ_CLI_HOME: %RHQ_CLI_HOME%
rem ----------------------------------------------------------------------
+rem Prepare the modules:/ script source provider to by default load our
+rem sample modules.
+rem ----------------------------------------------------------------------
+if not defined RHQ_CLI_MODULES_DIR (
+ set RHQ_CLI_MODULES_DIR="%RHQ_CLI_HOME%\samples\modules"
+)
+
+rem ----------------------------------------------------------------------
rem Find the Java executable and verify we have a VM available
rem Note that RHQ_CLI_JAVA_* props are still handled for back compat
rem ----------------------------------------------------------------------
@@ -105,7 +138,7 @@ rem Prepare the VM command line options to be passed in
rem ----------------------------------------------------------------------
if not defined RHQ_CLI_JAVA_OPTS (
- set RHQ_CLI_JAVA_OPTS=-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
+ set RHQ_CLI_JAVA_OPTS=-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-Drhq.scripting.modules.root-dir="%RHQ_CLI_MODULES_DIR%"
)
if defined RHQ_CLI_DEBUG echo RHQ_CLI_JAVA_OPTS: %RHQ_CLI_JAVA_OPTS%
diff --git a/modules/enterprise/remoting/cli/src/etc/rhq-cli.sh
b/modules/enterprise/remoting/cli/src/etc/rhq-cli.sh
index 9fce451..8399b50 100644
--- a/modules/enterprise/remoting/cli/src/etc/rhq-cli.sh
+++ b/modules/enterprise/remoting/cli/src/etc/rhq-cli.sh
@@ -49,20 +49,51 @@ else
debug_msg "No environment script found at:
${RHQ_CLI_BIN_DIR_PATH}/rhq-cli-env.sh"
fi
-if [ -z "$RHQ_CLI_HOME" ]; then
- cd "${RHQ_CLI_BIN_DIR_PATH}/.."
-else
- cd "${RHQ_CLI_HOME}" || {
- echo "Cannot go to the RHQ_CLI_HOME directory: ${RHQ_CLI_HOME}"
- exit 1
- }
+# this variable is set during the build and defines the desired default behavior for
directory changing
+# we do want to change the dir in RHQ, but possibly don't want to do that in JBoss ON
for backwards compatibility
+# reasons.
+RHQ_CLI_CHANGE_DIR_ON_START_DEFAULT=${rhq.cli.change-dir-on-start-default}
+if [ -z "$RHQ_CLI_CHANGE_DIR_ON_START" ]; then
+ RHQ_CLI_CHANGE_DIR_ON_START="$RHQ_CLI_CHANGE_DIR_ON_START_DEFAULT"
fi
-RHQ_CLI_HOME=`pwd`
+# Only change the directory on start when told so. This is new in RHQ 4.10.0.
+# Previous versions always changed directory.
+if [ -n "$RHQ_CLI_CHANGE_DIR_ON_START" -a
"$RHQ_CLI_CHANGE_DIR_ON_START" != "false" ]; then
+ if [ -z "$RHQ_CLI_HOME" ]; then
+ cd "${RHQ_CLI_BIN_DIR_PATH}/.."
+ else
+ cd "${RHQ_CLI_HOME}" || {
+ echo "Cannot go to the RHQ_CLI_HOME directory: ${RHQ_CLI_HOME}"
+ exit 1
+ }
+ fi
+ RHQ_CLI_HOME=`pwd`
+else
+ if [ -z "$RHQ_CLI_HOME" ]; then
+ RHQ_CLI_HOME="${RHQ_CLI_BIN_DIR_PATH}/.."
+ fi
+
+ #get an absolute path
+ RHQ_CLI_HOME=`readlink -f "$RHQ_CLI_HOME"`
+
+ if [ ! -d "$RHQ_CLI_HOME" ]; then
+ echo "RHQ_CLI_HOME detected or defined as [${RHQ_CLI_HOME}] doesn't seem
to exist or is not a directory"
+ exit 1
+ fi
+fi
debug_msg "RHQ_CLI_HOME: $RHQ_CLI_HOME"
# ----------------------------------------------------------------------
+# Prepare the modules:/ script source provider to by default load our
+# sample modules.
+# ----------------------------------------------------------------------
+if [ -z "$RHQ_CLI_MODULES_DIR" ]; then
+ RHQ_CLI_MODULES_DIR="${RHQ_CLI_HOME}/samples/modules"
+fi
+
+# ----------------------------------------------------------------------
# If we are on a Mac and JAVA_HOME is not set, then set it to /usr
# as this is the default location.
# ----------------------------------------------------------------------
@@ -113,8 +144,6 @@ for _JAR in $_JAR_FILES ; do
fi
debug_msg "CLASSPATH entry: $_JAR"
done
-_JAR="${RHQ_CLI_HOME}/jbossws-native-dist/deploy/lib/jbossws-client.jar"
-CLASSPATH="${CLASSPATH}:${_JAR}"
debug_msg "CLASSPATH entry: $_JAR"
# ----------------------------------------------------------------------
@@ -122,7 +151,7 @@ debug_msg "CLASSPATH entry: $_JAR"
# ----------------------------------------------------------------------
if [ -z "$RHQ_CLI_JAVA_OPTS" ]; then
- RHQ_CLI_JAVA_OPTS="-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true"
+ RHQ_CLI_JAVA_OPTS="-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-Drhq.scripting.modules.root-dir=${RHQ_CLI_MODULES_DIR}"
fi
debug_msg "RHQ_CLI_JAVA_OPTS: $RHQ_CLI_JAVA_OPTS"
diff --git a/modules/enterprise/remoting/cli/src/main/scripts/rhq-client.build.xml
b/modules/enterprise/remoting/cli/src/main/scripts/rhq-client.build.xml
index 1836e9f..a752037 100644
--- a/modules/enterprise/remoting/cli/src/main/scripts/rhq-client.build.xml
+++ b/modules/enterprise/remoting/cli/src/main/scripts/rhq-client.build.xml
@@ -26,7 +26,7 @@
<target name="prepare-bin-dir">
<echo>*** Populating bin scripts...</echo>
<copy verbose="true" toDir="${bin.home}">
- <fileset dir="${basedir}/src/etc/" includes="rhq-cli*.*"
/>
+ <fileset dir="${basedir}/target/etc/"
includes="rhq-cli*.*" />
</copy>
<chmod dir="${bin.home}" perm="ug+rx"
includes="*.sh" />
</target>
commit eac6f82d17db5bba902f57e11851d0bb7a2d9ad0
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Dec 12 13:43:56 2013 +0100
Removing old WS client files from CLI codebase
diff --git a/modules/enterprise/remoting/cli/src/etc/Remoting_Setup.txt
b/modules/enterprise/remoting/cli/src/etc/Remoting_Setup.txt
deleted file mode 100644
index 10bf3dc..0000000
--- a/modules/enterprise/remoting/cli/src/etc/Remoting_Setup.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-# Steps to build and run Remoting CLI:
-
-i) Checkout RHQ
-
-ii) Enable [rhq_source]/modules/enterprise/client/src/main/java as a java source
directory for your ide. For eclipse users, 'use as source folder'
-
-iii) Build RHQ from [rhq_source] and enable the Webservice endpoints by passing in the
following additional parameter at build time:
- -Drhq.server.enable.ws
-
-iv) Run rhq as normal and after startup, verify that your webservices are deployed at
http://[server]:7080/jbossws/services
-
-v) Until we figure out how to correctly fit this client side portion into the maven
build, or even if, the following will need to be done in your IDE/Dev environment to get
the client side JAXB generated types to run the following steps successfully. Jay is
tasked with Maven-izing it.
- a) Open up a shell and navigate to [rhq_source]/modules/enterprise/client/src/ and run
generate-jaxb-client-types.sh/bat script to generate all JAXB types to ./output directory.
- b) Add ./output directory to the top of your classpath setup in your IDE.
- c) Add the XStream 1.2.2 library from your maven repository to the classpath for your
project as well.
- d) Download JLine 0.9.94 library and add it to the classpath for your project as
well.
-
-vi) Run the test suite (currently incomplete and we'll be enhancing it as we move
forward) by:
- a)Log into the RHQ GUI client and create a new WS test user, u:ws-test p:ws-test and
the "Super User" Role.
- b)You should be able to startup XMLClientMainTest.java from you IDE and run it as a
junit test.
-
-
-Notes:
--i) Take extra care that the classes that you are using for the exposed SLSBs are coming
out of the 'org.rhq.enterprise.server.ws' package only. Any components that are
using types NOT from these client side JAXB elements is using server side types which we
do NOT want to do. We need to continue to operate as a pure JAXB client so that we most
closely mimic the operating environment for all WS* clients.
-
-ii) Sometimes it is helpful when debugging the webservice interface to see what the
client side or server side type actually looks like as XML. XStream, while inefficient
for serializing arbitrary java object trees, is much less picky about serializing these
object trees so you can get a quick picture of a given object. JAXB typically will not
serialize unless you do some extra coding.
-
-
-iii) After jaxb type generation may need to:
-
- A)
-Navigate to org.rhq.enterprise.server.ws.ContentManagerRemote.getPackageTypes and change
-
-throws ResourceTypeNotFoundException_Exception
- to
-throws ResourceTypeNotFoundException
-
- B) Navigate to and change
-public class ResourceTypeNotFoundException {
- to
-public class ResourceTypeNotFoundException extends Throwable {
-
- C) Delete the ResourceTypeNotFoundException_Exception class.
diff --git a/modules/enterprise/remoting/cli/src/etc/build.xml
b/modules/enterprise/remoting/cli/src/etc/build.xml
deleted file mode 100644
index 6aa91c1..0000000
--- a/modules/enterprise/remoting/cli/src/etc/build.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<project name="RHQ Remoting" basedir="."
default="jar">
-
- <!--location that JAXB remote ws types are compiled to -->
- <property name="rhq-jaxb-types-location"
- location="${basedir}/output"/>
-
- <!--location that RHQ client classes are compiled to -->
- <property name="rhq-remote-classes"
- location="${basedir}/bin"/>
-
- <!--location for JLine dependency -->
- <property name="jline-jar"
- location="C:/installers/Jline/jline-0.9.94/jline-0.9.94.jar"/>
-
- <!-- -->
- <property name="repo" location="C:/Documents and
Settings/Simeon/.m2/repository"/>
-
- <!--location for Gnu-Getopt dependency -->
- <property name="gnu-jar"
- location="${repo}/gnu-getopt/getopt/1.0.13/getopt-1.0.13.jar"/>
-
- <!--location for Gnu-Getopt dependency -->
- <property name="i18-jar"
- location="${repo}/i18nlog/i18nlog/1.0.10/i18nlog-1.0.10.jar"/>
-
- <property name="runLocation" value="${basedir}/run"/>
-
- <path id="project.class.path">
- <pathelement location="${runLocation}/getopt-1.0.13.jar"/>
- <pathelement location="${runLocation}/remoting.jar"/>
- <pathelement location="${runLocation}/jline-0.9.94.jar"/>
- <pathelement location="${runLocation}/i18nlog-1.0.10.jar"/>
-<!-- <pathelement path="${java.class.path}/"/>
- <pathelement path="${additional.path}"/> -->
- </path>
-
-
- <!--This target bundles up the remoting elements as an
- executable jar
- -->
- <target name="jar" description="Make executable jar">
- <delete file="${runLocation}/remoting.jar"/>
- <jar destfile="${runLocation}/remoting.jar"
- basedir="${rhq-remote-classes}"
- includes="org/rhq/**"
- excludes="**/WsFindGroupsCommand.class"
- />
-
- <!-- Copy all necessary jars to that location too -->
- <copy tofile="${runLocation}/jline-0.9.94.jar"
file="${jline-jar}"/>
- <copy tofile="${runLocation}/getopt-1.0.13.jar"
file="${gnu-jar}"/>
- <copy tofile="${runLocation}/i18nlog-1.0.10.jar"
file="${i18-jar}"/>
- <copy tofile="${runLocation}/toRun.txt"
file="${basedir}/toRun.txt"/>
-<!-- <copy todir="${runLocation}">
- <fileset dir="src_dir" excludes="**/*.java"/>
- </copy> -->
-
- </target>
-
- <target name="zip" depends="jar">
- <delete file="${runLocation}/bundle.zip"/>
- <zip destfile="${runLocation}/bundle.zip"
- basedir="${runLocation}"
- />
- </target>
-
- <target name="run">
- <java classname="org.rhq.enterprise.client.ClientMain">
- <!-- <arg value="-h"/> -->
- <classpath refid="project.class.path">
- <!-- <pathelement refid="project.class.path"/>
- <pathelement path="${java.class.path}"/> -->
-
- </classpath>
- </java>
-
-
- </target>
-
-</project>
diff --git a/modules/enterprise/remoting/cli/src/etc/generate-jaxb-client-types.bat
b/modules/enterprise/remoting/cli/src/etc/generate-jaxb-client-types.bat
deleted file mode 100644
index 68e8706..0000000
--- a/modules/enterprise/remoting/cli/src/etc/generate-jaxb-client-types.bat
+++ /dev/null
@@ -1,16 +0,0 @@
-rem This script should consume all the wsdls and compile the JAXB types all
-rem into one directory.
-
-call ../../../../dev-container/jbossas/bin/wsconsume.bat -k
http://127.0.0.1:7080/rhq-rhq-server/RoleManagerBean?wsdl -p org.rhq.enterprise.server.ws
-
-call ../../../../dev-container/jbossas/bin/wsconsume.bat -k
http://127.0.0.1:7080/rhq-rhq-server/ContentManagerBean?wsdl -p
org.rhq.enterprise.server.ws
-
-call ../../../../dev-container/jbossas/bin/wsconsume.bat -k
http://127.0.0.1:7080/rhq-rhq-server/SubjectManagerBean?wsdl -p
org.rhq.enterprise.server.ws
-
-call ../../../../dev-container/jbossas/bin/wsconsume.bat -k
http://127.0.0.1:7080/rhq-rhq-server/OperationManagerBean?wsdl -p
org.rhq.enterprise.server.ws
-
-call ../../../../dev-container/jbossas/bin/wsconsume.bat -k
http://127.0.0.1:7080/rhq-rhq-server/RepoManagerBean?wsdl -p org.rhq.enterprise.server.ws
-
-call ../../../../dev-container/jbossas/bin/wsconsume.bat -k
http://127.0.0.1:7080/rhq-rhq-server/ConfigurationManagerBean?wsdl -p
org.rhq.enterprise.server.ws
-
-call ../../../../dev-container/jbossas/bin/wsconsume.bat -k
http://127.0.0.1:7080/rhq-rhq-server/ResourceManagerBean?wsdl -p
org.rhq.enterprise.server.ws
\ No newline at end of file
diff --git a/modules/enterprise/remoting/cli/src/etc/generate-jaxb-client-types.sh
b/modules/enterprise/remoting/cli/src/etc/generate-jaxb-client-types.sh
deleted file mode 100644
index f83293b..0000000
--- a/modules/enterprise/remoting/cli/src/etc/generate-jaxb-client-types.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-
-# This script should consume all the wsdls and compile the JAXB types all
-# into one directory.
-
-../../../../dev-container/jbossas/bin/wsconsume.sh -k
http://localhost:7080/rhq-rhq-server/RoleManagerBean?wsdl -p org.rhq.enterprise.server.ws
-
-../../../../dev-container/jbossas/bin/wsconsume.sh -k
http://localhost:7080/rhq-rhq-server/ContentManagerBean?wsdl -p
org.rhq.enterprise.server.ws
-
-../../../../dev-container/jbossas/bin/wsconsume.sh -k
http://localhost:7080/rhq-rhq-server/SubjectManagerBean?wsdl -p
org.rhq.enterprise.server.ws
-
-../../../../dev-container/jbossas/bin/wsconsume.sh -k
http://localhost:7080/rhq-rhq-server/OperationManagerBean?wsdl -p
org.rhq.enterprise.server.ws
-
-../../../../dev-container/jbossas/bin/wsconsume.sh -k
http://localhost:7080/rhq-rhq-server/RepoManagerBean?wsdl -p org.rhq.enterprise.server.ws
-
-../../../../dev-container/jbossas/bin/wsconsume.sh -k
http://localhost:7080/rhq-rhq-server/ConfigurationManagerBean?wsdl -p
org.rhq.enterprise.server.ws
-
-../../../../dev-container/jbossas/bin/wsconsume.sh -k
http://localhost:7080/rhq-rhq-server/ResourceManagerBean?wsdl -p
org.rhq.enterprise.server.ws
\ No newline at end of file
diff --git a/modules/enterprise/remoting/cli/src/etc/toRun.txt
b/modules/enterprise/remoting/cli/src/etc/toRun.txt
deleted file mode 100644
index a86a75b..0000000
--- a/modules/enterprise/remoting/cli/src/etc/toRun.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-java -cp getopt-1.0.13.jar:remoting.jar:jline-0.9.94.jar:i18nlog-1.0.9.jar
org.rhq.enterprise.client.ClientMain
-
-java -cp getopt-1.0.13.jar;remoting.jar;jline-0.9.94.jar;i18nlog-1.0.9.jar
org.rhq.enterprise.client.ClientMain
\ No newline at end of file
commit 40016f023129faf02dc0d591e3e0085d5cc46130
Author: Jirka Kremser <jkremser(a)redhat.com>
Date: Thu Dec 12 16:51:31 2013 +0100
[BZ 1040928] - User with default permissions sees his assigned resources as DOWN -
using the subjectManager.getOverlord() instead of the actual subject, because the live
resource availability should not require the MANAGE_SETTINGS permission.
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
index 8a78995..2351f08 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
@@ -2452,7 +2452,7 @@ public class ResourceManagerBean implements ResourceManagerLocal,
ResourceManage
try {
// first, quickly see if we can even ping the agent, if not, don't bother
trying to get the resource avail
- Agent agent = agentManager.getAgentByResourceId(subject, resourceId);
+ Agent agent = agentManager.getAgentByResourceId(subjectManager.getOverlord(),
resourceId);
if (agent == null) {
if (log.isDebugEnabled()) {
log.debug("Resource [" + resourceId + "] does not
exist or has no agent assigned");
commit a12716ee947628ad29f28cae5fbd34bf5d19984c
Author: John Sanda <jsanda(a)redhat.com>
Date: Thu Dec 12 10:14:12 2013 -0500
calculate bloom filters
diff --git
a/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
b/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
index 77c22fd..d185f56 100644
--- a/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
+++ b/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
@@ -24,8 +24,113 @@
var time = new Time();
+ function BloomFilter(keys) {
+ function BloomSpecification(k, bucketsPerElement) {
+ this.K = k;
+ this.bucketsPerElement = bucketsPerElement;
+ }
+
+ // This is taken directly from BloomCalculations.java
+ this.probs = [
+ [1.0], // dummy row representing 0 buckets per element
+ [1.0, 1.0], // dummy row representing 1 buckets per element
+ [1.0, 0.393, 0.400],
+ [1.0, 0.283, 0.237, 0.253],
+ [1.0, 0.221, 0.155, 0.147, 0.160],
+ [1.0, 0.181, 0.109, 0.092, 0.092, 0.101], // 5
+ [1.0, 0.154, 0.0804, 0.0609, 0.0561, 0.0578, 0.0638],
+ [1.0, 0.133, 0.0618, 0.0423, 0.0359, 0.0347, 0.0364],
+ [1.0, 0.118, 0.0489, 0.0306, 0.024, 0.0217, 0.0216, 0.0229],
+ [1.0, 0.105, 0.0397, 0.0228, 0.0166, 0.0141, 0.0133, 0.0135, 0.0145],
+ [1.0, 0.0952, 0.0329, 0.0174, 0.0118, 0.00943, 0.00844, 0.00819, 0.00846], //
10
+ [1.0, 0.0869, 0.0276, 0.0136, 0.00864, 0.0065, 0.00552, 0.00513, 0.00509],
+ [1.0, 0.08, 0.0236, 0.0108, 0.00646, 0.00459, 0.00371, 0.00329, 0.00314],
+ [1.0, 0.074, 0.0203, 0.00875, 0.00492, 0.00332, 0.00255, 0.00217, 0.00199,
0.00194],
+ [1.0, 0.0689, 0.0177, 0.00718, 0.00381, 0.00244, 0.00179, 0.00146, 0.00129,
0.00121, 0.0012],
+ [1.0, 0.0645, 0.0156, 0.00596, 0.003, 0.00183, 0.00128, 0.001, 0.000852,
0.000775, 0.000744], // 15
+ [1.0, 0.0606, 0.0138, 0.005, 0.00239, 0.00139, 0.000935, 0.000702, 0.000574,
0.000505, 0.00047, 0.000459],
+ [1.0, 0.0571, 0.0123, 0.00423, 0.00193, 0.00107, 0.000692, 0.000499, 0.000394,
0.000335, 0.000302, 0.000287, 0.000284],
+ [1.0, 0.054, 0.0111, 0.00362, 0.00158, 0.000839, 0.000519, 0.00036, 0.000275,
0.000226, 0.000198, 0.000183, 0.000176],
+ [1.0, 0.0513, 0.00998, 0.00312, 0.0013, 0.000663, 0.000394, 0.000264, 0.000194,
0.000155, 0.000132, 0.000118, 0.000111, 0.000109],
+ [1.0, 0.0488, 0.00906, 0.0027, 0.00108, 0.00053, 0.000303, 0.000196, 0.00014,
0.000108, 8.89e-05, 7.77e-05, 7.12e-05, 6.79e-05, 6.71e-05] // 20
+ ]; // the first column is a dummy column representing K=0.
+
+ var self = this;
+ var excess = 20;
+ var bitset_excess = 20;
+ var minBuckets = 2;
+ var minK = 1;
+ var optKPerBuckets = [];
+ var maxFalsePosProb = 0.01;
+
+
+ for (i = 0; i < this.probs.length; i++) {
+ var min = java.lang.Double.MAX_VALUE;
+ var prob = this.probs[i];
+ for (j = 0; j < prob.length; j++) {
+ if (prob[j] < min) {
+ min = prob[j];
+ optKPerBuckets[i] = Math.max(minK, j);
+ }
+ }
+ }
+
+ var bucketsPerElement = maxBucketsPerElement(keys);
+ var spec = computeBloomSpec(bucketsPerElement, maxFalsePosProb);
+ var numBits = (keys * spec.bucketsPerElement) + bitset_excess;
+ var wordCount = bits2words(numBits);
+
+ if (wordCount > java.lang.Integer.MAX_VALUE) {
+ throw "Bloom filter size is > 16GB, reduce the
bloom_filter_fp_chance";
+ }
+
+ var bytes = wordCount * 8;
+ this.size = bytes + 8;
+
+ function maxBucketsPerElement(numElements) {
+ numElements = Math.max(1, numElements);
+ var v = (java.lang.Long.MAX_VALUE - excess) / keys;
+ if (v < 1) {
+ throw "Cannot compute probabilities for " + numElements + "
elements.";
+ }
+ return Math.min(self.probs.length - 1, v);
+ }
+
+ // This is taken from BloomCalculations.java
+ function computeBloomSpec(maxBucketsPerElement, maxFalsePosProb) {
+ var maxK = self.probs[maxBucketsPerElement].length - 1;
+
+ // Handle the trivial cases
+ if(maxFalsePosProb >= self.probs[minBuckets][minK]) {
+ return new BloomSpecification(2, optKPerBuckets[2]);
+ }
+ if (maxFalsePosProb < self.probs[maxBucketsPerElement][maxK]) {
+ throw "Unable to satisfy " + maxFalsePosProb + " with " +
maxBucketsPerElement + " buckets per element";
+ }
+
+ // First find the minimal required number of buckets:
+ var bucketsPerElement = 2;
+ var K = optKPerBuckets[2];
+ while(self.probs[bucketsPerElement][K] > maxFalsePosProb){
+ bucketsPerElement++;
+ K = optKPerBuckets[bucketsPerElement];
+ }
+ // Now that the number of buckets is sufficient, see if we can relax K
+ // without losing too much precision.
+ while(self.probs[bucketsPerElement][K - 1] <= maxFalsePosProb) {
+ K--;
+ }
+ println('K = ' + K + ', bucketsPerElement = ' +
bucketsPerElement);
+ return new BloomSpecification(K, bucketsPerElement);
+ }
+
+ function bits2words(numBits) {
+ return (((numBits-1)>>>6)+1);
+ }
+ }
+
/**
- * Encapsulates sizing data for a set of rows, having the samae number of columns and
+ * Encapsulates sizing data for a set of rows, having the same number of columns and
* each column being the same size.
*/
function RowInfo() {
@@ -124,6 +229,7 @@
schedules) {
var table = new Table(name);
table.data = calculateData(schedules, columnSize, rowKeySize, duration);
+ table.bloomFilter = new BloomFilter(5).size;
util.foreach(table.data.rows, function(interval) {
var rowInfo = table.data.rows[interval];
@@ -216,8 +322,8 @@
var rowKeyValueSize = 4;
var columnNameSize = 8;
- return calculateMetricsTableSize('raw_metrics', columnSize, rowKeySize,
rowKeyValueSize, columnNameSize, time.week,
- schedules);
+ return calculateMetricsTableSize('raw_metrics', columnSize, rowKeySize,
rowKeyValueSize, columnNameSize,
+ time.week, schedules);
};
/**
@@ -261,4 +367,9 @@
exports.sizeOf24HourMetrics = function(schedules) {
return calculateAggregatesTableSize('twenty_four_hour_metrics', time.day *
365, schedules);
};
+
+ // exposed for testing
+ exports.bloomFilter = function(keys) {
+ return new BloomFilter(keys).size;
+ }
})();
\ No newline at end of file
commit 2fbc974a65c2b0331b52c81143d9821d755863a3
Author: John Sanda <jsanda(a)redhat.com>
Date: Wed Dec 11 17:03:35 2013 -0500
adding some usage docs
diff --git
a/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
b/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
index 77e78b7..77c22fd 100644
--- a/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
+++ b/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
@@ -5,6 +5,11 @@
* installs, some input, in terms of the numbers and types of resources, will have to be
provided in order to generate
* the estimates. Right now the module has functionality for generating the sizes of the
data and partition index files
* for the metrics tables (which does not include the metrics_index table).
+ *
+ * current usage (from CLI shell):
+ *
+ * $ storage = require('modules:/rhq.storage.sizing.js');
+ * $ results = storage.sizeOfRawMetrics({30000: 5, 60000: 5});
*/
(function() {
var util = require('modules:/util');
commit 3141f63345442240fc2cd3d90a996840dfb1e428
Author: John Sanda <jsanda(a)redhat.com>
Date: Wed Dec 11 16:59:10 2013 -0500
initial commit for storage sizing CLI script
diff --git
a/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
b/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
new file mode 100644
index 0000000..77e78b7
--- /dev/null
+++ b/modules/enterprise/remoting/cli/src/main/samples/modules/rhq.storage.sizing.js
@@ -0,0 +1,259 @@
+/**
+ * This module provides functionality to generate storage cluster sizing estimates. The
end goal is for it to support
+ * generating estimates for both existing and new installations. For existing
installations, the script will query
+ * the existing RHQ database to get the necessary metric schedule info needed to generate
the estimates. For new
+ * installs, some input, in terms of the numbers and types of resources, will have to be
provided in order to generate
+ * the estimates. Right now the module has functionality for generating the sizes of the
data and partition index files
+ * for the metrics tables (which does not include the metrics_index table).
+ */
+(function() {
+ var util = require('modules:/util');
+
+ function Time() {
+ this.second = 1000;
+ this.minute = this.second * 60;
+ this.hour = this.minute * 60;
+ this.day = this.hour * 24;
+ this.week = this.day * 7;
+ }
+
+ var time = new Time();
+
+ /**
+ * Encapsulates sizing data for a set of rows, having the samae number of columns and
+ * each column being the same size.
+ */
+ function RowInfo() {
+ // The total number of rows described by this RowInfo object
+ this.numRows = 0;
+ // The total number of columns contained in each row
+ this.numColumns = 0;
+ // The size of an individual row
+ this.rowSize = 0;
+ // The total size of all rows described by this RowInfo object
+ this.totalSize = 0;
+ }
+
+ /**
+ * Encapsulates sizing data for an RHQ table, e.g., raw_metrics, one_hour_metrics
+ */
+ function Table(name) {
+ // The name of the table
+ this.name = name;
+ // The size of the partition index component
+ this.partitionIndex = 0;
+ // A Data object that corresponds to the Data component
+ this.data = null;
+ }
+
+ /**
+ * Encapsulates sizing info for the Data component
+ */
+ function Data() {
+ // A map of RowInfo objects. Keys are collection intervals while values are the
RowInfo
+ // objects. This mapping allows us to see what footprint on disk a particular
collection
+ // interval will have.
+ this.rows = {};
+ // The overall total size of the Data component.
+ this.totalSize = 0;
+ }
+
+ /**
+ * In order to calculate the data component size, we need to know the number of rows
and
+ * columns. The number of rows is the number of schedules. The number of columns is
+ * determined by the collection interval. Intermediate (per-row) results are grouped
by
+ * collection interval.
+ *
+ * @param schedules
+ * @param columnSize
+ * @param rowKeySize
+ * @param duration
+ * @returns data
+ */
+ var calculateData = function(schedules, columnSize, rowKeySize, duration) {
+ var data = new Data();
+
+ util.foreach(schedules, function(interval, numSchedules) {
+ var rowInfo = new RowInfo();
+ rowInfo.numColumns = duration / interval;
+ rowInfo.rowSize = (rowInfo.numColumns * columnSize) + rowKeySize;
+ rowInfo.numRows = numSchedules;
+ rowInfo.totalSize = rowInfo.rowSize * rowInfo.numRows;
+
+ data.rows[interval] = rowInfo;
+ data.totalSize = data.totalSize + rowInfo.totalSize;
+ });
+
+ return data;
+ };
+
+ var calculatePartitionIndex = function(keySize, rowSize, columnNameSize, numRows) {
+ var keyLength = 2;
+ var position = 8;
+ var promotedSize = 4;
+
+ if (rowSize < 65536) {
+ return (keyLength + keySize + position + promotedSize) * numRows;
+ }
+
+ var localDeletionTime = 4;
+ var markedForDeleteAt = 8;
+ var columnIndexSize =4;
+
+ // compute index entry size
+ var firstNameLen = 2;
+ var firstName = columnNameSize;
+ var lastNameLen = 2;
+ var lastName = columnNameSize;
+ var offset = 8;
+ var width = 8;
+ var columnIndexEntry = firstNameLen + firstName + lastNameLen + lastName + offset +
width;
+
+ var numColumnIndexEntries = Math.ceil(rowSize / 65536);
+
+ return (keyLength + keySize + position + promotedSize + localDeletionTime +
markedForDeleteAt + columnIndexSize +
+ (numColumnIndexEntries * columnIndexEntry)) * numRows;
+ };
+
+ var calculateMetricsTableSize = function(name, columnSize, rowKeySize, rowKeyValueSize,
columnNameSize, duration,
+ schedules) {
+ var table = new Table(name);
+ table.data = calculateData(schedules, columnSize, rowKeySize, duration);
+
+ util.foreach(table.data.rows, function(interval) {
+ var rowInfo = table.data.rows[interval];
+ table.partitionIndex += calculatePartitionIndex(rowKeyValueSize, rowInfo.rowSize,
columnNameSize, rowInfo.numRows);
+ });
+
+ return table;
+ };
+
+ var calculateAggregatesTableSize = function(name, duration, schedules) {
+ // Here is the break down the of the column size for aggregate metrics tables
+ //
+ // date component - 11 (see org.apache.cassandra.db.marshal.CompositeType for
more details on byte encoding
+ // type component - 7 byte encoding of composite types. In short, there are
an extran 3 bytes of overhead
+ // column name length - 2 per component.)
+ // flags - 1
+ // TTL - 4
+ // deletion time - 4
+ // timestamp - 8
+ // column value length - 4
+ // column value - 8
+ var columnSize = 49;
+
+ // See the rowKeySize for rawMetrics. The byte-wise break down is the same.
+ var rowKeySize = 30;
+
+ var columnNameSize = 18;
+ var rowKeyValueSize = 4;
+
+ // We have to multiply the column size by 3 because there are 3 values (i.e.,
columns)
+ // per aggregate metric.
+ return calculateMetricsTableSize(name, columnSize * 3, rowKeySize, rowKeyValueSize,
columnNameSize, duration,
+ schedules);
+ };
+
+ exports.loadSchedules = function() {
+ var criteria = MeasurementScheduleCriteria();
+ criteria.addFilterEnabled(true);
+ criteria.addSortId(PageOrdering.ASC);
+ criteria.setPaging(0, 500);
+
+ var schedulesSummary = {};
+
+ util.foreach(criteria, function(schedule) {
+ var count = schedulesSummary[schedule.interval];
+ if (count == null) {
+ schedulesSummary[schedule.interval] = 1;
+ } else {
+ schedulesSummary[schedule.interval] = count + 1;
+ }
+ });
+
+ return schedulesSummary;
+ };
+
+ exports.time = new Time();
+
+ /**
+ * Calculates SSTable component files sizes for the raw_metrics table for a set of
schedules.
+ *
+ * @param schedules A map of collection intervals to the number of schedules for each
+ * interval. It is assumed that counts include only enabled schedules.
+ *
+ * @returns Table
+ */
+ exports.sizeOfRawMetrics = function(schedules) {
+ // Here is a byte-wise break down for the overall column size
+ //
+ // column name length - 2
+ // column name - 8
+ // flags - 1
+ // TTL - 4
+ // local deletion time - 4
+ // timestmap - 8
+ // column value length - 8
+ // column value - 8
+ var columnSize = 39;
+
+ //Here is a byte-wise break down for the row key. Note that this is the total row
key
+ // overhead, not just the length of the key itself.
+ //
+ // key length - 2
+ // key value - 4
+ // columns size - 8
+ // local deletion time - 4
+ // marked for delete at - 8
+ // column count - 4
+ var rowKeySize = 30;
+
+ var rowKeyValueSize = 4;
+ var columnNameSize = 8;
+
+ return calculateMetricsTableSize('raw_metrics', columnSize, rowKeySize,
rowKeyValueSize, columnNameSize, time.week,
+ schedules);
+ };
+
+ /**
+ * Calculates SSTable component files sizes for the one_hour_metrics table for a set of
schedules. Note that this
+ * method is exposed right now primarily for testing. Moreover, it is assumed that the
schedules argument is not the
+ * same as the one that would be passed to the sizeOfRawMetrics function.
+ *
+ * @param schedules A map of collection intervals to the number of schedules for each
+ * interval. It is assumed that counts include only enabled schedules.
+ *
+ * @returns Table
+ */
+ exports.sizeOf1HourMetrics = function(schedules) {
+ return calculateAggregatesTableSize('one_hour_metrics', time.day * 7,
schedules);
+ };
+
+ /**
+ * Calculates SSTable component files sizes for the six_hour_metrics table for a set of
schedules. Note that this
+ * method is exposed right now primarily for testing. Moreover, it is assumed that the
schedules argument is not the
+ * same as the one that would be passed to the sizeOfRawMetrics function.
+ *
+ * @param schedules A map of collection intervals to the number of schedules for each
+ * interval. It is assumed that counts include only enabled schedules.
+ *
+ * @returns Table
+ */
+ exports.sizeOf6HourMetrics = function(schedules) {
+ return calculateAggregatesTableSize('six_hour_metrics', time.day * 31,
schedules);
+ };
+
+ /**
+ * Calculates SSTable component files sizes for the twenty_four_hour_metrics table for
a set of schedules. Note that
+ * this method is exposed right now primarily for testing. Moreover, it is assumed that
the schedules argument is not
+ * the same as the one that would be passed to the sizeOfRawMetrics function.
+ *
+ * @param schedules A map of collection intervals to the number of schedules for each
+ * interval. It is assumed that counts include only enabled schedules.
+ *
+ * @returns Table
+ */
+ exports.sizeOf24HourMetrics = function(schedules) {
+ return calculateAggregatesTableSize('twenty_four_hour_metrics', time.day *
365, schedules);
+ };
+})();
\ No newline at end of file
commit f18d8e3d9467bbfb9da8b4afc86789d392cea803
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Tue Dec 10 16:02:27 2013 +0100
Bug 991202 - Excessive warnings of invalid metric calls
Fixed "*-exceeded" metrics dataType
Created new MemoryPoolComponent
Now gathering "usage-threshold-*" and
"collection-usage-threshold-*" metrics only if enabled
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/MemoryPoolComponent.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/MemoryPoolComponent.java
new file mode 100644
index 0000000..36939a5
--- /dev/null
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/MemoryPoolComponent.java
@@ -0,0 +1,88 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+package org.rhq.modules.plugins.jbossas7;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.rhq.core.domain.measurement.MeasurementDataTrait;
+import org.rhq.core.domain.measurement.MeasurementReport;
+import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
+import org.rhq.core.pluginapi.inventory.ResourceContext;
+
+/**
+ * @author Thomas Segismont
+ */
+public class MemoryPoolComponent extends BaseComponent<BaseComponent<?>> {
+
+ private static final String USAGE_THRESHOLD_PREFIX = "usage-threshold-";
+ private static final String USAGE_THRESHOLD_SUPPORTED_ATTRIBUTE =
USAGE_THRESHOLD_PREFIX + "supported";
+ private static final String COLLECTION_USAGE_THRESHOLD_PREFIX =
"collection-" + USAGE_THRESHOLD_PREFIX;
+ private static final String COLLECTION_USAGE_THRESHOLD_SUPPORTED_ATTRIBUTE =
COLLECTION_USAGE_THRESHOLD_PREFIX
+ + "supported";
+
+ private Boolean usageThresholdSupported;
+ private Boolean collectionUsageThresholdSupported;
+
+ @Override
+ public void start(ResourceContext<BaseComponent<?>> context) throws
Exception {
+ super.start(context);
+ usageThresholdSupported = readAttribute(getAddress(),
USAGE_THRESHOLD_SUPPORTED_ATTRIBUTE, Boolean.class);
+ collectionUsageThresholdSupported = readAttribute(getAddress(),
COLLECTION_USAGE_THRESHOLD_SUPPORTED_ATTRIBUTE,
+ Boolean.class);
+ }
+
+ @Override
+ public void stop() {
+ super.stop();
+ usageThresholdSupported = null;
+ collectionUsageThresholdSupported = null;
+ }
+
+ @Override
+ public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest>
metrics) throws Exception {
+ Set<MeasurementScheduleRequest> filteredMetrics = new
HashSet<MeasurementScheduleRequest>();
+ for (MeasurementScheduleRequest request : metrics) {
+ String requestName = request.getName();
+ if (USAGE_THRESHOLD_SUPPORTED_ATTRIBUTE.equals(requestName)) {
+ report.addData(new MeasurementDataTrait(request,
usageThresholdSupported.toString()));
+ continue;
+ }
+ if (requestName.startsWith(USAGE_THRESHOLD_PREFIX)) {
+ if (usageThresholdSupported) {
+ filteredMetrics.add(request);
+ }
+ continue;
+ }
+ if (COLLECTION_USAGE_THRESHOLD_SUPPORTED_ATTRIBUTE.equals(requestName)) {
+ report.addData(new MeasurementDataTrait(request,
collectionUsageThresholdSupported.toString()));
+ continue;
+ }
+ if (requestName.startsWith(COLLECTION_USAGE_THRESHOLD_PREFIX)) {
+ if (collectionUsageThresholdSupported) {
+ filteredMetrics.add(request);
+ }
+ continue;
+ }
+ filteredMetrics.add(request);
+ }
+ super.getValues(report, filteredMetrics);
+ }
+}
diff --git a/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml
b/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml
index 2dcf2bd..972e31f 100644
--- a/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml
@@ -7280,7 +7280,7 @@
<service name="Memory Pool Resource"
discovery="SubsystemDiscovery"
- class="BaseComponent"
+ class="MemoryPoolComponent"
description="The management interface for a memory pool. A memory
pool represents the memory resource managed by the Java virtual machine and is managed by
one or more memory managers.">
<plugin-configuration>
@@ -7299,7 +7299,7 @@
<metric property="collection-usage:committed"
displayName="Collection Usage - Committed" description="The amount of
memory in bytes that is committed for the Java virtual machine to use."/>
<metric property="collection-usage:max" displayName="Collection
Usage - Max" description="The maximum amount of memory in bytes that can be used
for memory management."/>
<metric property="collection-usage-threshold-count"
description="The number of times that the Java virtual machine has detected that the
memory usage has reached or exceeded the collection usage threshold. A memory pool may not
support a collection usage threshold. If
'collection-usage-threshold-supported', is
'false' trying to read this attribute via the
'read-attribute' operation will result in failure, and the value
of this attribute in the result of a 'read-resource' operation
will be 'undefined'."/>
- <metric property="collection-usage-threshold-exceeded"
description="Whether the memory usage of this memory pool after the most recent
collection on which the Java virtual machine has expended effort has reached or exceeded
its collection usage threshold. A memory pool may not support a collection usage
threshold. If
'collection-usage-threshold-supported', is
'false' trying to read this attribute via the
'read-attribute' operation will result in failure, and the value
of this attribute in the result of a 'read-resource' operation
will be 'undefined'."/>
+ <metric property="collection-usage-threshold-exceeded"
dataType="trait" description="Whether the memory usage of this memory pool
after the most recent collection on which the Java virtual machine has expended effort has
reached or exceeded its collection usage threshold. A memory pool may not support a
collection usage threshold. If
'collection-usage-threshold-supported', is
'false' trying to read this attribute via the
'read-attribute' operation will result in failure, and the value
of this attribute in the result of a 'read-resource' operation
will be 'undefined'."/>
<metric property="collection-usage-threshold-supported"
dataType="trait" description="Whether this memory pool supports a
collection usage threshold."/>
<metric property="name" dataType="trait"
description="The name representing this memory pool."/>
<metric property="peak-usage:init" displayName="Peak Usage -
Init" description="The amount of memory in bytes that the Java virtual machine
initially requests from the operating system for memory management."/>
@@ -7312,7 +7312,7 @@
<metric property="usage:committed" displayName="Usage -
Committed" description="The amount of memory in bytes that is committed for the
Java virtual machine to use."/>
<metric property="usage:max" displayName="Usage - Max"
description="The maximum amount of memory in bytes that can be used for memory
management."/>
<metric property="usage-threshold-count" description="The
number of times that the memory usage has crossed the usage threshold. A memory pool may
not support a usage threshold. If
'usage-threshold-supported', is
'false' trying to read this attribute via the
'read-attribute' operation will result in failure, and the value
of this attribute in the result of a 'read-resource' operation
will be 'undefined'."/>
- <metric property="usage-threshold-exceeded"
description="Whether the memory usage of this memory pool reaches or exceeds its
usage threshold value. A memory pool may not support a usage threshold. If
'usage-threshold-supported', is
'false' trying to read this attribute via the
'read-attribute' operation will result in failure, and the value
of this attribute in the result of a 'read-resource' operation
will be 'undefined'."/>
+ <metric property="usage-threshold-exceeded"
dataType="trait" description="Whether the memory usage of this memory pool
reaches or exceeds its usage threshold value. A memory pool may not support a usage
threshold. If 'usage-threshold-supported', is
'false' trying to read this attribute via the
'read-attribute' operation will result in failure, and the value
of this attribute in the result of a 'read-resource' operation
will be 'undefined'."/>
<metric property="usage-threshold-supported"
dataType="trait" description="Whether this memory pool supports usage
threshold."/>
<metric property="valid" dataType="trait"
description="Whether this memory pool is valid in the Java virtual machine. A memory
pool becomes invalid once the Java virtual machine removes it from the memory
system."/>
commit f796666a12533b74e3a1218125751a9b617177a2
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Tue Dec 10 15:33:28 2013 +0100
Further updated translations
diff --git
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_de.properties
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_de.properties
index 50e343f..2670220 100644
---
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_de.properties
+++
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_de.properties
@@ -528,7 +528,7 @@ view_aboutBox_version=Version
view_adminConfig_agentPlugins=Agent Plugins
view_adminConfig_alertDefTemplates=Vorlagen fÃŒr Alarmdefinitionen
view_adminConfig_downloads=Downloads
-view_adminConfig_driftDefTemplates=Vorlagen fÃŒr Dritf-Definitionen
+view_adminConfig_driftDefTemplates=Vorlagen fÃŒr Drift-Definitionen
view_adminConfig_ignoreResourceTypes=Ignorierte Ressource Typen
view_adminConfig_ignoreResourceTypes_changeTitle=Ãndern?
view_adminConfig_ignoreResourceTypes_confirmIgnore=Sind Sie sicher, dass Sie den
Ressourcentyp [{0}] ignorieren wollen? Sie werden nicht mehr in der Lage sein, Ressourcen
dieses Typs zu importieren und alle Ressourcen dieses Typs, die bereits im Inventar sind,
werden aus dem Inventar entfernt und Sie können diese nicht mehr verwalten.
@@ -554,11 +554,13 @@ view_adminRoles_assignedSubjects=Zugewisene Benutzer
view_adminRoles_failCreateRoleWithExistingName=Konnte die Rolle mit dem existierenden
Namen [{0}] nicht anlegen. Bitte wÀhlen Sie einen anderen Namen.
view_adminRoles_failLdap=Konnte nicht ermitteln, ob LDAP konfiguriert ist - gehe von
keiner LDAP-Konfiguration aus.
view_adminRoles_failLdapAvailableGroups=Fehlgeschlagen\: Kann Status fÃŒr letzten
AvailableGroups() Aufruf nicht abrufen.
+view_adminRoles_failLdapCancelling=Client kann nicht fortfahren. Storniere alle
zukÃŒnftigen verfÃŒgbaren GruppenstatusprÃŒfungen fÃŒr diesen Thread. Wahrscheinlich ist
ein Fehler bei der 1)LDAP Server Kommunikation oder der 2)ldap AnfrageprÃŒfung.
# #view_adminRoles_failLdapAvailableGroups = Konnte de LDAP-Gruppen nicht laden. Annahme
ist, dass es keine gibt.
# #view_adminRoles_failLdapCancelling = Konnte de LDAP-Gruppen nicht laden. Annahme ist,
dass es keine gibt.
view_adminRoles_failLdapGroups=Konnte de LDAP-Gruppen nicht laden. Annahme ist, dass es
keine gibt.
view_adminRoles_failLdapGroupsRole=Konnte die LDAP-Gruppen fÃŒr die Rolle nicht laden.
view_adminRoles_failLdapGroupsSettings=Konnte Systemeinstellungsinformationen fÃŒr
LDAP-Gruppen nicht abrufen.
+view_adminRoles_failLdapRetry=Versuch 3 Mal wiederholt. Storniere zukÃŒnftige verfÃŒgbare
Gruppenanfragen.
# #view_adminRoles_failLdapGroupsSettings = Konnte de LDAP-Gruppen nicht laden. Annahme
ist, dass es keine gibt.
# #view_adminRoles_failLdapRetry = Konnte de LDAP-Gruppen nicht laden. Annahme ist, dass
es keine gibt.
view_adminRoles_failRoles=Konnte die Rollen nicht laden.
@@ -584,6 +586,11 @@ view_adminRoles_ldapWarnTooManyResults=Es werden viele Ergebnisse
wiedergegeben.
view_adminRoles_noLdap=Die LDAP-Integration ist nicht konfiguriert. Um LDAP zu
konfigurieren, wechseln sie zu <a {0}>{1}</a>.
view_adminRoles_permissions_autoselecting_configureRead_implied=Autodeselected
CONFIGURE_WRITE permission, since lack of CONFIGURE_READ implies lack of it...
view_adminRoles_permissions_autoselecting_configureWrite_implied=Autoselected
CONFIGURE_READ permission, since CONFIGURE_WRITE implies it...
+view_adminRoles_permissions_autoselecting_manageBundleGroups_implied=Autoselect von View
Bundles (Bundles ansehen), das von Manage Bundle Groups (Bundle Gruppen verwalten)
gewÀhrt wird...
+view_adminRoles_permissions_autoselecting_manageBundle_implied=Autoselect nicht
gewÀhlter Berechtigungen, da Manage Bundle (Bundle verwalten) Berechtigung die
Berechtigungen Manage Bundle Groups (Bundle Gruppen verwalten), Create Bundles (Bundles
erstellen), Delete Bundles (Bundles löschen), View Bundles (Bundles ansehen) und
Deploy_Bundles (Bundles deployen) gewÀhrt...
+view_adminRoles_permissions_autoselecting_manageInventory_implied=Autoselect von nicht
gewÀhlten Ressourcen Berechtigungen, da MANAGE_INVENTORY alle Ressourcen Berechtigungen
voraussetzt...
+view_adminRoles_permissions_autoselecting_manageSecurity_implied=Autoselect von nicht
gewÀhlten Berechtigungen, da MANAGE_SECURITY alle anderen Berechtigungen voraussetzt...
+view_adminRoles_permissions_bundlePermissions=Bundle Berechtigungen
# #view_adminRoles_permissions_autoselecting_configureRead_implied = Autodeselected
CONFIGURE_WRITE permission, since lack of CONFIGURE_READ implies lack of it...
# #view_adminRoles_permissions_autoselecting_configureWrite_implied = Autoselected
CONFIGURE_READ permission, since CONFIGURE_WRITE implies it...
# #view_adminRoles_permissions_autoselecting_manageBundleGroups_implied = Autoselected
View Bundles, which is granted by Manage Bundle Groups...
@@ -592,6 +599,11 @@
view_adminRoles_permissions_autoselecting_configureWrite_implied=Autoselected CO
# #view_adminRoles_permissions_autoselecting_manageSecurity_implied = Autoselected
unselected permissions, since MANAGE_SECURITY implies all other permissions...
# #view_adminRoles_permissions_bundlePermissions = Bundle Permissions
view_adminRoles_permissions_globalPermissions=Globale Rechte
+view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection=Auswahl
der {0} Leseberechtigung kann nicht aufgehoben werden, wenn nicht die Auswahl der {0}
Schreibberechtigung (die die Leseberechtigung voraussetzt), zuerst aufgehoben wird.
+view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection=Auswahl
der {0} Berechtigung kann nicht aufgehoben werden, wenn nicht die Auswahl von Manage
Bundle Groups (Bundle Gruppen verwalten) (das die {0} Berechtigung voraussetzt), zuerst
aufgehoben wird.
+view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection=Auswahl der {0}
Berechtigung kann nicht aufgehoben werden, wenn nicht die Auswahl von Manage Bundle
(Bundle verwalten) (das alle Bundle Berechtigungen voraussetzt), zuerst aufgehoben wird.
+view_adminRoles_permissions_illegalDeselectionDueToManageInventorySelection=Auswahl der
{0} Berechtigung kann nicht aufgehoben werden, wenn nicht die Auswahl von Manage Inventory
(Inventar verwalten) (das alle Ressourcen Berechtigungen voraussetzt), zuerst aufgehoben
wird.
+view_adminRoles_permissions_illegalDeselectionDueToManageSecuritySelection=Auswahl der
{0} Berechtigung kann nicht aufgehoben werden, wenn nicht die Auswahl von Manage Security
Permission (Sicherheitsberechtigung verwalten) (die alle anderen Berechtigungen
voraussetzt), zuerst aufgehoben wird.
# #view_adminRoles_permissions_illegalDeselectionDueToCorrespondingWritePermSelection =
{0} read permission cannot be deselected, unless the {0} write permission, which implies
the read permission, is deselected first.
# #view_adminRoles_permissions_illegalDeselectionDueToManageBundleGroupsSelection = {0}
permission cannot be deselected, unless Manage Bundle Groups, which implies {0}
permission, is deselected first.
# #view_adminRoles_permissions_illegalDeselectionDueToManageBundleSelection = {0}
permission cannot be deselected, unless Manage Bundle, which implies all Bundle
permissions, is deselected first.
@@ -600,6 +612,15 @@ view_adminRoles_permissions_globalPermissions=Globale Rechte
view_adminRoles_permissions_isAuthorized=Berechtigt?
view_adminRoles_permissions_isRead=Lesen?
view_adminRoles_permissions_isWrite=Schreiben?
+view_adminRoles_permissions_permDesc_assignBundlesToGroup=Kann sichtbare Bundles in die
Bundle Gruppe kopieren
+view_adminRoles_permissions_permDesc_createBundles=kann neue Bundle [Version]en
erstellen. Kann sichtbare Bundles sichtbaren Gruppen zuweisen
+view_adminRoles_permissions_permDesc_createBundlesInGroup=kann neue Bundle [Version]en
fÃŒr die Bundle Gruppe erstellen. Kann sichtbare Bundles in die Bundle Gruppe kopieren.
+view_adminRoles_permissions_permDesc_deleteBundles=kann sichtbare Bundle [Version]en
löschen oder Zuweisung aufheben
+view_adminRoles_permissions_permDesc_deleteBundlesFromGroup=kann Bundle [Version]en aus
der Bundle Gruppe löschen (diese werden implizit aus anderen zugewiesenen Gruppen
gelöscht)
+view_adminRoles_permissions_permDesc_deployBundles=kann beliebige sichtbare Bundle
Version an beliebige sichtbare, deploybare, kompatible Ressourcengruppe deployen
+view_adminRoles_permissions_permDesc_deployBundlesToGroup=kann beliebige sichtbare Bundle
Version an die sichtbare, deploybare, kompatible Ressourcengruppe deployen
+view_adminRoles_permissions_permDesc_manageBundleGroups=kann Bundle Gruppen erstellen und
löschen. Kann Bundles Bundle Gruppen zuweisen. GewÀhrt View Bundles (Bundles ansehen)
Berechtigungen
+view_adminRoles_permissions_permDesc_manageBundles=kann beliebige Bundle Aufgabe
durchfÌhren. Eine Berechtigung, die Autoselect nicht gewÀhlter Berechtigungen, die
Berechtigungen Manage Bundle Groups (Bundle Gruppen verwalten), Create Bundles (Bundles
erstellen), Delete Bundles (Bundles löschen), View Bundles (Bundles ansehen) und
Deploy_Bundles (Bundles deployen) gewÀhrt...
# #view_adminRoles_permissions_permDesc_assignBundlesToGroup = can copy a viewable bundle
to the bundle group
# #view_adminRoles_permissions_permDesc_createBundles = can create new bundle [version]s.
can assign viewable bundles to viewable groups
# #view_adminRoles_permissions_permDesc_createBundlesInGroup = can create new bundle
[version]s for the bundle group. can copy a viewable bundle to the bundle group.
@@ -610,9 +631,14 @@ view_adminRoles_permissions_isWrite=Schreiben?
# #view_adminRoles_permissions_permDesc_manageBundleGroups = can create and delete bundle
groups. can assign bundles to bundle groups. grants View Bundles permissions
# #view_adminRoles_permissions_permDesc_manageBundles = can perform any bundle task. a
convenience permission that grants Manage Bundle Groups, Create Bundles, Delete Bundles,
Deploy Bundles and View Bundles permissions.
view_adminRoles_permissions_permDesc_manageInventory=Hat alle Rechte auf alle Ressourcen,
wie unten beschrieben. Kann Gruppen anlegen, aktualisieren und löschen. Kann Ressourcen
in das Inventar aufnehmen.
+view_adminRoles_permissions_permDesc_manageRepositories=kann Repositories jedes Benutzers
erstellen, aktualisieren oder löschen (jeder kann seine eigenen Repositories erstellen),
kann Content Quellen mit Repositories assoziieren.
# #view_adminRoles_permissions_permDesc_manageRepositories = can create, update, or
delete repositories of any user (everyone can create their own repositories), can
associate content sources to repositories.
view_adminRoles_permissions_permDesc_manageSecurity=Kann Benutzer und Rollen anlegen,
aktualisieren oder löschen (Anschauen ist fÌr alle implizit erlaubt)
view_adminRoles_permissions_permDesc_manageSettings=Kann die Konfiguration des
{0}-Servers Àndern und jegliche Server-bezogene FunktionalitÀt ausfÌhren.
+view_adminRoles_permissions_permDesc_unassignBundlesFromGroup=kann die Zuweisung eines
Bundles zu einer Bundle Gruppe aufheben (nicht löschen)
+view_adminRoles_permissions_permDesc_viewBundles=kann Bundle Details, Deployments, u.s.w.
fÃŒr jedes Bundle ansehen, einschlieÃlich nicht zugewiesener Bundles (die keiner Bundle
Gruppe zugewiesen sind)
+view_adminRoles_permissions_permDesc_viewBundlesInGroup=(VORAUSGESETZT) kann Bundle
Details, Deployments, u.s.w. fÃŒr jedes Bundle in Bundle Gruppen ansehen, die mit den
relevanten Rollen assoziiert sind.
+view_adminRoles_permissions_permDesc_viewUsers=kann andere Benutzer ansehen, mit Ausnahme
deren zugewiesener Rollen
# #view_adminRoles_permissions_permDesc_unassignBundlesFromGroup = can unassign (not
delete) a bundle from the bundle group
# #view_adminRoles_permissions_permDesc_viewBundles = can view bundle details,
deployments, etc for any bundle, including unassigned bundles (those not assigned to any
bundle group)
# #view_adminRoles_permissions_permDesc_viewBundlesInGroup = (IMPLIED) can view bundle
details, deployments, etc for any bundle in bundle groups associated with the relevant
roles.
@@ -641,12 +667,15 @@ view_adminRoles_permissions_perm_assignBundlesToGroup=Bundles zu
Gruppen zuweise
view_adminRoles_permissions_perm_configure=Konfiguration
view_adminRoles_permissions_perm_control=Operationen
view_adminRoles_permissions_perm_createBundles=Bundles anlegen
+view_adminRoles_permissions_perm_createBundlesInGroup=Bundles in Gruppe erstellen
# #view_adminRoles_permissions_perm_createBundlesInGroup = Create Bundles In Group
view_adminRoles_permissions_perm_createChildResources=Kind-Ressourcen erzeugen
view_adminRoles_permissions_perm_deleteBundles=Bundles löschen
+view_adminRoles_permissions_perm_deleteBundlesFromGroup=Bundles aus der Gruppe löschen
# #view_adminRoles_permissions_perm_deleteBundlesFromGroup = Delete Bundles From Group
view_adminRoles_permissions_perm_deleteChildResources=Löschen von Kind-Ressourcen
view_adminRoles_permissions_perm_deployBundles=Bundles deployen
+view_adminRoles_permissions_perm_deployBundlesToGroup=Bundles in die Gruppe deployen
# #view_adminRoles_permissions_perm_deployBundlesToGroup = Deploy Bundles To Group
view_adminRoles_permissions_perm_inventory=Inventar
view_adminRoles_permissions_perm_manageAlerts=Alarme verwalten
@@ -676,34 +705,74 @@ view_adminRoles_roleUpdateFailed=Konnte die Rolle [{0}] nicht
aktualisieren.
view_adminRoles_roleUpdated=Rolle [{0}] aktualisiert.
view_adminTemplates_definedBy=DDefiniert durch
view_adminTemplates_disabledTemplates=Inaktive Vorlagen
+view_adminTemplates_editAlertTemplate=Alarm Vorlage bearbeiten
view_adminTemplates_editTemplates=Vorlagen bearbeiten
view_adminTemplates_enabledTemplates=Aktive Vorlagen
+view_adminTemplates_platformServices=Plattform Dienste
view_adminTemplates_platforms=Platformen
view_adminTemplates_pluginTemplates=Vorlagen fÃŒr Plugins Plugins
+view_adminTemplates_prompt_disabledAlertTemplates=Anzahl von Alarm Vorlagen an diesem
Ressourcentyp, die erstellt aber deaktiviert sind
+view_adminTemplates_prompt_disabledMetricTemplates=Anzahl von metrischen ZeitplÀnen, die
standardmÀÃig an diesem Ressourcentyp deaktiviert sind
+view_adminTemplates_prompt_enabledAlertTemplates=Anzahl von Alarm Vorlagen an diesem
Ressourcentyp, die aktiviert sind
+view_adminTemplates_prompt_enabledMetricTemplates=Anzahl von metrischen ZeitplÀnen, die
standardmÀÃig an diesem Ressourcentyp aktiviert sind
view_adminTemplates_servers=Server
view_adminTemplates_userTemplates=Nutzers-spezifische Vorlagen
view_adminTopology_affinityGroups=AffinitÀtsgruppen
view_adminTopology_affinityGroups_agentCount=Anzahl Agenten
view_adminTopology_affinityGroups_agentsInThisGroup=Agenten in dieser Gruppe
+view_adminTopology_affinityGroups_agentsNotPartOfAnAffinityGroup=Agenten, die nicht Teil
einer Affinity Gruppe sind
+view_adminTopology_affinityGroups_agetnMembers=Agent Mitglieder
# #view_adminTopology_affinityGroups_agentsNotPartOfAnAffinityGroup = Agents not Part of
an Affinity Group
# #view_adminTopology_affinityGroups_agetnMembers = Agent Members
view_adminTopology_affinityGroups_createNew=Neu anlegen
+view_adminTopology_affinityGroups_details=Affinity Gruppen Details
# #view_adminTopology_affinityGroups_details = Affinity Group Details
view_adminTopology_affinityGroups_removeSelected=AusgewÀhlte entfernen
view_adminTopology_affinityGroups_serverCount=Anzahl Server
+view_adminTopology_affinityGroups_serverMembers=Server Mitglieder
# #view_adminTopology_affinityGroups_serverMembers = Server Members
view_adminTopology_agentDetail_address=Adresse
+view_adminTopology_agentDetail_agentFailoverList=Agent Failover Liste
# #view_adminTopology_agentDetail_agentFailoverList = Agent Failover List
view_adminTopology_agentDetail_currentServer=Aktueller Server
+view_adminTopology_agentDetail_remoteEndpoint=Remote Endpunkt
+view_adminTopology_agentDetail_token=Token
+view_adminTopology_agent_agentBindAddress=Agent Bind Adresse
+view_adminTopology_agent_agentBindPort=Agent Bind Port
# #view_adminTopology_agentDetail_token = Token
# #view_adminTopology_agent_agentBindAddress = Agent Bind Address
# #view_adminTopology_agent_agentBindPort = Agent Bind Port
view_adminTopology_agent_agentName=Name des Agenten
view_adminTopology_agent_connectedServer=Verbundener Server
+view_adminTopology_agent_delete_confirm=Dies hebt die Registrierung der gewÀhlten
Agenten auf und entfernt deren korrespondierende Plattformen und alle mit ihnen
assoziierten Ressourcen aus dem Inventar. Dieser Vorgang kann nicht rÌckgÀngig gemacht
werden. Sind Sie sicher, dass Sie dies tun möchten?
+view_adminTopology_agent_delete_error=Anfrage fÌr das Löschen der ausgewÀhlten Agenten
ist fehlgeschlagen
+view_adminTopology_agent_delete_submitted=[{0}] Agenten gelöscht und alle ihre
assoziierten Ressourcen dem Inventar entnommen.\n
+view_adminTopology_agent_lastAvailabilityPing=Letzter VerfÃŒgbarkeitsbericht-Ping
+view_adminTopology_agent_lastAvailabilityReport=Letzter VerfÃŒgbarkeitsbericht
# #view_adminTopology_agent_delete_confirm = This will deregister the selected agents and
uninventory their corresponding platforms and all other resources associated with them.
There is no way to undo this action. Are you sure you want to do this?
# #view_adminTopology_agent_lastAvailabilityPing = Last Availability Ping
# #view_adminTopology_agent_lastAvailabilityReport = Last Availability Report
view_adminTopology_agents=Agenten
+view_adminTopology_message_agentsCount=Es sind {0} Agenten bei diesem Server registriert.
Diese Anzahl stimmt nicht mit den derzeit verbundenen Agenten ÃŒberein.
+view_adminTopology_message_agroupAssingAgentsFail=Kann Agenten nicht der Affinity Gruppe
mit ID {0} zuweisen.
+view_adminTopology_message_agroupAssingServersFail=Kann Server nicht der Affinity Gruppe
mit ID {0} zuweisen.
+view_adminTopology_message_agroupRemovingAgentsFail=Kann Agenten nicht aus der Affinity
Gruppe mit ID {0} entfernen.
+view_adminTopology_message_agroupRemovingServersFail=Kann Server nicht aus der Affinity
Gruppe mit ID {0} entfernen.
+view_adminTopology_message_agroupRenamed=Affinity Gruppe mit ID {0} und Namen {1} wurde
umbenannt in {2}.
+view_adminTopology_message_agroupRenamingFail=Kann Affinity Gruppe mit ID {0} und Namen
{1} nicht umbenennen.
+view_adminTopology_message_fetchAgentFail=Kann Agent Details fÃŒr Agent mit ID {0} nicht
abrufen.
+view_adminTopology_message_fetchAgents2Fail=Kann Agenten nicht abrufen.
+view_adminTopology_message_fetchAgentsFail=Kann Agent(en) fÃŒr Affinity Gruppe mit ID {0}
nicht abrufen.
+view_adminTopology_message_fetchAgroupFail=Kann Affinity Gruppen Details mit ID {0} nicht
abrufen.
+view_adminTopology_message_fetchAgroupsFail=Kann Affinity Gruppe(n) nicht abrufen.
+view_adminTopology_message_fetchFailOverLists=Kann Fail Over Listen Details nicht
abrufen.
+view_adminTopology_message_fetchPEventDetailsFail=Kann Partitionsereignisdetails fÃŒr
Ereignis mit ID {0} nicht abrufen.
+view_adminTopology_message_fetchPEventFail=Kann Partitionsereignisse nicht abrufen.
+view_adminTopology_message_fetchServerFail=Kann Serverdetails fÃŒr Server mit ID {0}
nicht abrufen.
+view_adminTopology_message_fetchServers2Fail=Kann Server nicht abrufen.
+view_adminTopology_message_fetchServersFail=Kann Server fÃŒr Affinity Gruppe mit ID {0}
nicht abrufen.
+view_adminTopology_message_forceRepartition=Möchten Sie eine Repartitionierung des
gesamten Clusters wirklich erzwingen? It will force all the agents to connect to its most
preferred server.
+view_adminTopology_message_forceRepartitionFail=Kann keine Repartitionierung ausfÃŒhren.
# #view_adminTopology_message_agentsCount = There are {0} agents registered to this
server. This number doesn't correspond to the number of currently connected agents.
# #view_adminTopology_message_agroupAssingAgentsFail = Unable to assign agents to the
affinity group with id {0}.
# #view_adminTopology_message_agroupAssingServersFail = Unable to assign servers to the
affinity group with id {0}.
@@ -725,6 +794,22 @@ view_adminTopology_agents=Agenten
# #view_adminTopology_message_forceRepartition = Do you really want to force a
repartition of whole cluster? It will force all the agents to connect to its most
preferred server.
# #view_adminTopology_message_forceRepartitionFail = Unable to run repartition.
view_adminTopology_message_order=Reihenfolge
+view_adminTopology_message_removeAGroupsConfirm=Möchten Sie die folgenden Affinity
Gruppen {0} wirklich entfernen?
+view_adminTopology_message_removeAGroupsFail=Kann die folgende(n) Affinity Gruppe(n){0}
nicht entfernen.
+view_adminTopology_message_removeAllPEventConfirm=Möchten Sie wirklich alle
Partitionsereignisse bereinigen?
+view_adminTopology_message_removePEventConfirm=Möchten Sie die folgenden
Partitionsereignisse {0} wirklich entfernen?
+view_adminTopology_message_removePEventFail=Kann {0} Partitionsereignis(se) nicht
entfernen.
+view_adminTopology_message_removeServerConfirm=Möchten Sie die Server {0} wirklich
entfernen?
+view_adminTopology_message_removeServerFail=Kann {0} Server nicht entfernen.
+view_adminTopology_message_removedAGroups={0} Affinity Gruppe(n) entfernt.
+view_adminTopology_message_removedAllPEvent=Es wurden alle Partitionsereignisse
bereinigt.
+view_adminTopology_message_removedAllPEventFail=Kann nicht alle Partitionsereignisse
bereinigen.
+view_adminTopology_message_removedPEvent={0} Partitionsereignis(se) entfernt.
+view_adminTopology_message_removedServer={0} Server entfernt.
+view_adminTopology_message_repartitioned=Die Cluster Repartitionierung wurde erfolgreich
aufgerufen.
+view_adminTopology_message_serverUpdateFail=Kann Server {0} nicht aktualisieren.
+view_adminTopology_message_serverUpdated=Der Server {0} wurde erfolgreich aktualisiert.
+view_adminTopology_message_setMode={0} Server auf {1} Modus eingestellt.
# #view_adminTopology_message_removeAGroupsConfirm = Do you really want to remove
following affinity groups {0}?
# #view_adminTopology_message_removeAGroupsFail = Unable to remove following affinity
groups(s) {0}.
# #view_adminTopology_message_removeAllPEventConfirm = Do you really want to purge all
partition events?
@@ -744,12 +829,22 @@ view_adminTopology_message_order=Reihenfolge
view_adminTopology_message_setModeConfirm=Möchten Sie wirklich die Sever {0} in den
Zustand {1} bringen?
view_adminTopology_message_setModeFail=Konnte die Server {0} nicht in den Zustand {1}
bringen.
view_adminTopology_partitionEvents=Partitionierungs-Ereignisse
+view_adminTopology_partitionEventsDetail_agentAssignments=Agent Assignments
+view_adminTopology_partitionEventsDetail_agentAssignments_nothing=Es wurden keine Agenten
als Ergebnis dieses Partitionsereignisses erneut zugewiesen
+view_adminTopology_partitionEventsDetail_eventDetails=Ereignis Details
+view_adminTopology_partitionEventsDetail_eventExecutionTime=Ereignis AusfÃŒhrungszeit
+view_adminTopology_partitionEventsDetail_eventType=Ereignistyp
# #view_adminTopology_partitionEventsDetail_agentAssignments = Agent Assignments
# #view_adminTopology_partitionEventsDetail_agentAssignments_nothing = No agents were
reassigned as a result of this partition event
# #view_adminTopology_partitionEventsDetail_eventDetails = Event Details
# #view_adminTopology_partitionEventsDetail_eventExecutionTime = Event Execution Time
# #view_adminTopology_partitionEventsDetail_eventType = Event Type
view_adminTopology_partitionEvents_details=Details
+view_adminTopology_partitionEvents_detailsFilter=Filter fÃŒr Details
+view_adminTopology_partitionEvents_execStatusFilter=AusfÃŒhrungsstatus Filter
+view_adminTopology_partitionEvents_execTime=AusfÃŒhrungszeit
+view_adminTopology_partitionEvents_executionStatus=AusfÃŒhrungsstatus
+view_adminTopology_partitionEvents_forceRepartition=Repartitionierung erzwingen
# #view_adminTopology_partitionEvents_detailsFilter = Details Filter
# #view_adminTopology_partitionEvents_execStatusFilter = Execution Status Filter
# #view_adminTopology_partitionEvents_execTime = Execution Time
@@ -758,22 +853,33 @@ view_adminTopology_partitionEvents_details=Details
view_adminTopology_partitionEvents_initiatedBy=Initiiert durch
view_adminTopology_partitionEvents_purgeAll=Alle löschen
view_adminTopology_partitionEvents_type=Typ
+view_adminTopology_partitionEvents_typeFilter=Typ Filter
# #view_adminTopology_partitionEvents_typeFilter = Type Filter
view_adminTopology_remoteAgentInstall=Installation entfernter Agenten
+view_adminTopology_serverDetail_connectedAgents=Verbundene Agenten
+view_adminTopology_serverDetail_installationDate=Installationsdatum
+view_adminTopology_serverDetail_operationMode=Operationsmodus
+view_adminTopology_server_affinityGroup=Affinity Gruppe
# #view_adminTopology_serverDetail_connectedAgents = Connected Agents
# #view_adminTopology_serverDetail_installationDate = Installation Date
# #view_adminTopology_serverDetail_operationMode = Operation Mode
# #view_adminTopology_server_affinityGroup = Affinity Group
view_adminTopology_server_agentCount=Anzahl Agenten
+view_adminTopology_server_endpointAddress=Endpunkt-Adresse
+view_adminTopology_server_lastUpdateTime=Zeitpunkt der letzten Aktualisierung
# #view_adminTopology_server_endpointAddress = Endpoint Address
# #view_adminTopology_server_lastUpdateTime = Last Update Time
view_adminTopology_server_mode=Modus
+view_adminTopology_server_nonSecurePort=Ungesicherter Port
+view_adminTopology_server_removeSelected=Auswahl entfernen
+view_adminTopology_server_securePort=Gesicherter Port
# #view_adminTopology_server_nonSecurePort = Nonsecure Port
# #view_adminTopology_server_removeSelected = Remove Selected
# #view_adminTopology_server_securePort = Secure Port
view_adminTopology_server_setMaintenance=Wartung setzen
view_adminTopology_server_setNormal=Normalbetrieb setzen
view_adminTopology_servers=Server
+view_adminTopology_storageNode_jmxConnectionUrl=JMX Verbindung URL
# #view_adminTopology_storageNode_jmxConnectionUrl = JMX Connection URL
view_adminTopology_storageNodes=Speicherknoten
view_adminUsersDetails_dataTypeName=Benutzer
@@ -783,11 +889,18 @@ view_admin_configuration=Konfiguration
view_admin_content=Inhalte
view_admin_downloads_agentDownload=Agent Download
view_admin_downloads_agent_buildNumber=Build-Nummer des Agents
+view_admin_downloads_agent_help=<p> Dies ist die {0} Agent Update Binary jar Datei.
Diese jar Datei soll Ihnen die Installation eines frischen Agenten an einer Maschine
ermöglichen, an der noch kein Agent vorhanden ist und Ihnen auÃerdem die Aktualisierung
eines bereits an einer Maschine installierten Agenten ermöglichen. FÌr weitere
Informationen fÃŒhren Sie diese Agent Download jar mit der --help Befehlszeilenoption
aus\:<br/> <b>java -jar <agent-download.jar> --help</b>
</p> <h3>Agent Install</h3> <p> <b>java -jar
<agent-download.jar> --install[\=<new agent
directory>]</b><br/> Dieser Befehl installiert einen neuen Agent. Falls
Sie das neue Agentverzeichnis nicht festlegen, so lautet der Standard "."
</p> <h3>Agent Update</h3> <p> <b>java -jar
<agent-download.jar> --update[\=<old agent
home>]</b><br/> Dies aktualisiert einen vorhandenen Agent, der bereits
installiert war. Falls Sie das Verzeichnis nicht festlegen, in dem der altevorhande
ne Agent installiert war, so wird davon ausgegangen, dass es "rhq-agent" ist.
</p>
+view_admin_downloads_agent_link_value=Agent {0} ({1}) herunterladen
+view_admin_downloads_agent_loadError=Erhalt von Agenten Versionsinfo nicht möglich
# #view_admin_downloads_agent_help = <p> This is the {0} Agent Update Binary jar
file. The purpose of this jar file is to allow you to install a fresh agent on a machine
where an agent does not yet exist and to allow you to update an agent that is already
installed on a machine. For more details, run this agent download jar with the --help
command line option:<br/> <b>java -jar <agent-download.jar>
--help</b> </p> <h3>Agent Install</h3> <p> <b>java
-jar <agent-download.jar> --install[=<new agent
directory>]</b><br/> This command will install a new agent. If you do
not specify the new agent directory, the default will be "." </p>
<h3>Agent Update</h3> <p> <b>java -jar
<agent-download.jar> --update[=<old agent
home>]</b><br/> This will update an existing agent that was already
installed. If you do not specify the directory where the old, existing agent was
installed, it will assumed to be "rhq-agent". </p>
# #view_admin_downloads_agent_link_value = Download Agent {0} ({1})
# #view_admin_downloads_agent_loadError = Cannot get agent version info
view_admin_downloads_agent_md5=MD5 PrÃŒfsumme des Agents
view_admin_downloads_agent_version=Version des Agents
+view_admin_downloads_bundleDownload=Bundle Deployer Download
+view_admin_downloads_bundle_help=<p> Dies ist das Bundle Deployer Tool. Es dient
der Verwendung durch Entwickler und Verpacker von {0} Bundles. Dieses eigenstÀndige Tool
das Testen Ihrer Bundles und deren Anleitungen von einer Konsole. </p>
+view_admin_downloads_bundle_link_value=Bundle Deployer {0} herunterladen
+view_admin_downloads_bundle_loadError=Erhalt von Bundle Deployer Info nicht möglich
# #view_admin_downloads_bundleDownload = Bundle Deployer Download
# #view_admin_downloads_bundle_help = <p> This is the Bundle Deployer tool. It is
for use by developers and packagers of {0} bundles. This standalone tool allows you to
test your bundles and their recipes from a console. </p>
# #view_admin_downloads_bundle_link_value = Download Bundle Deployer {0}
@@ -796,6 +909,11 @@ view_admin_downloads_cliAlertScriptsDownload=Download von
CLI-Alarm-Skripten
view_admin_downloads_cliAlertScripts_help=CLI-Alarm-Skripte sind vorefertigete Skripte,
die als Vorlagen fÌr die Erstellung von Alert-Skripten genutzt werden können. Die
Skripte benötigen Ìblicherweise einiger Anpassungen bevore sie zur Benachrichtigun fÌr
eine spezifische Alarm-Definition genutzt werden können.
view_admin_downloads_cliAlertScripts_loadError=Kann keine Informationen ÃŒber
CLI-Alarm-Skripte fÃŒr den Download lesen
view_admin_downloads_cliAlertScripts_none=Es liegen keine CLI-Alarm-Skripte fÃŒr den
Download vor
+view_admin_downloads_cliDownload=Befehlszeilen Client Download
+view_admin_downloads_cli_buildNumber=CLI Build
+view_admin_downloads_cli_help=<p> Dies ist das Befehlszeilen Client Tool, auch
unter dem Namen CLI bekannt. Es handelt sich um ein eigenstÀndiges Tool das von innerhalb
einer Konsole lÀuft und ein Befehölszeilen Interface fÌr den {0} Server bereitstellt.
Sie können Befehle Ìber das CLI aufrufen und Skripte fÌr die DurchfÌhrung
automatisierter Aufgaben ausfÃŒhren. In der Dokumentation finden Sie weitere Informationen
zur Installation und Verwendung des CLI. </p>
+view_admin_downloads_cli_link_value=CLI {0} ({1}) herunterladen
+view_admin_downloads_cli_loadError=Erhalt von CLI Versionsinfo nicht möglich
# #view_admin_downloads_cliDownload = Command Line Client Download
# #view_admin_downloads_cli_buildNumber = CLI Build
# #view_admin_downloads_cli_help = <p> This is the Command Line Client tool,
otherwise known as the CLI. It is a standalone tool that runs from within a console and
provides a command line interface to the {0} Server. You can invoke commands via the CLI
as well as run scripts to perform automated tasks. See the documentation for more
information on how to install and use the CLI. </p>
@@ -803,6 +921,14 @@ view_admin_downloads_cliAlertScripts_none=Es liegen keine
CLI-Alarm-Skripte fÃŒr
# #view_admin_downloads_cli_loadError = Cannot get CLI version info
view_admin_downloads_cli_md5=MD5 PrÃŒfsumme des CLI
view_admin_downloads_cli_version=Version des CLI
+view_admin_downloads_connectorsDownload=Konnektoren Download
+view_admin_downloads_connectors_help=Bei Konnektoren handelt es sich um Software die
erforderlich ist, damit einige Produkte durch {0} verwaltet werden können. Konnektoren
werden in einige verwaltete Produkte installiert, damit {0} Agenten mit diesen
kommunizieren können. Weitere Informationen finden Sie in der Dokumentation.
+view_admin_downloads_connectors_loadError=Erhalt von Konnektoren Info nicht möglich
+view_admin_downloads_connectors_none=Keine Konnektoren zum Download verfÃŒgbar
+view_admin_downloads_scriptModulesDownload=Skript Module Download
+view_admin_downloads_scriptModules_help=<p> Skript Module sind wiederverwendbare
Komponenten, die von der RHQ bereitgestellt werden, um in Ihren Skripten verwendet zu
werden (entweder Alarm Skripte oder CLI Skripte). Sie können mittels des
"rhq\://downloads/<module-name-without-file-extension>" URI in der
Skriptsprache Ihrer Wahl darauf zugreifen (d.h. in javascript wÃŒrden Sie die
"require"-Funktion verwenden).</p>
+view_admin_downloads_scriptModules_loadError=Kann die Liste von verfÃŒgbaren
Skriptmodulen nicht laden
+view_admin_downloads_scriptModules_none=Keine Skriptmodule zum Download verfÃŒgbar
# #view_admin_downloads_connectorsDownload = Connectors Download
# #view_admin_downloads_connectors_help = Connectors are software that is needed in order
for some products to be manageable by {0}. You install connectors into some managed
products so {0} agents can talk to them. See the documentation for more information.
# #view_admin_downloads_connectors_loadError = Cannot get connectors info
@@ -813,6 +939,7 @@ view_admin_downloads_cli_version=Version des CLI
# #view_admin_downloads_scriptModules_none = No script modules are available for
download
view_admin_landing=In dieser Sektion können die globalen Einstellungen fÌr {0}
verwaltet werden. Dies schlieÃt Sicherheitseinstellungen und Plugins ein, sowie die
Verwaltung der {0} Server- und Agentplugins.
view_admin_measTemplates_updateExisting_title=Existierende ZeitplÀne aktualisieren
+view_admin_measTemplates_updateExisting_tooltip=Markieren Sie dieses KÀstchen, um die
Collection ZeitplÀne fÌr die gewÀhlten Metriken an allen Ressourcen dieses Typs zu
aktualisieren. Ist es nicht markiert, so werden die VorlagenzeitplÀne nur an neuen
Ressourcen dieses Typs angewendet, die zu einem spÀteren Zeitpunkt dem Inventar
hinzugefÃŒgt werden.
# #view_admin_measTemplates_updateExisting_tooltip = Check this box to update the
collection schedules for the selected metrics on all existing resources of this type. If
this is not checked, the template schedules will only be applied to new resources of this
type that are added to inventory in the future.
view_admin_plugins_agent=Agent
view_admin_plugins_agentDeleteConfirm=<b>Achtung\!</b><br/>\nDie
folgenden Agent-Plugins werden gelöscht\:<br/>\n{0}<br/>\nSind Sie sicher,
dass sie diese löschen wollen?
@@ -835,6 +962,10 @@ view_admin_plugins_purgedAgentPlugins=Das AufrÀumen der
Agent-Plugins {0} wird
view_admin_plugins_purgedAgentPluginsFailure=Konnte die Agent-Plugins nicht entfernen
view_admin_plugins_purgedServerPlugins=Server-Plugins {0} entfernt
view_admin_plugins_purgedServerPluginsFailure=Konnte die Server-Plugins nicht entfernen
+view_admin_plugins_restartMasterPC=Master Plugin Container neu starten
+view_admin_plugins_restartMasterPCComplete=Master Plugin Container wurde neu gestartet.
+view_admin_plugins_restartMasterPCFailure=Neustart von Master Plugin Container
fehlgeschlagen
+view_admin_plugins_restartMasterPCStarted=Starte Master Plugin Container neu...
# #view_admin_plugins_restartMasterPC = Restart Master Plugin Container
# #view_admin_plugins_restartMasterPCComplete = Master plugin container has been
restarted.
# #view_admin_plugins_restartMasterPCFailure = Failed to restart the master plugin
container
@@ -847,9 +978,12 @@ view_admin_plugins_serverConfig=Plugin-Konfiguration
view_admin_plugins_serverConfig_badSettings=Bitte geben Sie gÃŒltige Daten ein
view_admin_plugins_serverConfig_saveFailed=Konnte die Einstellungen nicht speichern
view_admin_plugins_serverConfig_settingsSaved=Die Einstellungen wurden gespeichert
+view_admin_plugins_serverControls=Steuerungen
# #view_admin_plugins_serverControls = Controls
view_admin_plugins_serverControls_badParams=Bitte geben Sie gÃŒltige Parameter an
view_admin_plugins_serverControls_clickForError=Klicken, um die Fehlermeldung anzuzeigen
+view_admin_plugins_serverControls_invokeFailure=Aufruf von Steuerung fehlgeschlagen
+view_admin_plugins_serverControls_name=Steuerung
# #view_admin_plugins_serverControls_invokeFailure = Failed to invoke the control
# #view_admin_plugins_serverControls_name = Control
view_admin_plugins_serverControls_parameters=Parameter
@@ -858,27 +992,95 @@
view_admin_plugins_serverDisableConfirm=<b>Achtung\!</b><br/>\nDie
folgenden Ser
view_admin_plugins_serverScheduleJobs=Geplante Aufgaben
view_admin_plugins_serverUndeployConfirm=<b>Achtung\!</b><br/>\nDie
folgenden Server-Plugins werden gelöscht\:<br/>\n{0}<br/>\nSind Sie sicher,
dass diese gelöscht werden sollen?
view_admin_plugins_showDeleted=Gelöschte anzeigen
+view_admin_plugins_showUndeployed=Undeployte anzeigen
+view_admin_plugins_undeploy=Undeployen
+view_admin_plugins_undeployedServerPlugins=Undeployte Server Plugins\: {0}
+view_admin_plugins_undeployedServerPluginsFailure=Konnte die Server-Plugins nicht
undeployen.
# #view_admin_plugins_showUndeployed = Show Undeployed
# #view_admin_plugins_undeploy = Undeploy
# #view_admin_plugins_undeployedServerPlugins = Undeployed server plugins: {0}
# #view_admin_plugins_undeployedServerPluginsFailure = Failed to undeploy server
plugins.
view_admin_plugins_upload=Plugin hochladen
view_admin_security=Sicherheit
+view_admin_systemSettings_ActiveDriftServerPlugin_desc=Der Drift Server Plugin der die
Persistenz von Drift-bezogenen Entities und Content verwaltet.
# #view_admin_systemSettings_ActiveDriftServerPlugin_desc = The drift server plugin that
manages the persistence of drift-related entities and content.
view_admin_systemSettings_ActiveDriftServerPlugin_name=Aktives Drift-Server-Plugin
+view_admin_systemSettings_AgentMaxQuietTimeAllowed_desc=Wenn diese Zeit ohne Reaktion vom
Agent verlÀuft, so wird dieser stille Agent als auÃer Betrieb angesehen. Der Wert ist in
Minuten festgelegt.
+view_admin_systemSettings_AgentMaxQuietTimeAllowed_name=Agent Max Ruhezeit gestattet
+view_admin_systemSettings_AlertPurge_desc=Wie alt Verlaufselemente sein mÃŒssen, ehe sie
aus der Datenbank bereinigt werden. Dies ist in Tagen festgelegt.
view_admin_systemSettings_AlertPurge_name=Bereinigen der Alarme, die Àlter sind als
+view_admin_systemSettings_AvailabilityPurge_desc=Wie alt VerfÃŒgbarkeitsdaten sein
mÃŒssen, ehe sie aus der Datenbank bereinigt werden. Dies ist in Tagen festgelegt.
view_admin_systemSettings_AvailabilityPurge_name=Lösche VerfÌgbarkeitsdaten, die Àlter
sind als
+view_admin_systemSettings_BaseURL_desc=Eine URL zum Server GUI, die hauptsÀchlich
innerhalb von Alarm E-Mail Benachrichtigungen verwendet wird.
+view_admin_systemSettings_BaseURL_name=GUI Konsole URL
+view_admin_systemSettings_BaselineDataSet_desc=Die Menge an vergangenen Messdaten, die
zur Bestimmung des Referenzbands verwendet werden. Dies ist in Tagen festgelegt.
+view_admin_systemSettings_BaselineDataSet_name=Referenzband Datensatz
+view_admin_systemSettings_BaselineFrequency_desc=Die HÀufigkeit mit der die
auto-calculation (Selbstberechnung) von ReferenzbÀndern durchgefÌhrt wird. Falls 0, so
ist die Referenzband auto-calculation deaktiviert. Dies ist in Tagen festgelegt.
Maximalwert ist 'Baseline Dataset' (Referenzband Datensatz).
+view_admin_systemSettings_BaselineFrequency_name=Referenzband BerechnungshÀufigkeit
+view_admin_systemSettings_DataMaintenance_desc=Wie oft die Datenbankwartung durchgefÃŒhrt
wird (zum Beispiel Vacuuming bei Verwendung von Postgres). Dies wird in Stunden
festgelegt.
+view_admin_systemSettings_DataMaintenance_name=Datenbankwartungszeitraum
+view_admin_systemSettings_DataReindex_desc=Wenn aktiviert, so werden bestimmte
Datenbanken periodisch neu indiziert.
+view_admin_systemSettings_DataReindex_name=Datentabellen jede Nacht neu indizieren
+view_admin_systemSettings_DriftFilePurge_desc=Wie alt nicht benutzte und verwaiste Drift
Dateien sein mÃŒssen, ehe sie aus dem Backend-Speicher bereinigt werden. Dies ist in Tagen
festgelegt.
# #view_admin_systemSettings_DriftFilePurge_desc = How old unused and orphaned drift
files must be before being purged from backend storage. This is specified in days.
view_admin_systemSettings_DriftFilePurge_name=Bereinige ungenutzte Drift-Dateine, die
Àlter sind als
+view_admin_systemSettings_EnableAgentAutoUpdate_desc=Legt fest, ob der Server Agents ein
auto-update (Selbstaktualisierung) gestattet. Ist dies deaktiviert, so können Sie keine
Agent Distributionen vom Server herunterladen.
+view_admin_systemSettings_EnableAgentAutoUpdate_name=Agenten Auto-Updates aktivieren
+view_admin_systemSettings_EnableDebugMode_desc=Falls aktiviert, so startet der Server den
Fehlerbehebungsmodus.
+view_admin_systemSettings_EnableDebugMode_name=Fehlerbehebungsmodus aktivieren
+view_admin_systemSettings_EnableExperimentalFeatures_desc=Falls aktiviert werden im
aktuellen Produkt vorhandene experimentelle Features verfÃŒgbar.
+view_admin_systemSettings_EnableExperimentalFeatures_name=Experimentelle Features
aktivieren
+view_admin_systemSettings_EventPurge_desc=Wie alt Ereignisdaten sein mÃŒssen, ehe sie aus
der Datenbank bereinigt werden. Dies ist in Tagen festgelegt.
+view_admin_systemSettings_EventPurge_name=Ereignisse löschen, die Àlter sind als
+view_admin_systemSettings_JAASProvider_desc=Sollte zur Bestimmung der BenutzeridentitÀt
LDAP verwendet werden?
+view_admin_systemSettings_JAASProvider_name=LDAP aktivieren
+view_admin_systemSettings_LDAPBaseDN_desc=Die Basis des Verzeichnisbaums zur Suche nach
Benutzernamen und Passwörter werden der Authentifizierung von Benutzern, z.B.
ou\=People,dc\=redhat,dc\=com
view_admin_systemSettings_LDAPBaseDN_name=Basis fÃŒr Suche
+view_admin_systemSettings_LDAPBindDN_desc=Der Benutzername zur Verbindung mit dem LDAP
Server bei der Abfrage der LDAP Benutzerdatenbank. Dies ist in der Regel der vollstÀndige
LDAP distinguierte Name (DN) eines Manager Benutzers, z.B. cn\=Manager,dc\=redhat,dc\=com
+view_admin_systemSettings_LDAPBindDN_name=Benutzername
+view_admin_systemSettings_LDAPBindPW_desc=Die Berechtigungsnachweise des Benutzers, die
fÃŒr die Verbindung mit dem LDAP-Server bei der Abfrage der LDAP Benutzerdatenbank
verwendet werden.
+view_admin_systemSettings_LDAPBindPW_name=Passwort
+view_admin_systemSettings_LDAPFilter_desc=Etwaige zusÀtzliche Filter, die bei der LDAP
Suche angewendet werden sollen. Dies ist nÃŒtzlich, wenn die Population zur
Authentifizierung ÃŒber eine gegebene LDAP Property identifiziert werden kann, z.B.
RHQUser\=true
+view_admin_systemSettings_LDAPFilter_name=Suchfilter
+view_admin_systemSettings_LDAPGroupFilter_desc=LDAP Suchfilter, der alle fÃŒr die
Autorisierung verfÃŒgbaren LDAP Gruppen wiedergeben muss. Dies wird fÃŒr LDAP
Gruppenautorisierung verwendet.
+view_admin_systemSettings_LDAPGroupFilter_name=Gruppen Suchfilter
+view_admin_systemSettings_LDAPGroupMember_desc=LDAP Suchfilter der in Verbindung mit dem
Gruppen Suchfilter zur Bestimmung der Benutzerberechtigung verwendet wird. Dies wird fÃŒr
die LDAP Gruppenautorisierung verwendet.
+view_admin_systemSettings_LDAPGroupMember_name=Gruppen Mitgliederfilter
+view_admin_systemSettings_LDAPGroupPageSize_desc=Um RFC 2696 zu unterstÃŒtzen wird dieser
LDAP Group Page Size Suchparameter in Verbindung mit anderen Gruppensuchparametern
verwendet, um die Anzahl von mit jedem Abfragenergebnis wiedergegebene Anzahl von
Gruppenmitgliedern einzuschrÀnken. Dieser Wert sollte so hoch wie möglich eingestellt
werden und zum Serverseiten maximalen SeitengröÃenwert um die besten Ergebnisse zu
erhalten. Values > (server max page size) hat keine Auswirkung. Verringern Sie diesen
Wert wenn LDAP Gruppenanfragen zu lange fÃŒr die Wiedergabe brauchen. Der Standard sind
1000 Ergebnisse.
+view_admin_systemSettings_LDAPGroupPageSize_name=Group Search Page Size (Gruppen Suche
Seiten GröÃe)
+view_admin_systemSettings_LDAPGroupUsePaging_desc=Definiert, ob LDAP Gruppenanfragen die
"Simple Paged Results" FunktionalitÀt (wie von RFC 2696 definiert) verwenden
sollten. Insbesondere bei die Anfrageergebnisse einschrÀnkenden LDAP Servern wird der
Client Seite fÃŒr Seite alle Ergebnisse in der Group Page Size (GruppenseitengröÃe)
durchgehen, bis er fertig ist. Standardeinstellung ist false.
+view_admin_systemSettings_LDAPGroupUsePaging_name=Verwendung von Group Query Paging
+view_admin_systemSettings_LDAPGroupUsePosixGroup_desc=Definiert, ob PosixGroup Semantik
fÃŒr die GruppenmitgliedschaftsprÃŒfung verwendet werden soll. Mit PosixGroups ist der
Group Member Filter (Gruppenmitgliedschaftsfilter) in der Regel auf 'memberUid'
und der Group Filter (Gruppenfilter) auf 'objectclass\=posixGroup' eingestellt.
+view_admin_systemSettings_LDAPGroupUsePosixGroup_name=Ist PosixGroup
+view_admin_systemSettings_LDAPLoginProperty_desc=Die LDAP Eigenschaft, die den
Benutzernamen enthÀlt. Die Standardeinstellung ist "cn". Werden mehrere
Ãbereinstimmungen gefunden, so wird der erste Eintrag verwendet.
+view_admin_systemSettings_LDAPLoginProperty_name=Login Eigenschaft
+view_admin_systemSettings_LDAPProtocol_desc=Soll die Kommunikation mit dem LDAP Server
ÃŒber SSL erfolgen?
+view_admin_systemSettings_LDAPProtocol_name=SSL
+view_admin_systemSettings_LDAPUrl_desc=URL zum LDAP Server
+view_admin_systemSettings_LDAPUrl_name=LDAP URL
+view_admin_systemSettings_RHQSessionTimeout_desc=Wenn diese Zeit ohne Benutzerinteraktion
im Browser verlÀuft, so wird die Session als abgelaufen angesehen und der Benutzer wird
um erneute Anmeldung gebeten. Der Wert ist in Stunden festgelegt.
+view_admin_systemSettings_RHQSessionTimeout_name=GUI Session Timeout
+view_admin_systemSettings_RtDataPurge_desc=Wie alt Antwort Zeitdaten sein mÃŒssen, ehe
sie aus der Datenbank bereinigt werden. Dies ist in Tagen festgelegt.
+view_admin_systemSettings_RtDataPurge_name=Lösche Antwort Zeitdaten, die Àlter sind
als
+view_admin_systemSettings_TraitPurge_desc=Wie alt Mess Merkmaldaten sein mÃŒssen, ehe sie
aus der Datenbank bereinigt werden. Dies ist in Tagen festgelegt.
# #view_admin_systemSettings_RHQSessionTimeout_desc = If this amount of time passes
without any user interaction in the browser, the session is considered as expired and user
is aked to log in again. This value is specified in hours.
# #view_admin_systemSettings_RHQSessionTimeout_name = GUI Session Timeout
view_admin_systemSettings_TraitPurge_name=Bereinigen der Trait-Daten, die Àlter sind
als
+view_admin_systemSettings_cannotLoadServerDetails=Kann Server Details nicht laden
+view_admin_systemSettings_cannotLoadSettings=Erhalt aktueller Systemeinstellungen nicht
möglich
view_admin_systemSettings_dumpToLogFailed=Schreiben der Systeminformation in die
Server-Log-Datei ist fehlgeschlagen
view_admin_systemSettings_dumpedToLog=System informationen wurden erfolgreich in die
Server-Log-Datei geschrieben
+view_admin_systemSettings_fixBeforeSaving=Bitte korrigieren Sie ungÃŒltige Werte vor dem
Speichern
+view_admin_systemSettings_group_baseline=Automatische Referenzband
Konfigurationseigenschaften
+view_admin_systemSettings_group_dataMgr=Datenmanager Konfigurationseigenschaften
+view_admin_systemSettings_group_drift=Drift Server Konfigurationseigenschaften
+view_admin_systemSettings_group_general=Allgemeine Konfigurationseigenschaften
+view_admin_systemSettings_group_ldap=LDAP-Konfigurationseigenschaften
# #view_admin_systemSettings_group_drift = Drift Server Configuration Settings
view_admin_systemSettings_saveFailure=Das Speichern der Systemeinstellungen ist
fehlgeschlagen
view_admin_systemSettings_savedSettings=Sie haben die Systemeinstellungen erfolgreich
gespeichert
+view_admin_systemSettings_serverDetails=Server Details
+view_admin_systemSettings_serverDetails_buildNumber=Build-Nummer
view_admin_systemSettings_serverDetails_dbDriverName=Name des Datenbanktreibers
view_admin_systemSettings_serverDetails_dbDriverVersion=Version des Datenbanktreibers
view_admin_systemSettings_serverDetails_dbName=Produktname der Datenbank
@@ -892,6 +1094,7 @@ view_admin_systemSettings_serverDetails_tz=Zeitzone des Servers
view_admin_topology=Topologie
view_alert_common_tab_conditions=Bedingungen
view_alert_common_tab_conditions_expression=Alarm auslösen wenn
+view_alert_common_tab_conditions_expression_tooltip=Bestimmt ob ANY (eine) oder ALL
(alle) Bedingungen als "true" evaluiert werden mÃŒssen, damit der gesamte
Bedingungssatz als "true" angesehen wird.
# #view_alert_common_tab_conditions_expression_tooltip = Determines if ANY or ALL of the
conditions must evaluate to true in order for the entire condition set to be considered
true.
view_alert_common_tab_conditions_modalEdit_title=Bedingungen Àndern
view_alert_common_tab_conditions_modal_title=Bedingung hinzufÃŒgen
@@ -914,6 +1117,7 @@ view_alert_common_tab_conditions_type_metric_calltime_change_verb=um
mindestens
view_alert_common_tab_conditions_type_metric_calltime_delta_grows=WÀchst
view_alert_common_tab_conditions_type_metric_calltime_delta_other=Ãndert sich
view_alert_common_tab_conditions_type_metric_calltime_delta_shrinks=Schrumpft
+view_alert_common_tab_conditions_type_metric_calltime_destination=mit Aufruf
DestinationsÃŒbereinstimmung
# #view_alert_common_tab_conditions_type_metric_calltime_destination = with call
destination matching
view_alert_common_tab_conditions_type_metric_calltime_threshold=Call-Time ÃŒberschreitet
Schwellwert
view_alert_common_tab_conditions_type_metric_change=Wert der Metrik Àndert sich
@@ -923,6 +1127,7 @@
view_alert_common_tab_conditions_type_metric_range_outside_exclusive=Wertbereich
view_alert_common_tab_conditions_type_metric_range_outside_inclusive=Wertbereich der
Metrik\: [{0}] ausserhalb [{1}] und [{2}], inklusiv
view_alert_common_tab_conditions_type_metric_threshold=Metrik ÃŒberschreitet Schwellwert
view_alert_common_tab_conditions_type_metric_trait_change=Trait-Ãnderung
+view_alert_common_tab_conditions_type_metric_trait_matching=mit Trait Wert
Ãbereinstimmung
# #view_alert_common_tab_conditions_type_metric_trait_matching = with trait value
matching
view_alert_common_tab_conditions_type_operation=AusfÃŒhrung der Operation
view_alert_common_tab_conditions_type_operation_status=mit Ergebnis-Status
@@ -947,6 +1152,8 @@
view_alert_common_tab_dampening_partial_evalatuions_label_tooltip=Anzahl wie oft
view_alert_common_tab_dampening_partial_occurrences_label=Anzahl Vorkommen
view_alert_common_tab_dampening_partial_occurrences_label_tooltip=Anzahl wie oft die
Bedingungen innerhalb der letzten N Auswertungen wahr sein mÃŒssen, bevor der Alarm
ausgelöst wird.
view_alert_common_tab_general=Allgemeine Eigenschaften
+view_alert_common_tab_invalid_condition_category=UngÃŒltige Bedingungskategorie - bitte
berichten Sie diesen Fehler\: {0}
+view_alert_common_tab_invalid_dampening_category=UngÃŒltige Dampening Kategorie - bitte
berichten Sie diesen Fehler\: {0}
# #view_alert_common_tab_invalid_condition_category = Invalid condition category - please
report this as a bug: {0}
# #view_alert_common_tab_invalid_dampening_category = Invalid dampening category - please
report this as a bug: {0}
view_alert_common_tab_invalid_time_units=UngÃŒltige Zeiteinheit - bitte berichten Sie
diesen Fehler\: {0}
@@ -956,6 +1163,7 @@ view_alert_common_tab_notifications_sender=Sender
view_alert_common_tab_notifications_status=Status
view_alert_common_tab_recovery=Erholung
view_alert_definition_condition_editor_availabilityDuration=Dauer der VerfÃŒgbarkeit
+view_alert_definition_condition_editor_availabilityDuration_state=VerfÃŒgbarkeitsstatus
# #view_alert_definition_condition_editor_availabilityDuration_state = Availability
State
view_alert_definition_condition_editor_availabilityDuration_tooltip=Geben Sie die
Ãnderung der VerfÃŒgbarkeit und die LÀnge der Dauer des Zustandes an damit die Bedingung
zutrifft. Die Dauer ist in Minuten und sollte lang genug sein (mehrere Minuten), um dem
Agent Zeit zugeben eine potentielle Ãnderung des Zustands zu erkennen.
view_alert_definition_condition_editor_availabilityDuration_tooltip_duration=Die Anzahl
der Minuten in der die Ressource die gegeben VerfÃŒgbarkeit haben muss, bevor die
Bedingung zutrifft.
@@ -969,29 +1177,48 @@ view_alert_definition_condition_editor_common_min=Minimum
view_alert_definition_condition_editor_common_regex=RegulÀrer Ausdruck
view_alert_definition_condition_editor_delete_confirm=Die ausgewÀhlte(n)
Alarm-Bedingung(en) löschen?
view_alert_definition_condition_editor_drift_configname_regex=Name der Drift-Definition
+view_alert_definition_condition_editor_drift_configname_regex_tooltip=Falls festgelegt
ist dies der Drift Definitionsname, der fÃŒr den aufgespÃŒrten Drift verantwortlich war.
Dies kann optional ein regulÀrer Ausdruck sein, falls Sie eine Ãbereinstimmung mit
mehreren Drift Definitionsnamen haben möchten.
# #view_alert_definition_condition_editor_drift_configname_regex_tooltip = If specified,
this is the drift definition name that was responsible for the drift that was detected.
This can optionally be a regular expression if you wish to match multiple drift definition
names.
view_alert_definition_condition_editor_drift_pathname_regex=RegulÀrer Ausdruck fÌr den
Pfadnamen
+view_alert_definition_condition_editor_drift_pathname_regex_tooltip=Falls festgelegt ist
dies ein regulÀrer Ausdruck, der mit den Pfadnamen der Dateien mit Drift Ìbereinstimmen
muss.
+view_alert_definition_condition_editor_drift_tooltip=Diese Bedingung wird ausgelöst,
wenn Drift aufgespÃŒrt wurde.
# #view_alert_definition_condition_editor_drift_pathname_regex_tooltip = If specified,
this is a regular expression that must match the pathnames of those files that drifted.
# #view_alert_definition_condition_editor_drift_tooltip = This condition is triggered
when drift has been detected.
view_alert_definition_condition_editor_event_regexTooltip=If specified, this is a regular
expression that must match a collected event message in order to trigger the condition.
view_alert_definition_condition_editor_event_severity=Schwere des Ereignisses
+view_alert_definition_condition_editor_event_tooltip=Legen Sie eine Ereignisschwere fest,
bei der eine Ereignismeldung gemeldet werden muss, um diese Bedingung auszulösen. Falls
Sie einen optionalen regulÀren Audruck festlegen, muss die Ereignismeldung auch mit dem
regulÀren Ausdruck Ìbereinstimmen, um die Bedingung auszulösen.
+view_alert_definition_condition_editor_metric_baseline_percentage=Referenzband
Prozentsatz
+view_alert_definition_condition_editor_metric_baseline_percentage_tooltip=Ein gesammelter
metrischer Wert löst diese Bedingung beim Vergleich mit diesem Prozentsatz des gewÀhlten
Referenzbandswerts mittels des gewÀhlten Komparators aus.
+view_alert_definition_condition_editor_metric_baseline_tooltip=Legen Sie den
Referenzbandwert fest, der verletzt werden muss, um die Bedingung auszulösen. Der von
Ihnen festgelegte Wert ist ein Prozentsatz des gegebenen Referenzbandwerts.
# #view_alert_definition_condition_editor_event_tooltip = Specify the event severity that
an event message must be reported with in order to trigger this condition. If you specify
an optional regular expression, the event message must also match that regular expression
in order for the condition to trigger.
# #view_alert_definition_condition_editor_metric_baseline_percentage = Baseline
Percentage
# #view_alert_definition_condition_editor_metric_baseline_percentage_tooltip = A
collected metric value will trigger this condition when compared to this percentage of the
selected baseline value using the selected comparator
# #view_alert_definition_condition_editor_metric_baseline_tooltip = Specify the baseline
value that must be violated to trigger the condition. The value you specify is a
percentage of the given baseline value.
view_alert_definition_condition_editor_metric_baseline_value=Referenzband
view_alert_definition_condition_editor_metric_calltime_change_percentage=Ãnderung des
Prozentsatzes
+view_alert_definition_condition_editor_metric_calltime_change_percentage_tooltip=Ein
gesammelter Aufrufzeit Wert löst diese Bedingung aus, wenn er um mindestens diesen
Prozentsatz vom gewÀhlten Aufrufzeit Grenzwert differiert.
+view_alert_definition_condition_editor_metric_calltime_change_tooltip=Legen Sie den
Aufrufzeit Wert fest der die Bedingung auslöst, wenn er um mindestens eine festgelegte
Menge verÀndert wird. Sie mÌssen festlegen, welche Aufrufzeit Grenze geprÌft werden
soll (minimum, maximum oder durchschnittlicher Aufrufzeit Wert) und den Prozentsatz der
Ãnderung.
# #view_alert_definition_condition_editor_metric_calltime_change_percentage_tooltip = A
collected calltime value will trigger this condition when it differs by at least this
percentage of the selected calltime limit value
# #view_alert_definition_condition_editor_metric_calltime_change_tooltip = Specify the
calltime value that, when changed at least a specified amount, triggers the condition. You
must specify which calltime limit to check (minimum, maximum or average calltime value)
and the percentage of change that must occur.
view_alert_definition_condition_editor_metric_calltime_common_comparator=Komparator
view_alert_definition_condition_editor_metric_calltime_common_comparator_changes=Ãndert
sich
view_alert_definition_condition_editor_metric_calltime_common_comparator_grows=WÀchst
view_alert_definition_condition_editor_metric_calltime_common_comparator_shrinks=Schrumpft
+view_alert_definition_condition_editor_metric_calltime_common_comparator_tooltip=Wie ein
gesammelter Aufrufzeit Wert zur gegebenen Aufrufzeit Grenze verglichen werden soll
+view_alert_definition_condition_editor_metric_calltime_common_limit=Aufrufzeit Grenze
+view_alert_definition_condition_editor_metric_calltime_common_limit_tooltip=Der
Aufrufzeit Grenzwert der mit dem gegebenen Wert verglichen werden soll
+view_alert_definition_condition_editor_metric_calltime_common_name=Aufrufzeit Metrik
# #view_alert_definition_condition_editor_metric_calltime_common_comparator_tooltip = How
a collected calltime value should be compared to the given calltime limit
# #view_alert_definition_condition_editor_metric_calltime_common_limit = Call Time Limit
# #view_alert_definition_condition_editor_metric_calltime_common_limit_tooltip = The
calltime limit value that is to be compared with the given value
# #view_alert_definition_condition_editor_metric_calltime_common_name = Call Time Metric
view_alert_definition_condition_editor_metric_calltime_regexTooltip=If specified, this is
a regular expression that must match a call destination in order to trigger the
condition.
+view_alert_definition_condition_editor_metric_calltime_threshold_tooltip=Legen Sie den
Aufrufzeit-Schwellwert fest, der verletzt werden muss, um die Bedingung auszulösen. Der
von Ihnen festgelegte Wert ist ein absoluter Wert, mit einem optionalen Einheiten
Spezifikationssymbol. Sie mÃŒssen auch festlegen, mit welcher Aufrufzeitgrenze der Wert
verglichen werden soll (minimum, maximum oder durchschnittlicher Aufrufzeit Wert).
+view_alert_definition_condition_editor_metric_calltime_threshold_value=Aufrufzeit Wert
+view_alert_definition_condition_editor_metric_calltime_threshold_value_tooltip=Der
Schwellwert der Metrik, die beim Vergleich mittels des gewÀhlten Komparators die
Bedingung auslöst.
+view_alert_definition_condition_editor_metric_change_tooltip=Legen Sie die Metrik fest,
deren Wert sich Àndern muss, um die Bedingung auszulösen.
+view_alert_definition_condition_editor_metric_common_definition_not_found=HÀtte
metrische Definition finden sollen - etwas stimmt nicht
+view_alert_definition_condition_editor_metric_nometrics=Bei Verwendung der ALL Verbindung
können Sie nicht dieselbe Metrik in mehreren Bedingungen verwenden und dieser Alarm
verwendet alle verfÃŒgbaren Metriken in aktuell vorhandenen Bedingungen.
# #view_alert_definition_condition_editor_metric_calltime_threshold_tooltip = Specify the
calltime threshold value that, when violated, triggers the condition. The value you
specify is an absolute value with an optional units specifier. You also must specify which
calltime limit to compare the value with (minimum, maximum or average calltime value).
# #view_alert_definition_condition_editor_metric_calltime_threshold_value = Call Time
Value
# #view_alert_definition_condition_editor_metric_calltime_threshold_value_tooltip = The
threshold value of the metric that will trigger the condition when compared using the
selected comparator.
@@ -1003,26 +1230,43 @@
view_alert_definition_condition_editor_metric_range_comparator_inside_exclusive=
view_alert_definition_condition_editor_metric_range_comparator_inside_inclusive=Innerhalb,
inklusiv
view_alert_definition_condition_editor_metric_range_comparator_outside_exclusive=Ausserhalb,
exklusiv
view_alert_definition_condition_editor_metric_range_comparator_outside_inclusive=Ausserhalb,
inklusiv
+view_alert_definition_condition_editor_metric_range_comparator_tooltip=Legt fest, ob ein
metrischer Wert diese Bedingung auslösen soll wenn der Bereich innerhalb oder auÃerhalb
verlÀuft. Falls inbegriffen, so wird der Wert als im Bereich angesehen, wenn sein Wert
einem Hoch- oder Tiefwert des Schwellwerts gleich ist. Falls exklusiv, so gilt der Wert
als nicht im Bereich wenn er dem Hoch- oder Tiefwert gleich ist.
# #view_alert_definition_condition_editor_metric_range_comparator_tooltip = Determines if
a metric value should trigger this condition when inside the range or outside of it.
view_alert_definition_condition_editor_metric_range_hivalue=Oberer Schwellwert
view_alert_definition_condition_editor_metric_range_hivalue_tooltip=Der obere Schwellwert
des Bereichs
view_alert_definition_condition_editor_metric_range_lovalue=Unterer Schwellwert
view_alert_definition_condition_editor_metric_range_lovalue_tooltip=Der untere
Schwellwert des Bereichs
+view_alert_definition_condition_editor_metric_range_tooltip=Vergleicht einen metrischen
Wert zu einem gegebenen Tief-/Hoch Bereichswert.
# #view_alert_definition_condition_editor_metric_range_tooltip = Compares a metric value
to a given low-high value range.
view_alert_definition_condition_editor_metric_threshold_comparator=Komparator
view_alert_definition_condition_editor_metric_threshold_comparator_equal=Gleich
view_alert_definition_condition_editor_metric_threshold_comparator_greater=GröÃer als
view_alert_definition_condition_editor_metric_threshold_comparator_less=Kleiner als
+view_alert_definition_condition_editor_metric_threshold_comparator_tooltip=Wie ein
gesammelter metrischer Wert mit dem gegebenen Schwellwert verglichen werden soll
# #view_alert_definition_condition_editor_metric_threshold_comparator_tooltip = How a
collected metric value should be compared to the given threshold value
view_alert_definition_condition_editor_metric_threshold_name=Metrik
+view_alert_definition_condition_editor_metric_threshold_tooltip=Legen Sie den Schwellwert
fest, der verletzt werden muss, um die Bedingung auszulösen. Der von Ihnen festgelegte
Wert ist ein absoluter Wert, mit einem optionalen Einheiten Spezifikationssymbol.
# #view_alert_definition_condition_editor_metric_threshold_tooltip = Specify the
threshold value that, when violated, triggers the condition. The value you specify is an
absolute value with an optional units specifier.
view_alert_definition_condition_editor_metric_threshold_value=Wert der Metrik
+view_alert_definition_condition_editor_metric_threshold_value_tooltip=Der Schwellwert der
Metrik, die beim Vergleich mittels des gewÀhlten Komparators die Bedingung auslöst.
+view_alert_definition_condition_editor_metric_trait_change_tooltip=Legen Sie das Merkmal
fest, dessen Wert sich Àndern muss, um die Bedingung auszulösen.
+view_alert_definition_condition_editor_metric_trait_change_value=Merkmal
+view_alert_definition_condition_editor_metric_trait_regexTooltip=Falls festgelegt ist
dies ein regulÀrer Ausdruck, der mit dem neuen Merkmalwert Ìbereinstimmen muss, um die
Bedingung auszulösen.
+view_alert_definition_condition_editor_metricswarning=Sie können nicht mehrere
Bedingungen haben, die dieselbe Metrik verwenden, wen Sie die ALL VerknÃŒpfung verwenden.
Diese Alarm Definition besitzt mehrere Bedingungen, die die Metrik [{0}] verwenden.
# #view_alert_definition_condition_editor_metric_threshold_value_tooltip = The threshold
value of the metric that will trigger the condition when compared using the selected
comparator.
# #view_alert_definition_condition_editor_metric_trait_change_tooltip = Specify the trait
whose value must change to trigger the condition.
# #view_alert_definition_condition_editor_metric_trait_change_value = Trait
# #view_alert_definition_condition_editor_metric_trait_regexTooltip = If specified, this
is a regular expression that must match the new trait value in order to trigger the
condition.
# #view_alert_definition_condition_editor_metricswarning = You cannot have multiple
conditions that use the same metric when using the ALL conjunction. This alert definition
has multiple conditions that use the metric [{0}].
view_alert_definition_condition_editor_operation_status=Zustand der Operation
+view_alert_definition_condition_editor_operation_tooltip=Legen Sie das Ergebnis fest, das
auftreten muss, wenn der gewÀhlte Vorgang ausgefÌhrt wird, damit die Bedingung
ausgelöst wird.
+view_alert_definition_condition_editor_operator_availability_durationDown=Bleibt auÃer
Betrieb
+view_alert_definition_condition_editor_operator_availability_durationNotUp=Bleibt nicht
in Betrieb
+view_alert_definition_condition_editor_operator_availability_goesDisabled=Wird
deaktiviert
+view_alert_definition_condition_editor_operator_availability_goesDown=Geht auÃer
Betrieb
+view_alert_definition_condition_editor_operator_availability_goesNotUp=Geht nicht in
Betrieb
+view_alert_definition_condition_editor_operator_availability_goesUnknown=Geht unbekannt
+view_alert_definition_condition_editor_operator_availability_goesUp=Geht in Betrieb
# #view_alert_definition_condition_editor_operation_tooltip = Specify the result that
must occur when the selected operation is executed in order to trigger the condition.
view_alert_definition_condition_editor_option_availability=Ãnderung der VerfÃŒgbarkeit
view_alert_definition_condition_editor_option_drift=Erkennung von Drift
@@ -1030,6 +1274,7 @@ view_alert_definition_condition_editor_option_event=Erkennung von
Ereignissen
view_alert_definition_condition_editor_option_label=Typ der Bedingung
view_alert_definition_condition_editor_option_metric_baseline=Schwelle des Referenzbands
view_alert_definition_condition_editor_option_metric_calltime_change=Ãnderung des
Call-Time-Werts
+view_alert_definition_condition_editor_option_metric_calltime_threshold=Aufrufzeit Wert
Schwellwert
# #view_alert_definition_condition_editor_option_metric_calltime_threshold = Call Time
Value Threshold
view_alert_definition_condition_editor_option_metric_change=Wert der Metrik Àndert sich
view_alert_definition_condition_editor_option_metric_range=Wertebereich
@@ -1043,16 +1288,27 @@ view_alert_definition_for_group=Gruppendefinition ansehen
view_alert_definition_for_type=Vorlage ansehen
view_alert_definition_notification_cliScript_editor_anotherUser=Anderer Benutzer
view_alert_definition_notification_cliScript_editor_existingScript=Vorhandenes Skript
+view_alert_definition_notification_cliScript_editor_loadFailed=Konnte CLI
Benachrichtigungs-Editor nicht laden.
+view_alert_definition_notification_cliScript_editor_newScriptVersion=Version
+view_alert_definition_notification_cliScript_editor_repository=Repository
view_alert_definition_notification_cliScript_editor_script=Skript
+view_alert_definition_notification_cliScript_editor_selectRepo=WÀhlen Sie das
Repository, in dem das Skript gespeichert werden soll
+view_alert_definition_notification_cliScript_editor_selectRepoFirst=WÀhlen Sie zuerst
ein Repository-Konfigurationstool
view_alert_definition_notification_cliScript_editor_thisUser=Aktueller Benutzer
+view_alert_definition_notification_cliScript_editor_uploadNewScript=Neues Skript
hochladen
+view_alert_definition_notification_cliScript_editor_verifyAuthentication=Verifizieren
+view_alert_definition_notification_cliScript_editor_whichUser=Benutzer, als der das
Skript ausgefÃŒhrt werden soll
view_alert_definition_notification_editor_delete_confirm=Sind Sie sicher, dass sie die
ausgewÀhlten Alarm-Benachrichtigungen löschen wollen?
view_alert_definition_notification_editor_field_configuration=Konfiguration
view_alert_definition_notification_editor_field_configuration_loadFailed=Konte die
Vorschau der Benachrichtigung nicht laden
view_alert_definition_notification_editor_field_configuration_not_loaded=Unbekannt
view_alert_definition_notification_editor_field_sender=Sender
view_alert_definition_notification_editor_loadFailed=Kann die Alarm-Sender nicht laden
+view_alert_definition_notification_editor_loadFailed_single=Erhalt von Alarm Sender
Konfigurationsdefinition nicht möglich
# #view_alert_definition_notification_editor_loadFailed_single = Cannot get alert sender
configuration definition
view_alert_definition_notification_editor_none_available=Keine Alarm-Sender verfÃŒgbar
+view_alert_definition_notification_editor_saveFailed=Kann die
Benachrichtigungskonfiguration nicht speichern
+view_alert_definition_notification_editor_sender=Benachrichtigungssender
# #view_alert_definition_notification_editor_saveFailed = Cannot save the notification
configuration
# #view_alert_definition_notification_editor_sender = Notification Sender
view_alert_definition_notification_editor_title_add=Benachrichtigung hinzufÃŒgen
@@ -1061,15 +1317,24 @@
view_alert_definition_notification_operation_editor_common_operation=Operation
view_alert_definition_notification_operation_editor_mode_relative=Relative Ressource
view_alert_definition_notification_operation_editor_mode_specific=Spezifische Ressource
view_alert_definition_notification_operation_editor_mode_this=Diese Ressource
+view_alert_definition_notification_operation_editor_mode_title=Ressourcen Auswahlmodus
# #view_alert_definition_notification_operation_editor_mode_title = Resource Selection
Mode
view_alert_definition_notification_operation_editor_mode_unknown=Unbekannte Option -
Berichten Sie diesen Fehler
+view_alert_definition_notification_operation_editor_operations_loadFailed=Konnte die
Liste der verfÃŒgbaren Operationen nicht laden
+view_alert_definition_notification_operation_editor_operations_no_parameters=Diese
Operation nimmt keine Parameter
# #view_alert_definition_notification_operation_editor_operations_loadFailed = Failed to
load the list of available operations
# #view_alert_definition_notification_operation_editor_operations_no_parameters = This
operation does not take any parameters
view_alert_definition_notification_operation_editor_relative_ancestor=Suche starten bei
+view_alert_definition_notification_operation_editor_relative_ancestor_loadFailed=Erhalt
von Typ Vorfahren nicht möglich
+view_alert_definition_notification_operation_editor_relative_ancestor_root=Root Vorfahren
Typ
+view_alert_definition_notification_operation_editor_relative_ancestor_tooltip=WÀhlen Sie
die Spitze der Typenhierarchie aus, von der aus der Baum der Abkömmlinge fÌr den Filter
nach Typ durchsucht werden soll
# #view_alert_definition_notification_operation_editor_relative_ancestor_loadFailed =
Cannot get type ancestry
# #view_alert_definition_notification_operation_editor_relative_ancestor_root = Root
Ancestor Type
# #view_alert_definition_notification_operation_editor_relative_ancestor_tooltip = Select
the top of the type hierarchy from which to search its descedant tree for the Filter By
type
view_alert_definition_notification_operation_editor_relative_descendant=dann filtern
nach
+view_alert_definition_notification_operation_editor_relative_descendant_filter_tooltip=Ein
spezifischer Name zur eindeutigen Identifizierung einer Ressource, wenn mehr als eine
Ressource des gewÀhlten Typs vorhanden sein kann. Dies ist optional wenn stets nur eine
Ressource des Ressourcentyps in der gewÀhlten Typhierarchie existiert.
+view_alert_definition_notification_operation_editor_relative_descendant_loadFailed=Erhalt
von Typ Abkömmlingen nicht möglich
+view_alert_definition_notification_operation_editor_relative_descendant_tooltip=Der
Ressourcentyp, nach dem unter dem in der Start Search From Auswahl (Suche starten von)
definierten Root Typ gesucht werden soll.
# #view_alert_definition_notification_operation_editor_relative_descendant_filter_tooltip
= A specific name to uniquely identify a resource when more than one resource of the
selected type might exist. This is optional if there will only ever be one resource of the
resource type in the selected type hierarchy.
# #view_alert_definition_notification_operation_editor_relative_descendant_loadFailed =
Cannot get type descendants
# #view_alert_definition_notification_operation_editor_relative_descendant_tooltip = The
resource type to search for under the root type defined in the Start Search From
selection.
@@ -1085,6 +1350,8 @@ view_alert_definition_notification_user_editor_loadFailed=Kann die
aktuellen Ben
view_alert_definition_notification_user_editor_restoreFailed=Kann die aktuellen Benutzer
nicht verwenden - starte ohne
view_alert_definition_notification_user_editor_saveFailed=Kann die ausgewÀhlten Benutzer
nicht sichern
view_alert_definition_recovery_editor_disable_when_fired=Nach dem Auslösen inaktiv
schalten
+view_alert_definition_recovery_editor_disable_when_fired_tooltip=Gibt an, ob dieser Alarm
nach dem feuern deaktiviert wird. Nach Deaktivierung kann der Alarm manuell wieder
aktiviert werden oder ein Wiederherstellungsalarm kann eingestellt werden, damit er
automatisch wieder aktiviert wird. Ist dieser Alarm selbst ein Wiederherstellungsalarm, so
ist diese Einstellung nicht möglich.
+view_alert_definition_recovery_editor_loadFailed=Kann WiederhesrtsellungsmenÌ nicht
erstellen
# #view_alert_definition_recovery_editor_disable_when_fired_tooltip = Indicates if this
alert will be disabled after it fires. Once disabled, the alert can be manually re-enabled
or a recovery alert can be set up to automatically re-enable it. If this alert is a
recovery alert itself, this setting cannot be turned on.
# #view_alert_definition_recovery_editor_loadFailed = Cannot build recovery menu
view_alert_definition_recovery_editor_none_available=Keiner
@@ -1110,6 +1377,7 @@ view_alert_definitions_update_failure=Aktualisieren der
Alarm-Definition fehlges
view_alert_definitions_update_success=Alarm-Definition erfolgreich aktualisiert
view_alert_details_field_ack_at=BestÀtigt um
view_alert_details_field_ack_by=BestÀtigt durch
+view_alert_details_field_parent_definition=Parent Definition
view_alert_details_field_recovery_info=Info zur Erholung
view_alert_details_field_resource_ancestry=Vorfahren der Ressource
view_alert_details_field_watched_resource=Beobachtere Ressource
@@ -1161,6 +1429,7 @@ view_autoDiscoveryQ_ignored=Ignoriert
view_autoDiscoveryQ_importFailure=Konnte die Ressourcen nicht importieren
view_autoDiscoveryQ_importInProgress=Die ausgewÀhlten Ressourcen werden in''s
Inventar aufgenommen
view_autoDiscoveryQ_importSuccessful=Sie haben die ausgewÀhlten Ressourcen erfolgreich
importiert
+view_autoDiscoveryQ_loadFailure=Konnte die Inventar Discovery Warteschlange nicht laden
# #view_autoDiscoveryQ_loadFailure = Failed to load the inventory discovery queue
view_autoDiscoveryQ_newAndIgnored=Neu und Ignoriert
view_autoDiscoveryQ_noperm=(Die erforderlichen "manage inventory" Rechte
fehlen. Kontaktieren Sie den Administrator)
@@ -1169,8 +1438,17 @@ view_autoDiscoveryQ_showStatus=Zeige
view_autoDiscoveryQ_title=Autodiscovery-Warteschlange
view_autoDiscoveryQ_unignore=Ignorieren aufheben
view_autoDiscoveryQ_unignoreFailure=Konnte das Ignorieren fÃŒr die Ressourcen nicht
aufheben.
+view_autoDiscoveryQ_unignoreInProgress=Hebe die Ignorierung der gewÀhlten Ressourcen
auf...
view_autoDiscoveryQ_unignoreSuccessful=Sie haben erfolgreich das Ignorieren der
ausgewÀhlten Ressourcen aufgehoben.
view_autoDiscoveryQ_uninventoried=Aus dem Inventory gelöscht
+view_bundleGroup_assignFailPerm=Sie sind nicht berechtigt, dieser Bundle Gruppe Bundles
zuzuweisen. Bitte wenden Sie sich an Ihren Administrator.
+view_bundleGroup_deleteConfirm=Sind Sie sicher, dass Sie diese Bundle Gruppe löschen
möchten? Bundles fÌr die dies die einzige zugewiesene Bundle Gruppe ist verlieren ihre
Zurodnung und deren Ansicht erfordert eine allgemeine View Bundles (Bundles ansehen)
Berechtigung.
+view_bundleGroup_deletesFailure=Konnte die Bundle Gruppen nicht löschen
+view_bundleGroup_deletesSuccessful=Sie haben die Bundle Gruppen erfolgreich gelöscht
+view_bundleGroup_unassignFailPerm=Sie sind nicht berechtigt, die Zurodnung von Bundles zu
dieser Bundle Gruppe aufzuheben. Bitte wenden Sie sich an Ihren Administrator.
+view_bundleVersion_loadFailure=Konnte aktuellste Bundle Versionsdaten nicht laden
+view_bundle_bundleDeployment=Bundle Deployment
+view_bundle_bundleDeployments=Bundle Deployments
# #view_bundleGroup_assignFailPerm = You are not authorized to assign bundles to this
bundle group. Please check with your administrator.
# #view_bundleGroup_deleteConfirm = Are you sure you want to delete this bundle group?
Bundles for which this is the only assigned bundle group will become unassigned, and will
require global View Bundles permission to view.
# #view_bundleGroup_deletesFailure = Failed to delete the bundle groups
@@ -1184,6 +1462,32 @@ view_bundle_bundleFiles=Bundle-Dateien
view_bundle_bundleType=Bundle-Type
view_bundle_bundleVersion=Bundle-Version
view_bundle_bundleVersions=Bundle-Versionen
+view_bundle_createWizard_bundleDistro=Bundle Distribution
+view_bundle_createWizard_cancelFailure=Konnte die Erstellung von Bundle [{0}], Version \=
[{1}] nicht vollstÀndig abbrechen - das Bundle ist möglicherweise noch vorhanden.
+view_bundle_createWizard_cancelFailurePerm=Konnte die Erstellung von Bundle [{0}],
Version \= [{1}] nicht vollstÀndig abbrechen da der Benutzer Berechtigung zur Erstellung,
nicht aber fÌr das Löschen besitzt. Das Bundle muss wahrscheinlich von einem
Administrator entfernt werden mÃŒssen.
+view_bundle_createWizard_cancelSuccessful=Erstellung von Bundle [{0}], Version \= [{1}]
abgebrochen
+view_bundle_createWizard_clickToUploadRecipe=Zum Laden einer Anleitungsdatei klicken
+view_bundle_createWizard_createFailure=Konnte das Bundle nicht erstellen
+view_bundle_createWizard_createSuccessful=Sie haben erfolgreich ein Bundle [{0}] mit
einer Version von [{1}] erstellt
+view_bundle_createWizard_enterRecipe=Bitte geben Sie eine gÃŒltige Anleitung ein
+view_bundle_createWizard_enterUrl=Bitte geben Sie eine gÃŒltige URL ein, von wo die
Bundle Distribution Datei heruntergeladen werden kann
+view_bundle_createWizard_failedToUploadDistroFile=Konnte die Bundle Distribution Datei
nicht hochladen
+view_bundle_createWizard_failedToUploadFile=Konnte die Bundle Datei nicht hochladen
+view_bundle_createWizard_groupsStep_assign=Weisen Sie mindestens eine der berechtigten
Bundle Gruppen zu\:
+view_bundle_createWizard_groupsStep_assigned=Die neue Bundle Version ist fÃŒr ein
vorhandenes Bundle und erbt seine Bundle Gruppen Zuweisungen\:
+view_bundle_createWizard_groupsStep_failedAssign=Zuordnung erster Bundle Gruppen an ein
Bundle namens [{0}] mit einer Version von [{1}] fehlgeschlagen. Bitte beenden Sie den
Erstellungs-Wizard und benachrichtigen Sie Ihren Administrator.
+view_bundle_createWizard_groupsStep_failedGetAssignable=Konnte zuweisbare Bundle Gruppen
nicht bestimmen. Bitte beenden Sie den Erstellungs-Wizard und benachrichtigen Sie Ihren
Administrator.
+view_bundle_createWizard_groupsStep_help=Ein neues Bundle wird erstellt, wenn die erste
Version fÃŒr dieses Bundle hochgeladen wird. Das neue Bundle wird dann seinen ersten
Bundle Gruppen zugewiesen. Ein Benutzer kann das neue Bundle nur Bundle Gruppen zuweisen,
fÃŒr die er eine Create Bundles (Bundles erstellen) Berechtigung besitzt, entweder
allgemein oder auf Bundle Gruppen Ebene. Es muss mindestens eine Bundle Gruppe zugewiesen
sein, auÃer der Benutzer besitzt allgemeine Berechtigungen zur Erstellung und Ansicht von
Bundles, in welchem Falle die Zuweisung ausbleiben kann.
+view_bundle_createWizard_groupsStep_leaveUnassigned=Das neue Bundle ohne Zuweisung
lassen.
+view_bundle_createWizard_groupsStep_noAssignable=Konnte erste Bundle Version nicht
erstellen, da Benutzer keine Bundle Gruppen besitzt zu denen eine Zuweisung erfolgen kann.
Bitte beenden Sie den Erstellungs-Wizard und benachrichtigen Sie Ihren Administrator.
+view_bundle_createWizard_groupsStep_noneAssigned=Die neue Bundle Version muss mindestens
einer Bundle Gruppe zugewiesen werden\!
+view_bundle_createWizard_groupsStep_radioTitle=Erste Bundle Gruppen Zuordnung fÃŒr das
neue Bundle
+view_bundle_createWizard_groupsStep_successAssign=Sie haben erfolgreich erste Bundle
Gruppen einem Bundle namens [{0}] mit einer Version von [{1}] zugeordnet
+view_bundle_createWizard_groupsStep_unassigned=Die neue Bundle Version ist fÃŒr ein
vorhandenes Bundle und erbt seine Bundle Gruppen Zuweisungen. Das Bundle ist aktuell
keinen Bundle Gruppen zugeordnet.
+view_bundle_createWizard_loadBundleFileFailure=Kann Kann Bundle Datei Informationen nicht
vom Server abrufen
+view_bundle_createWizard_noAdditionalFilesNeeded=Es mÃŒssen keine weiteren Dateien fÃŒr
dieses Bundle hochgeladen werden
+view_bundle_createWizard_noBundleTypesAvail=Es sind keine Bundle Typen verfÃŒgbar
+view_bundle_createWizard_noBundleTypesSupported=Es werden keine Bundle Typen unterstÃŒtzt
- Sie mÃŒssen einen gÃŒltigen Plugin deployen, der Bundle Deployments unterstÃŒtzt
# #view_bundle_createWizard_bundleDistro = Bundle Distribution
# #view_bundle_createWizard_cancelFailure = Failed to fully cancel the creation of bundle
[{0}], version=[{1}] - the bundle may still exist.
# #view_bundle_createWizard_cancelFailurePerm = Failed to fully cancel the creation of
bundle [{0}], version = [{1}] because the user has create but not delete permissions. The
bundle will likley need to be removed by an administrator.
@@ -1211,8 +1515,10 @@ view_bundle_bundleVersions=Bundle-Versionen
# #view_bundle_createWizard_noBundleTypesAvail = No bundle types are available
# #view_bundle_createWizard_noBundleTypesSupported = No bundle types are supported - you
must deploy a valid plugin that supports bundle deployments
view_bundle_createWizard_provideBundleDistro=Stellen Sie eine Bundle-Distribution bereit
+view_bundle_createWizard_recipeOption=Anleitung
# #view_bundle_createWizard_recipeOption = Recipe
view_bundle_createWizard_title=Bundle anlegen
+view_bundle_createWizard_unassigned=nicht zugeordnet
# #view_bundle_createWizard_unassigned = unassigned
view_bundle_createWizard_uploadInProgress=Datei wird hochgeladen ... Dies kann fÃŒr
groÃe Dateien mehrere Minuten dauern
view_bundle_createWizard_uploadOption=Hochladen
@@ -1223,9 +1529,13 @@ view_bundle_createWizard_urlTooltip=Benutzername und Password
können fÌr HTTP
view_bundle_createWizard_urlUserName=Benutzername
view_bundle_createWizard_windowTitle=Assistent zum Anlegen von Bundles
view_bundle_createWizard_youMustChooseOne=Sie mÌssen eine Option auswÀhlen, um ein
Bundle anlegen zu können\!
+view_bundle_deleteConfirm=Sind Sie sicher, dass Sie dieses Bundle löschen wollen? Alle
Versionen, Destinationen und Deployments fÌr dieses Bundle werden ebenfalls gelöscht.
Dies entfernt keine Inhalte von Remote-Maschinen.
# #view_bundle_deleteConfirm = Are you sure you want to delete this bundle? All versions,
destinations and deployments for this bundle will also be deleted. However, this will not
remove any content from remote machines.
view_bundle_deploy=Deploy
view_bundle_deployDir=Deploy-Verzeichnis
+view_bundle_deployWizard_createGroup_error_1=Die Gruppe wurde nicht erstellt. Gruppe fÃŒr
Deployment darf nicht leer sein.
+view_bundle_deployWizard_createGroup_error_2=Die Gruppe wurde nicht erstellt. Die
resultierende Gruppe muss kompatibel sein (Mitglieder desselben Typs).
+view_bundle_deployWizard_createGroup_error_3=Die Gruppe wurde nicht erstellt. Der
Ressourcentyp der resultierenden Gruppe unterstÃŒtzt keine Deployments.
# #view_bundle_deployWizard_createGroup_error_1 = The group was not created. Group for
deployment cannot be empty.
# #view_bundle_deployWizard_createGroup_error_2 = The group was not created. Resulting
group must be compatible (members of the same type).
# #view_bundle_deployWizard_createGroup_error_3 = The group was not created. The resource
type of the resulting group does not support deployments.
@@ -1233,7 +1543,24 @@ view_bundle_deployWizard_deployStep=Bundle auf die Zielplattformen
deployen
view_bundle_deployWizard_deploying=Deploying...
view_bundle_deployWizard_deploymentCreated=Deployment angelegt...
view_bundle_deployWizard_deploymentCreatedDetail=Deployment [{0}] mit Beschreibung [{1}]
angelegt
+view_bundle_deployWizard_deploymentCreatedDetail_concise=Sie haben das Deployment [{0}]
erstellt
view_bundle_deployWizard_deploymentScheduled=Bundle-Deployment geplant\!
+view_bundle_deployWizard_deploymentScheduledDetail=Sie haben das Bundle Deployment [{0}]
zur Destinationsgruppe [{1}] terminiert
+view_bundle_deployWizard_deploymentScheduledDetail_concise=Sie haben das Bundle
Deployment terminiert
+view_bundle_deployWizard_destinationCreatedDetail=Sie haben die Destination [{0}] mit der
Beschreibung [{1}] erstellt
+view_bundle_deployWizard_destinationCreatedDetail_concise=Sie haben die Destination [{0}]
erstellt
+view_bundle_deployWizard_error_1=Löschen des neuen Deployment bei Cancel (Abbrechen)
fehlgeschlagen
+view_bundle_deployWizard_error_10=Erstellen der Destination fehlgeschlagen, sie ist
möglicherweise bereits vorhanden. (Hinweis\: FÌr eine vorhandene Destination von
Destinationsansicht deployen)
+view_bundle_deployWizard_error_11=Auffinden definierter Deployments fehlgeschlagen.
+view_bundle_deployWizard_error_12=Auffinden definierter Bundles fehlgeschlagen.
+view_bundle_deployWizard_error_2=Löschen der neuen Destination bei Cancel (Abbrechen)
fehlgeschlagen
+view_bundle_deployWizard_error_3=Terminieren des Deployments fehlgeschlagen\!
+view_bundle_deployWizard_error_4=Terminieren von Deployment fehlgeschlagen\: {0}
+view_bundle_deployWizard_error_5=Erstellen des Deployments fehlgeschlagen\!
+view_bundle_deployWizard_error_6=Erstellen des Deployments fehlgeschlagen\: {0}
+view_bundle_deployWizard_error_7=Abruf des Deployment Namens fehlgeschlagen.
+view_bundle_deployWizard_error_8=Sie mÃŒssen eine gÃŒltige Ressourcengruppe aus dem
Drop-Down-MenÌ wÀhlen
+view_bundle_deployWizard_error_9=Löschen der neuen Destination in nextPage
fehlgeschlagen
view_bundle_deployWizard_error_noBundleConfig=Abruf von Bundle-Zielinformationen
fehlgeschlagen. Ist die von Ihnen ausgewÀhlte Gruppe eine gÌltige kompatible Gruppe, die
Ziel fÃŒr Bundle-Deployments sein kann?
view_bundle_deployWizard_getConfigSkip=Keine Konfiguration nötig fÌr diese
Bundle-Version.
view_bundle_deployWizard_getConfigStep=Deployment-Konfiguration einstellen
@@ -1294,6 +1621,9 @@ view_bundle_deploy_loadBundleFailure=Konnte das Bundle nicht finden
view_bundle_deploy_loadDeployFailure=Konnte Bundle-Deployments nicht laden
view_bundle_deploy_loadFailure=Konnte Bundle-Deployment nicht laden
view_bundle_deploy_name=Name des Deployments
+view_bundle_deploy_selectARow=Zur Anzeige der Installationsdetails eine Reihe wÀhlen
+view_bundle_deploy_tagUpdateFailure=Aktualisierung der Bundle Deployment Tags
fehlgeschlagen
+view_bundle_deploy_tagUpdateSuccessful=Deployment-Tags fÃŒr Bundle erfolgreich
aktualisiert
# #view_bundle_deploy_deployedBy = Deployed By
# #view_bundle_deploy_deploymentPlatforms = Deployment Resource
# #view_bundle_deploy_installDetails = Install Details
@@ -1310,8 +1640,22 @@ view_bundle_deployments=Deployments
view_bundle_dest_backToBundle=ZurÃŒck zum Bundle
view_bundle_dest_baseDirName=Basisverzeichnis
view_bundle_dest_created=Angelegt
+view_bundle_dest_deleteConfirm=Sind Sie sicher, dass Sie diese Bundle-Destination
löschen wollen? Dies löscht es nur aus der Datenbank. Alle auf Remote Rechnern deployten
Bundle-Inhalte an dieser Destination bleiben erhalten.
+view_bundle_dest_deleteFailure=Konnte die Bundle-Destination nicht löschen [{0}]
+view_bundle_dest_deleteSuccessful=Sie haben die Bundle-Destination [{0}] erfolgreich
gelöscht
view_bundle_dest_deployDir=Deploy-Verzeichnis
view_bundle_dest_group=Gruppe
+view_bundle_dest_lastDeployedVersion=Zuletzt deployte Version
+view_bundle_dest_lastDeploymentDate=Letztes Deployment Datum
+view_bundle_dest_lastDeploymentStatus=Letzter Deployment Status
+view_bundle_dest_loadFailure=Konnte Bundle-Destination nicht laden
+view_bundle_dest_loadFailureVersionInfo=Konnte Bundle Destination deployte
Versionsinformationen nicht laden
+view_bundle_dest_purgeConfirm=Dies bereinigt den Bundle Inhalt von allen Remote Rechnern.
Sind Sie sicher, dass Sie dies tun möchten?
+view_bundle_dest_purgeFailure=Bereinigung der Bundle Destination [{0}] von einigen oder
allen Remote Rechnern fehlgeschlagen.
+view_bundle_dest_purgeSuccessful=Sie haben die Bundle-Destination [{0}] erfolgreich von
allen Remote Rechnern bereinigt.
+view_bundle_dest_revertConfirm=Dies rollt alle Remote Rechner zurÃŒck zum vorherigen
Bundle Deployment. Sind Sie sicher, dass Sie dies tun möchten?
+view_bundle_dest_tagUpdateFailure=Konnte die Tags fÃŒr Bundle-Destination nicht
aktualisieren
+view_bundle_dest_tagUpdateSuccessful=Sie haben die Tags fÃŒr Bundle-Destination
erfolgreich aktualisiert
# #view_bundle_dest_lastDeployedVersion = Last Deployed Version
# #view_bundle_dest_lastDeploymentDate = Last Deployment Date
# #view_bundle_dest_lastDeploymentStatus = Last Deployment Status
@@ -1320,8 +1664,10 @@ view_bundle_dest_group=Gruppe
# #view_bundle_dest_tagUpdateFailure = Failed to update bundle destination tags
# #view_bundle_dest_tagUpdateSuccessful = You have successfully updated the bundle
destination tags
view_bundle_destinations=Ziele
+view_bundle_fail_existingName=Erstellen von [{0}] fehlgeschlagen. Der Name wird bereits
verwendet. Bitte versuchen Sie es mit einem anderen Namen.
# #view_bundle_fail_existingName = Failed to create [{0}]. The name is already being
used. Please try another name.
view_bundle_fileListView_fileSize=DateigröÃe
+view_bundle_fileListView_loadFailure=Konnte die Bundle-Datei-Daten nicht laden
# #view_bundle_fileListView_loadFailure = Failed to load bundle file data
view_bundle_fileListView_md5=MD5
view_bundle_fileListView_sha256=SHA256
@@ -1330,13 +1676,24 @@ view_bundle_latestVersion=Aktuelle Version
view_bundle_list_backToAll=ZurÃŒck zur Bundle-Ãbersicht
view_bundle_list_deleteConfirm=Sind Sie sicher, dass Sie dieses Bundle löschen wollen?
view_bundle_list_deleteFailure=Löschen des Bundles [{0}] fehlgeschlagen
+view_bundle_list_deleteSuccessful=Sie haben das Bundle [{0}] erfolgreich gelöscht
+view_bundle_list_deletesFailure=Löschen der Bundles fehlgeschlagen
+view_bundle_list_deletesSuccessful=Sie haben die Bundles erfolgreich gelöscht
# #view_bundle_list_deleteSuccessful = You successfully deleted the bundle named [{0}]
# #view_bundle_list_deletesFailure = Failed to delete the bundles
# #view_bundle_list_deletesSuccessful = You successfully deleted the bundles
view_bundle_list_destinationsCount=Anzahl Ziele
+view_bundle_list_error1=Laden von Bundle zum Deployen [{0}] fehlgeschlagen
+view_bundle_list_error2=Erhalt eines einzelnen Bundles zum Deployen [{0}] fehlgeschlagen
# #view_bundle_list_error1 = Failed to load bundle to deploy [{0}]
# #view_bundle_list_error2 = Failed to get a single bundle to deploy [{0}]
view_bundle_list_error3=Konnte das Bundle nicht laden
+view_bundle_list_error4=Keine Bundles in diesem Repository gefunden
+view_bundle_list_loadFailure=Laden von Bundle zum Deployen [{0}] fehlgeschlagen
+view_bundle_list_loadWithLatestFailure=Konnte Bundle mit aktuellsten Versionsdaten nicht
laden
+view_bundle_list_singleLoadFailure=Erhalt eines einzelnen Bundles zum Deployen [{0}]
fehlgeschlagen
+view_bundle_list_tagUpdateFailure=Aktualisierung von Bundle-Tags fehlgeschlagen
+view_bundle_list_tagUpdateSuccessful=Sie haben die Bundle-Tags erfolgreich aktualisiert
# #view_bundle_list_error4 = No bundles found in this repository
# #view_bundle_list_loadFailure = Failed to load the bundle to be deployed [{0}]
# #view_bundle_list_loadWithLatestFailure = Failed to load bundle with the latest version
data
@@ -1345,9 +1702,33 @@ view_bundle_list_error3=Konnte das Bundle nicht laden
# #view_bundle_list_tagUpdateSuccessful = You have successfully updated the bundle tags
view_bundle_list_versionsCount=Anzahl Versionen
view_bundle_purge=Bereinigen
+view_bundle_recipe=Anleitung
+view_bundle_resDeployDS_loadFailure=Konnte Ressourcen-Deployments nicht laden
# #view_bundle_recipe = Recipe
# #view_bundle_resDeployDS_loadFailure = Failed to load bundle resource deployments
view_bundle_revert=ZurÃŒckrollen
+view_bundle_revertWizard_confirmStep_confirmation=Rolle Live Deployment auf vorheriges
Deployment zurÃŒck. Klicken Sie auf "Next" (Weiter) um fortzufahren...
+view_bundle_revertWizard_confirmStep_failedToFindLiveDeployment=Konnte Live Deployment
nicht finden; kann nicht zurÃŒckrollen
+view_bundle_revertWizard_confirmStep_liveDeployment=Live Deployment
+view_bundle_revertWizard_confirmStep_name=Deployment BestÀtigung zurÌckrollen
+view_bundle_revertWizard_confirmStep_noLiveDeployment=Es wurde kein Live Deployment fÃŒr
die Destination [{0}] gefunden
+view_bundle_revertWizard_confirmStep_noLiveDeployment_concise=Es wurde kein Live
Deployment fÃŒr die Destination gefunden
+view_bundle_revertWizard_confirmStep_noPriorDeployment=Das Live Deployment [{0}] kann
nicht zurÃŒckgerollt werden, weil es kein frÃŒheres Deployment fÃŒr die Destination [{1}]
gibt
+view_bundle_revertWizard_confirmStep_noPriorDeployment_concise=Das Live Deployment kann
nicht zurÃŒckgerollt werden, weil es kein frÃŒheres Deployment gibt
+view_bundle_revertWizard_confirmStep_prevDeployment=Vorheriges Deployment
+view_bundle_revertWizard_getInfoStep_cleanDeploy=Clean Deployment? (löscht ein altes
vorhandenes Deploy-Verzeichnis vor dem Start des ZurÃŒckroll-Deployments)
+view_bundle_revertWizard_getInfoStep_getNameFailure=Erhalt von ZurÃŒckroll Deployment
Namen fehlgeschlagen
+view_bundle_revertWizard_getInfoStep_name=ZurÃŒckroll-Informationen bereitstellen
+view_bundle_revertWizard_getInfoStep_revertDeployDesc=Deploy Beschreibung zurÃŒckrollen
+view_bundle_revertWizard_getInfoStep_revertDeployDescFull=[REVERT From] {0} [REVERT To]
{1}
+view_bundle_revertWizard_getInfoStep_revertDeployName=Deploy Namen zurÃŒckrollen
+view_bundle_revertWizard_revertStep_name=Bundle zu Destinationsplattformen deployen
+view_bundle_revertWizard_revertStep_reverting=Rolle zurÃŒck...
+view_bundle_revertWizard_revertStep_scheduled=Sie haben das ZurÃŒckroll-Deployment
erfolgreich terminiert\!
+view_bundle_revertWizard_revertStep_scheduledDetails=Sie haben das ZurÃŒckrollen des
Bundle Deployment [{0}] von Ressourcen Gruppe [{1}] erfolgreich terminiert
+view_bundle_revertWizard_revertStep_scheduledFailure=Terminieren des
ZurÃŒckroll-Deployments fehlgeschlagen\!
+view_bundle_revertWizard_title=Bundle zurÃŒckrollen
+view_bundle_revertWizard_windowTitle=Bundle ZurÃŒckroll Wizard
view_bundle_tree_loadFailure=Konnte die Bundle-Daten nicht laden
view_bundle_tree_unassigned_desc=Dies sind Bundles die noch nicht mit einer Bundle-Gruppe
assoziiert sind.
view_bundle_tree_unassigned_name=Nicht zugewiesene Bundles
@@ -1414,6 +1795,7 @@ view_configEdit_invalidListSizeMax=Die Liste sollte höchstens {0}
Reihe(n) enth
view_configEdit_invalidListSizeMin=Die Liste sollte mindestens {0} Reihe(n) enthalten
view_configEdit_invalidListSizeMinMax=Die Liste sollte mindestens {0} und höchstens {1}
Reihe(n) enthalten
view_configEdit_jumpToSection=Zum Abschnitt springen
+view_configEdit_maxBoundsExceeded=Kann keinen weiteren Eintrag hinzufÃŒgen, da die
maximalen GröÃeneinschrÀnkungen erreicht wurden\: {0}
view_configEdit_minBoundsExceeded=Kann diesen Eintrag nicht löschen, da das Minimum
eingestellt wurde auf\: {0}
# #view_configEdit_maxBoundsExceeded = Cannot add another entry because the maximum size
bounds has been met: {0}
# #view_configEdit_minBoundsExceeded = Cannot delete this entry as the minimum has been
set to: {0}
@@ -1439,11 +1821,31 @@
view_configurationDetails_configNotUpdatedDueToNoChange=Konfiguration wurde nich
view_configurationDetails_error_updateFailure=Konnte die Konfiguration nicht
aktualisieren
view_configurationDetails_messageConcise=Konfiguration aktualisiert - aktuelle Version is
{0}
view_configurationDetails_messageDetailed=Konfiguration der Ressource [{1}] aktualisiert
auf Version [{0}].
+view_configurationDetails_noConfigurationFetched=Es wurde keine Konfiguration abgerufen.
Dies bedeutet, dass entweder das Laden der Konfiguration durch den Plugin fehlgeschlagen
ist oder dass die Konfigurations-Collection lediglich in den Verbindungseinstellungen
abgeschaltet ist.
view_configurationDetails_noPermission=Sie sind nicht berechtigt die Konfiguration dieser
Ressource zu bearbeiten.
view_configurationDetails_somePropertiesInvalid=Die folgenden
Konfigurations-Einstellungen haben ungÃŒtige Werte \: {0}. Die Werte mÃŒssen korrigiert
werden, ehe die Konfiguration gespeichert werden kann.
+view_configurationHistoryDetails_error_loadFailure=Konnte den Verlauf der Konfiguration
nicht laden.
+view_configurationHistoryList_cannotDeleteCurrent=Eines der gewÀhlten Verlaufselemente
reprÀsentiert die aktuelle Konfiguration - Sie können es nicht löschen.
+view_configurationHistoryList_cannotDeleteGroupItems=Eines oder mehrere der gewÀhlten
Konfigurationsverlaufselemente ist/sind Teil eines Gruppenkonfigurations-Updates. Sie
mÃŒssen dieses ÃŒbergeordnete Gruppenverlaufselement bereinigen, ehe Sie dessen einzelne
Ressourcen Verlaufselemente löschen können.
+view_configurationHistoryList_delete_failure=Konnte die Konfigurationsverlaufselemente
nicht löschen.
+view_configurationHistoryList_delete_success=Sie haben die gewÀhlten
Konfigurationsverlaufselemente erfolgreich gelöscht.
+view_configurationHistoryList_rollback=Rollback
+view_configurationHistoryList_rollback_failure=Konnte die Konfiguration nicht
zurÃŒcksetzen. Die ursprÃŒngliche Konfiguration ist noch wirksam.
+view_configurationHistoryList_rollback_success=Sie haben die Konfiguration erfolgreich
zur gewÀhlten vorherigen Konfiguration zurÌckgesetzt.
+view_configurationHistoryList_table_clickStatusIcon=FÃŒr mehr Details auf das Status Icon
klicken
+view_configurationHistoryList_table_statusFailure=Diese Konfigurationsaktualisierung ist
fehlgeschlagen
+view_configurationHistoryList_table_statusInprogress=Diese Konfigurationsaktualisierung
lÀuft noch
+view_configurationHistoryList_table_statusNochange=Es wurden keine Ãnderungen an dieser
Konfiguration vorgenommen
+view_configurationHistoryList_table_statusSuccess=Diese Konfigurationsaktualisierung war
erfolgreich
# #view_configurationHistoryDetails_error_loadFailure = Unable to load configuration
history.
# #view_configurationHistoryList_itemNamePlural = configuration history items
view_configurationHistoryList_title=KonfigurationsÀnderungen
+view_connectionSettingsDetails_allPropertiesValid=Alle Verbindungseinstellungen haben
gÌltige Werte, daher können die Einstellungen jetzt gespeichert werden.
+view_connectionSettingsDetails_error_updateFailure=Verbindungseinstellungen konnten nicht
aktualisiert werden.
+view_connectionSettingsDetails_messageConcise_updateSuccess=Aktualisierung fÃŒr die
Verbindungseinstellungen initiiert.
+view_connectionSettingsDetails_messageDetailed_updateSuccess=Aktualisierung von
Verbindungseinstellungen initiiert fÃŒr Ressource [{0}].
+view_connectionSettingsDetails_noPermission=Sie sind nicht berechtigt die
Verbindungseinstellungen dieser Ressource zu bearbeiten.
+view_connectionSettingsDetails_somePropertiesInvalid=Die folgenden
Verbindungseinstellungen haben ungÃŒtige Werte \: {0}. Die Werte mÃŒssen korrigiert
werden, ehe die Einstellungen gespeichert werden können.
# #view_connectionSettingsDetails_allPropertiesValid = All connection settings have valid
values, so the settings can now be saved.
# #view_connectionSettingsDetails_error_updateFailure = Failed to update connection
settings.
# #view_connectionSettingsDetails_messageConcise_updateSuccess = Connection settings
update initiated.
@@ -1465,8 +1867,21 @@ view_dashboard_favorites_error1=Konnte die Ressoucen-Lesezeichen
nicht laden
view_dashboardsManager_error1=Konnte das neue Dashboard nicht hinzufÃŒgen
view_dashboardsManager_message_title_details=<h1>Willkommen bei
{0}</h1>\n<p>Dieses Dashboard kan durch BetÀtigen des
Bearbeitungsmodus-Knopfes verÀndert werden.</p>\n<p>Was möchten Sie
tun?</p>\n<p> <a href\="{1}">Neu gefundene
Ressourcen importieren.</a></p>\n<p> <a
href\="{2}">Ressourcen
suchen.</a></p>\n<p> <a
href\="{3}">Hilfe und Dokumentation ansehen.</a></p>
view_dashboards_confirm1=Sind Sie sicher, dass Sie löschen möchten
+view_dashboards_portlets_refresh_fail1=Aktualisierung von Auto-refresh Intervall
fehlgeschlagen
+view_dashboards_portlets_refresh_fail2=Deaktivierung von erneutem Laden von Auto-refresh
Intervall fehlgeschlagen
+view_dashboards_portlets_refresh_multiple_min={0} Minuten
+view_dashboards_portlets_refresh_none=Kein Aktualisieren
+view_dashboards_portlets_refresh_one_min=1 Minute
+view_dashboards_portlets_refresh_success1=Aktualisierter Intervall fÃŒr auto-refresh
+view_dashboards_portlets_refresh_success2=Stoppe erneutes Laden fÃŒr auto-refresh
view_dashboards_title=Dashboard
view_drift_button_detectNow=Jetzt ermitteln
+view_drift_button_pinToDef=An Definition pinnen
+view_drift_button_pinToDef_confirm=Pinning (Festmachen) stellt diesen Schnappschuss als
Schnappschuss 0 fÃŒr die Definition ein. Alle anderen vorhandenen SchnappschÃŒsse werden
aus der Definition entfernt. Die Definition wird als "pinned" (festgemacht)
gekennzeichnet und nachfolgende Drifts werden stets gegen den festgemachten Schnappschuss
gemeldet. Soll dieser Schnappschuss an der Definition festgemacht werden?
+view_drift_button_pinToTemplate=An Vorlage festmachen
+view_drift_button_pinToTemplate_confirm=Nach dem Festmachen wird dieser Schnappschuss als
erster Schnappschuss fÃŒr alle mittels der Vorlage erstellten Definitionen verwendet.
Falls an einer bestehenden Vorlage festgemacht, so werden die bestehenden Definitionen der
Vorlage an dem neuen ersten Schnappschuss festgemacht und die bestehenden SchnappschÃŒsse
werden entfernt. Mit Vorlagenauswahl fortfahren?
+view_drift_carousel_sizeFilterLabel=Schnappschuss Anzeige Max
+view_drift_carousel_startFilterLabel=Schnappschuss Start
# #view_drift_button_pinToDef = Pin to Definition
# #view_drift_button_pinToDef_confirm = Pinning will set this snapshot as snapshot 0 for
the definition. All other existing snapshots will be removed from the definition. The
definition will be be marked as pinned and subsequent drift will always be reported
against the pinned snapshot. Pin this snapshot to the definition?
# #view_drift_button_pinToTemplate = Pin to Template
@@ -1475,8 +1890,27 @@ view_drift_button_detectNow=Jetzt ermitteln
# #view_drift_carousel_startFilterLabel = Snapshot Start
view_drift_category_fileAdded=Datei hinzugefÃŒgt
view_drift_category_fileChanged=Datei geÀndert
+view_drift_category_fileNew=Neu aufgefunden
# #view_drift_category_fileNew = Newly Detected
view_drift_category_fileRemoved=Datei gelöscht
+view_drift_confirm_deleteAllDefs=Alle Drift-Erkennungsdefinitionen löschen?
+view_drift_confirm_deleteDefs=Die ausgewÀhlte(n) Drift-Erkennungsdefinition(en)
löschen?
+view_drift_confirm_deleteTemplate=Warnung\! Das Löschen dieser Vorlage löscht auch alle
angehÀngten Drift-Definitionen. Diese angehÀngten Definitionen sowie alle deren
SchnappschÌsse werden dauerhaft vom System entfernt. Nicht angehÀngte Definitionen
werden nicht entfernt. Sind Sie sicher, dass Sie fortfahren möchten?
+view_drift_failure_deleteDefs=Löschen einiger oder alle Drift-Erkennungsdefinitionen
fehlgeschlagen.
+view_drift_failure_deleteTemplates=Löschen einiger oder alle Drift Vorlagen
fehlgeschlagen
+view_drift_failure_detectNow=Absenden von Anfrage zur AusfÃŒhrung der Drift-Erkennung
fehlgeschlagen
+view_drift_failure_load=Abruf von Drift Instanzen fehlgeschlagen
+view_drift_failure_pinToDef=Festmachen von Schnappschuss an Definition fehlgeschlagen
+view_drift_success_defUpdated=Drift Erkennung Definition aktualisiert und wird
Auswirkungen auf die nÀchste ErkennungsausfÌhrung haben.
+view_drift_success_delete=Erfolgreiche Löschung von {0} Drift Instanzen
+view_drift_success_deleteDefs=Erfolgreiche Löschung von {0} Drift Erkennung
Definitionen
+view_drift_success_deleteTemplate=Erfolgreiche Löschung von {0} Drift Vorlagen
+view_drift_success_detectNow=Absenden von Anfrage zur AusfÃŒhrung der Drift-Erkennung
erfolgreich
+view_drift_success_pinToDef=Erfolgreiches Festmachen von Schnappschuss {0} an Drift
Definition.
+view_drift_success_templateUpdated=Drift Vorlage aktualisiert und Ãnderungen an
angehÀngte Definitionen gepusht.
+view_drift_table_attached=AngehÀngt?
+view_drift_table_baseDir=Basis-Verzeichnis
+view_drift_table_driftHandlingMode=Der Umgang mit Drift
# #view_drift_confirm_deleteAllDefs = Delete all drift detection definitions?
# #view_drift_confirm_deleteDefs = Delete the selected drift detection definition(s)?
# #view_drift_confirm_deleteTemplate = Warning! Deleting this template will also cause
all attached drift definitions to be deleted as well. Those attached definitions along
with all of their snapshots will be permanently removed from the system. Detached
definitions will not be removed. Are you sure you want to continue?
@@ -1497,7 +1931,13 @@ view_drift_category_fileRemoved=Datei gelöscht
# #view_drift_table_driftHandlingMode = Drift Handling
view_drift_table_driftHandlingMode_normal=normal
view_drift_table_driftHandlingMode_plannedChanges=geplante Ãnderungen
+view_drift_table_hover_defNotPinned=Die Drift Definition ist nicht festgemacht. Zur
Ansicht des ersten Schnappschusses klicken.
+view_drift_table_hover_defPinned=Die Drift Definition ist an ihrem ersten Schnappschuss
festgemacht. FÃŒr Ansicht des ersten Schnappschusses klicken.
+view_drift_table_hover_edit=Zur Ansicht oder Bearbeitung der Drift Definition oder
Vorlagen Eigenschaften klicken.
+view_drift_table_hover_outOfCompliance_drift=Drift vorhanden
view_drift_table_hover_outOfCompliance_noBaseDir=Das Basisverzeichnis existiert nicht
+view_drift_table_hover_templateNotPinned=Die Drift Vorlage ist nicht an einem
Schnappschuss festgemacht.
+view_drift_table_hover_templatePinned=Die Drift Vorlage ist an einem Schnappschuss
festgemacht. FÃŒr Ansicht des festgemachten Schnappschusses klicken.
# #view_drift_table_hover_defNotPinned = The drift definition is not pinned Click to
view the initial snapshot.
# #view_drift_table_hover_defPinned = The drift definition is pinned to its initial
snapshot. Click to view the initial snapshot.
# #view_drift_table_hover_edit = Click to view or edit the drift definition or template
properties.
@@ -1507,11 +1947,44 @@ view_drift_table_hover_outOfCompliance_noBaseDir=Das
Basisverzeichnis existiert
# #view_drift_table_hover_templatePinned = The drift template is pinned to a snapshot.
Click to view the pinned snapshot.
view_drift_table_newFile=Neue Datei
view_drift_table_oldFile=Alte Datei
+view_drift_table_pinned=Festgemacht?
+view_drift_table_resourceDef=Ressource Drift Erkennung Definition
+view_drift_table_resourceHistory=Ressource Drift Historie
view_drift_table_snapshot=Schnappschuss
view_drift_table_snapshotTime=Schnappschuss Zeit
view_drift_table_template=Vorlage
+view_drift_table_title_initialSnapshot=Erster Schnappschuss fÃŒr Definition [{0}] \:
Pinned \= [{1}]
view_drift_table_title_snapshot=Schnappschuss [{0}] fÃŒr Definition [{1}]
+view_drift_table_title_templateSnapshot=Festgemachter Schnappschuss fÃŒr Vorlage [{0}]
+view_drift_wizard_addDef_failure=HinzufÃŒgen der neuen Drift Erkennung Definition [{0}]
fehlgeschlagen
+view_drift_wizard_addDef_infoStepHelp=Jede Drift Erkennungsdefinition beschreibt einen
Satz Dateien, fÃŒr die die Drift Ãberwachung durchgefÃŒhrt wird. Die Definition kann
aktiviert und deaktiviert sein, definiert den ErkennungsausfÃŒhrungsintervall und legt ein
Basisverzeichnis und optionale Dateifilter fest. FÃŒr jeden Ressourcentyp der Drift
Erkennung bietet gibt es eine oder mehrere vordefinierte Vorlagen zur Verwendung als
Startdefinition, die anschlieÃend bearbeitet werden können.
+view_drift_wizard_addDef_infoStepName=WÀhlen Sie die Vorlage fÌr die neue Drift
Erkennungsdefinition
+view_drift_wizard_addDef_success=Neue Drift Erkennungsdefinition [{0}] erfolgreich
hinzugefÃŒgt. Agent(en) wird/werden aktualisiert.
+view_drift_wizard_addDef_templatePrompt=Drift Definition Vorlagen
+view_drift_wizard_addDef_title=Drift Erkennung Definition fÃŒr Ressource vom Typ [{0}]
hinzufÃŒgen
+view_drift_wizard_addDef_windowTitle=Drift Erkennung Definition Wizard hinzufÃŒgen
+view_drift_wizard_addTemplate_failure=HinzufÃŒgen der neuen Drift Vorlage [{0}]
fehlgeschlagen
+view_drift_wizard_addTemplate_infoStepHelp=Jede Drift Vorlage ist von einer bestehenden
Vorlage abgeleitet. Dies bietet eine schnelle Weise der Erstellung neuer Vorlagen, die
bestehenden Vorlagen Àhneln oder die ihren Ursprung in Plugin-definierten Vorlagen haben.
Wie auch eine Drift Definition beschreibt die Vorlage einen Satz von Dateien, fÃŒr die
Drift Ãberwachung durchgefÃŒhrt wird. Je nach Situation können einer von einer Vorlage
abgeleiteten Definition Ãnderungen am Dateisatz oder anderen Einstellungen gestattet oder
nicht gestattet werden. Die Vorlagennamen mÃŒssen innerhalb eines Ressourcentyps eindeutig
sein.
+view_drift_wizard_addTemplate_infoStepName=Startvorlage auswÀhlen
+view_drift_wizard_addTemplate_success=HinzufÃŒgen der neuen Drift Vorlage [{0}]
erfolgreich.
+view_drift_wizard_addTemplate_title=Drift Definition Vorlage fÃŒr Typ [{0}] hinzufÃŒgen
+view_drift_wizard_addTemplate_windowTitle=Drift Definition Vorlage Wizard hinzufÃŒgen
+view_drift_wizard_pinTemplate_confirmNotPinned=Nach dem Festmachen besitzt jede aktuelle
und zukÃŒnftige Drift Definition fÃŒr die Vorlage ihren ersten Schnappschuss, der auf den
festgemachten Schnappschuss der Vorlage eingestellt ist. Vorhandene Definitionen fÃŒr
diese Vorlage werden auf den neuen ersten Schnappschuss zurÃŒckgesetzt und alle
bestehenden SchnappschÃŒsse werden entfernt. Mit dem Festmachen der Vorlage an den
Schnappschuss fortfahren?
+view_drift_wizard_pinTemplate_confirmPinned=Warnung\! Diese Vorlage ist bereits
festgemacht. Die Vorlage kann erneut an diesem Schnappschuss festgemacht werden. Nach dem
erneuten Festmachen ist jede aktuelle und zukÃŒnftige Drift Definition fÃŒr die Vorlage
mit ihrem ersten Schnappschuss auf den festgemachten Schnappschuss der Vorlage
eingestellt. Bestehende Definitionen fÃŒr diese Vorlage werden auf den ersten
Schnappschuss zurÃŒckgesetzt und alle bestehenden SchnappschÃŒsse zurÃŒckgesetzt. Mit dem
erneuten Festmachen der Vorlage mit diesem neuen Schnappschuss fortfahren?
view_drift_wizard_pinTemplate_duplicate_name_error=Vorlagen Name muss eindeutig sein
+view_drift_wizard_pinTemplate_failure=Festmachen des Schnappschusses an Drift Vorlage
[{0}] fehlgeschlagen
+view_drift_wizard_pinTemplate_infoStepExistingTemplate=An bestehender Vorlage festmachen
+view_drift_wizard_pinTemplate_infoStepHelp=Nach dem Festmachen besitzt jede aktuelle und
zukÃŒnftige Drift Definition fÃŒr die Vorlage ihren ersten Schnappschuss, der auf den
festgemachten Schnappschuss der Vorlage eingestellt ist. Und die Definition selbst wird
als festgemacht markiert. Dies wird zur Erkennung von Drift von einem erwarteten Dateisatz
verwendet. Vorhandene Definitionen fÃŒr diese Vorlage werden auf den neuen ersten
Schnappschuss zurÃŒckgesetzt und alle bestehenden SchnappschÃŒsse werden entfernt.
+view_drift_wizard_pinTemplate_infoStepName=WÀhlen Sie die festzumachende Vorlage
+view_drift_wizard_pinTemplate_infoStepNewTemplate=An neuer Vorlage festmachen (abgeleitet
von der Drift Definition des Schnappschusses)
+view_drift_wizard_pinTemplate_infoStepRadioHelp=Der Schnappschuss kann an einer neuen
oder bestehenden Drift Vorlage festgemacht werden. Die "New Template" Option
(neue Vorlage) gestattet es dem Benutzer eine vertrauenswÃŒrdige Definition und einen
Schnappschuss auf Ressourcenebene bis zur Typebene zu begÃŒnstigen. Die neue kann dann an
Mitgliedern des Typs angewendet werden. Die neue Vorlage ist anfangs eine Kopie der Drift
Definition des Schnappschusses, aber sie kann im nÀchsten Schritt bearbeitet werden. Der
Name sollte geÀndert werden und muss ein eindeutiger Drift Vorlagen Name fÌr den Typ
sein. Die "Existing Template" Option (vorhandene Option) gestattet dem Benutzer
das Festmachen oder das erneute Festmachen mit dem gewÀhlten Schnappschuss. Um gÌltig zu
sein muss die vorhandene Vorlage dieselben Verzeichnisse ÃŒberwachen, die die Definition
des Schnappschusses. Das AuswahlkÀstchen zeigt nur gÌltige bestehende Vorlagen an. Falls
es keine gÃŒltigen bestehenden
Vorlagen gibt, so kann diese Option nicht gewÀhlt werden.
+view_drift_wizard_pinTemplate_infoStepRadioTitle=Vorlagenauswahl
+view_drift_wizard_pinTemplate_infoStepSelectBlocked=Es sind keine bestehenden Vorlagen
vorhanden, die dieselben Verzeichnisse ÃŒberwachen wie die Definition des Schnappschusses.
WÀhlen Sie die "New Template" Option (neue Vorlage) um fortzufahren.
+view_drift_wizard_pinTemplate_infoStepSelectTitle=Bestehende Vorlagen
+view_drift_wizard_pinTemplate_success=Festmachen der neuen Drift Vorlage [{0}]
erfolgreich.
+view_drift_wizard_pinTemplate_title=Schnappschuss [{0}] von Definition [{1}] an Drift
Vorlage fÃŒr Typ [{2}] festmachen
+view_drift_wizard_pinTemplate_windowTitle=Drift Definition Vorlage Wizard festmachen
+view_dynagroup_children=DynaGroup Kinder
# #view_drift_table_pinned = Pinned?
# #view_drift_table_resourceDef = Resource Drift Detection Definition
# #view_drift_table_resourceHistory = Resource Drift History
@@ -1574,10 +2047,14 @@ view_dynagroup_exprBuilder_expressionType_resource=Ressource
view_dynagroup_exprBuilder_expressionType_resourceCategory=Ressourcen-Kategorie
view_dynagroup_exprBuilder_expressionType_resourceConfig=Ressourcen-Konfiguration
view_dynagroup_exprBuilder_expressionType_resourceType=Ressourcen-Typ
+view_dynagroup_exprBuilder_expressionType_tooltip=Der Type von Eigenschaft, den dieser
Ausdruck einschaltet\:<br/> <b>Ressource</b>\: Eine
Ressourceneigenschaft wie deren Name oder Version<br/>
<b>Ressourcetyp</b>\: Suche nach Ressourcen eines bestimmten Typs<br/>
<b>Ressourcenkategorie</b>\: Suche nach Ressourcen nach Kategorie\: Plattform,
Server, Dienst<br/> <b>Merkmal</b>\: Ressourcen, die ausgewÀhlte Werte
fÃŒr ein ÃŒberwachtes Merkmal besitzen<br/> <b>Plugin
Konfiguration</b>\: Suche nach der Plugin Komponente Konfigurationseinstellung der
Komponente<br/> <b>Ressourcenkonfiguration</b>\: Suche nach der
Konfigurationsenstellung der verwalteten Ressource
view_dynagroup_exprBuilder_expressionType_trait=Trait
+view_dynagroup_exprBuilder_expression_tooltip=Dies ist der vollstÀndige Ausdruck, der
von den Auswahlen im Formular unten reprÀsentiert wird. Dieser Text wird dem Text Ihres
Gruppendefinitionsausdrucks hinzugefÌgt, wenn Sie auf die SchaltflÀche "Add
Expression" (Ausdruck hinzufÃŒgen) klicken.
view_dynagroup_exprBuilder_groupBy=Gruppieren nach
+view_dynagroup_exprBuilder_groupBy_tooltip=Durch GroupBy schwenkt das System die Werte
der eingegebenen AusdrÃŒcke und erstellt eine separate Gruppe fÃŒr jeden Wert. Zum
Beispiel GroupBy am Cluster Namen zur Erstellung einer Gruppe fÃŒr jeden Cluster mit allen
Cluster Mitgliedern darin.
# #view_dynagroup_exprBuilder_groupBy_tooltip = groupby will cause the system to pivot on
the values from the entered expressions creating a separate group for each value. For
example, groupby on the cluster name to create a group for each cluster with all cluster
members in it.
view_dynagroup_exprBuilder_memberOf=Mitglied von
+view_dynagroup_exprBuilder_memberOf_tooltip=memberof schrÀnkt die dynagroup Mitglieder
auf einen Untersatz der festgelegten Ressourcengruppe ein. Die Festlegung mehrerer
memberof Bedingungen schrÀnkt die dynagroup Mitglieder auf einen Untersatz der
Vereinigung von Mitgliedern der festgelegten Gruppen ein.
# #view_dynagroup_exprBuilder_memberOf_tooltip = memberof will restrict the dynagroup
members to be a subset of the specified resource group. Specifying multiple memberof
conditions will restrict the dynagroup members to be a subset of the union of members of
the specified groups.
view_dynagroup_exprBuilder_noPlugins=--Keine Plugins--
view_dynagroup_exprBuilder_noProperties=--Keine Eigenschaften--
@@ -1585,13 +2062,25 @@ view_dynagroup_exprBuilder_noResourceTypes=--Keine
Ressourcen-Typen--
view_dynagroup_exprBuilder_pluginLoadFailure=Kann die Liste der Plugins nicht laden
view_dynagroup_exprBuilder_propLoadFailure=Kann die Liste der Eigenschaften nicht laden
view_dynagroup_exprBuilder_propertyName=Name der Eigenschaft
+view_dynagroup_exprBuilder_propertyName_tooltip=Der Name der abzufragenden Eigenschaft.
Dies wird sowohl durch den Ausdruckstyp als auch den Ressourcentyp definiert.
+view_dynagroup_exprBuilder_resTypeLoadFailure=Erhalt der Liste von Ressourcentypen fÃŒr
Plugin [{0}] nicht möglich
+view_dynagroup_exprBuilder_resource=Ressource
+view_dynagroup_exprBuilder_resourceType=Ressourcen-Typ
+view_dynagroup_exprBuilder_resourceType_tooltip=Der Ressourcentyp
+view_dynagroup_exprBuilder_resource_child=Child
+view_dynagroup_exprBuilder_resource_grandparent=Grandparent
view_dynagroup_exprBuilder_resource_greatGrandparent=GreatGrandparent
view_dynagroup_exprBuilder_resource_greatGreatGrandparent=GreatGreatGrandparent
view_dynagroup_exprBuilder_resource_parent=Eltern
view_dynagroup_exprBuilder_resource_resource=Ressource
view_dynagroup_exprBuilder_resource_tooltip=WÀhlen Sie die Ebene der Ressource, die Sie
wÀhlen möchten. Wenn Sie zum Beispiel "parent" wÀhlen, so finden Sie
Ressourcen, deren ÃŒbergeordnete Ressource ("Parent" Ressource) mit dem Rest des
Ausdrucks ÃŒbereinstimmt.
view_dynagroup_exprBuilder_savedExpression=Gespeicherter Ausdruck
+view_dynagroup_exprBuilder_title=Expression-Builder
+view_dynagroup_exprBuilder_unset=Ungesetzt
+view_dynagroup_exprBuilder_unset_tooltip=Unset (Ungesetzt) findet alle Werte mit einem
Nullwert in der Datenbank. Dies ist nicht mittels des "\=" Operators möglich,
wegen der Art undWeise auf die Datenbanken Daten speichern und abfragen.
+view_dynagroup_exprBuilder_value_tooltip=Der String-Wert fÃŒr den abzufragenden Ausdruck
view_dynagroup_expression=Ausdruck
+view_dynagroup_expressionBuilderIconTooltip=Expression Builder...
view_dynagroup_expressionSet=Ausdruck
view_dynagroup_lastCalculationTime=Zeitpunkt letzte Berechnung
view_dynagroup_loadDefinitionFailure=Konnte die Gruppendefinition [{0}] nicht laden
@@ -1616,6 +2105,8 @@ view_dynagroup_template_customExpression=Benutzerdefinierter
Ausdruck...
view_dynagroup_template_downedResources=Alle Ressourcen derzeit auÃer Betrieb
view_dynagroup_template_jbossas4_clusters=JBossAS 4 - Cluster
view_dynagroup_template_jbossas4_earClusters=JBossAS 4 - Geclusterte EARs
+view_dynagroup_template_jbossas4_hostingApp=JBossAS 4 - Alle, die eine beliebige Version
von "my" App hosten
+view_dynagroup_template_jbossas4_nonsecured=JBossAS 4 - Alle nicht gesicherten
view_dynagroup_template_jbossas4_uniqueVersions=JBossAS 4 - Eindeutige Versionen
view_dynagroup_template_jbossas5_clusters=JBossAS 5/6 - Cluster
view_dynagroup_template_platforms=Plattform Ressourcen im Inventar
@@ -1652,17 +2143,25 @@ view_group_detail_failRecursiveChange=Konnte die Einstellung
''Rekursiv'' fÃŒr d
view_group_detail_implicitAvail=Group availability for all members (includes recursive
members).
view_group_detail_recursiveChange=Sie haben erfolgreich die
''Rekursiv''-Einstellung fÌr die Gruppe [{0}] geÀndert.
view_group_inventory_activity_no_recent_metrics=Diese Gruppe hat keine aktuellen
Metriken
+view_group_meas_schedules_title=Gruppen Metrik Collection ZeitplÀne
# #view_group_meas_schedules_title = Group Metric Collection Schedules
view_group_membership_failFetch=Konnte die Ressourcen-Gruppe nicht laden
view_group_membership_saveFailure=Aktualisierung der Mitgliedschaft von Gruppe [{0}]
fehlgeschlagen
view_group_membership_saveSuccessful=Sie haben die die Mitgliedschaft von Gruppe [{0}]
aktualisiert
+view_group_operationScheduleDetails_failedToLoadMembers=Konnte die Gruppen Mitglieder
Ressourcen nicht laden.
view_group_operationScheduleDetails_field_execute=AusfÃŒhren
+view_group_operationScheduleDetails_field_haltOnFailure=Bei Fehlschlagen anhalten?
view_group_operationScheduleDetails_memberResource=Mitglied Ressource
+view_group_operationScheduleDetails_value_parallel=parallel
+view_group_operationScheduleDetails_value_sequential=in der unten festgelegten
Reihenfolge (Mitglieder Ressourcen zur Ãnderung der Reihenfolge ziehen und ablegen)
view_group_pluginConfig_edit_currentGroupProperties=Aktuelle Gruppeneigenschaften
+view_group_pluginConfig_edit_invalid=Die folgenden Verbindungseinstellungseigenschaften
haben ungÃŒtige Werte und mÃŒssen korrigiert werden, ehe die Verbindungseinstellungen
gespeichert werden können\: [{0}]
view_group_pluginConfig_edit_noperm=Sie sind nicht berechtigt diese Gruppen
Verbindungseinstellungen zu bearbeiten
+view_group_pluginConfig_edit_saveFailure=Die Initiierung der Gruppen
Verbindungseinstellungsaktualisierungen fÃŒr die [{0}] kompatible Gruppe namens [{1}] ist
fehlgeschlagen
view_group_pluginConfig_edit_saveInitiated_concise=Die Gruppen
Verbindungseinstellungsaktualisierungen wurden instantiiert
view_group_pluginConfig_edit_saveInitiated_full=Die Gruppen
Verbindungseinstellungsaktualisierungen wurden instantiiert fÃŒr die [{0}] kompatible
Gruppe namens [{1}]
view_group_pluginConfig_edit_saveTooltip=Die Verbindungseinstellungen aller
Gruppenmitglieder aktualisieren
+view_group_pluginConfig_edit_valid=Alle Verbindungseinstellungseigenschaften haben
gÌltige Werte, daher können die Verbindungseinstellungen jetzt gespeichert werden.
# #view_group_membership_saveFailure = Failed to update membership of group [{0}]
# #view_group_membership_saveSuccessful = You have updated the membership of group [{0}]
# #view_group_pluginConfig_edit_currentGroupProperties = Current Group Properties
@@ -1674,20 +2173,25 @@ view_group_pluginConfig_edit_saveTooltip=Die
Verbindungseinstellungen aller Grup
# #view_group_pluginConfig_edit_saveTooltip = Update the connection settings of all group
members
# #view_group_pluginConfig_edit_valid = All connection setting properties have valid
values, so the connection settings can now be saved
view_group_pluginConfig_members_fetchFailure=Failed to get plugin config update history
for members of group [{0}]
+view_group_pluginConfig_members_fetchFailureConn=Abruf von Mitglieder
Verbindungseinstellungen fehlgeschlagen fÃŒr [{0}]
+view_group_pluginConfig_members_fetchFailureConnInProgress=Eine Gruppen Plugin
Konfigurationsaktualisierung lÀuft derzeit. Sie mÌssen warten, bis die Aktualisierung
abgeschlossen ist, ehe Sie die Gruppeneinstellungen ansehen können.
view_group_pluginConfig_members_statusDetails=Status Details
view_group_pluginConfig_members_statusFailure=Die Konfigurationsaktualisierung ist aus
unbekanntem Grund fehlgeschlagen
view_group_pluginConfig_members_statusInprogress=Diese Konfigurationsaktualisierung
lÀuft noch
view_group_pluginConfig_members_statusNochange=Es wurden keine Ãnderungen an dieser
Konfiguration vorgenommen
view_group_pluginConfig_members_statusSuccess=Diese Konfigurationsaktualisierung war
erfolgreich
+view_group_pluginConfig_members_title=Gruppen Verbindungseinstellungen Mitglieder
Verlauf
view_group_pluginConfig_table_clickStatusIcon=FÃŒr mehr Details auf das Status Icon
klicken
view_group_pluginConfig_table_deleteFailure=Konnte die Gruppen Plugin Config History
nicht löschen
view_group_pluginConfig_table_deleteSuccessful=Sie haben [{0}] VerlaufseintrÀge
gelöscht
view_group_pluginConfig_table_failFetch=Konnte die Gruppen Plugin Config History nicht
abrufen
+view_group_pluginConfig_table_msg1=Mitglieder Historie fÃŒr Status jeder einzelnen
Ressource ansehen
view_group_pluginConfig_table_statusDetails=Status Details
view_group_pluginConfig_table_statusFailure=Diese Konfigurationsaktualisierung ist
fehlgeschlagen
view_group_pluginConfig_table_statusInprogress=Diese Gruppen Konfigurationsaktualisierung
lÀuft noch
view_group_pluginConfig_table_statusNochange=Es wurden keine Ãnderungen an dieser
Gruppen Konfiguration vorgenommen
view_group_pluginConfig_table_statusSuccess=Diese Gruppen Konfigurationsaktualisierung
ist fehlgeschlagen
+view_group_pluginConfig_table_title=Verlauf der Gruppen Verbindungs-Einstellungen
view_group_pluginConfig_table_viewMemberHistory=Mitglieder Historie ansehen
view_group_pluginConfig_table_viewSettings=Einstellungen ansehen
# #view_group_pluginConfig_members_statusFailure = This configuration update failed for
an unknown reason
@@ -1712,21 +2216,31 @@ view_group_pluginConfig_view_noperm=Sie haben nicht die
Berechtigung, um die Ver
view_group_resConfig_edit_invalid=Die folgenden Konfigurations-Einstellungen haben
ungÌtige Werte und mÌssen korrigiert werden, um die Einstellungen speichen zu können\:
[{0}]
view_group_resConfig_edit_loadFail=Abruf von Mitglieder Ressourcen Konfigurationen
fehlgeschlagen fÃŒr [{0}]
view_group_resConfig_edit_noperm=Sie sind nicht berechtigt diese Gruppen Konfiguration zu
bearbeiten
+view_group_resConfig_edit_saveFailure=Die Initiierung der Gruppen
Konfigurationsaktualisierungen fÃŒr die [{0}] kompatible Gruppe namens [{1}] ist
fehlgeschlagen
+view_group_resConfig_edit_saveInitiated_concise=Die Gruppen
Konfigurationsaktualisierungen wurden initiiert
view_group_resConfig_edit_saveInitiated_full=Die Gruppen Konfigurationsaktualisierungen
wurden instantiiert fÃŒr die [{0}] kompatible Gruppe namens [{1}]
view_group_resConfig_edit_saveTooltip=Die Konfigurationen aller Gruppenmitglieder
aktualisieren
view_group_resConfig_edit_valid=Alle Konfigurationseigenschaften haben gÃŒltige Werte,
daher kann die Konfiguration jetzt gespeichert werden
+view_group_resConfig_members_fetchFailure=Erhalt des Ressourcen config
Aktualisierungsverlaufs fÃŒr Mitglieder der Gruppe [{0}] fehlgeschlagen
+view_group_resConfig_members_fetchFailureConfig=Abruf von Mitglieder Ressourcen
Konfigurationenseinstellungen fehlgeschlagen fÃŒr [{0}]
+view_group_resConfig_members_fetchFailureConfigInProgress=Eine Gruppen Ressourcen
Konfigurationsaktualisierung lÀuft derzeit. Sie mÌssen warten, bis die Aktualisierung
abgeschlossen ist, ehe Sie die Gruppeneinstellungen ansehen können.
view_group_resConfig_members_statusDetails=Status Details
view_group_resConfig_members_statusFailure=Die Konfigurationsaktualisierung ist aus
unbekanntem Grund fehlgeschlagen
view_group_resConfig_members_statusInprogress=Diese Konfigurationsaktualisierung lÀuft
noch
view_group_resConfig_members_statusNochange=Es wurden keine Ãnderungen an dieser
Konfiguration vorgenommen
view_group_resConfig_members_statusSuccess=Diese Konfigurationsaktualisierung war
erfolgreich
+view_group_resConfig_members_title=Gruppen Ressourcen Konfiguration Mitglieder Verlauf
view_group_resConfig_table_clickStatusIcon=FÃŒr mehr Details auf das Status Icon klicken
+view_group_resConfig_table_deleteFailure=Konnte die Gruppen Ressourcen Config History
nicht löschen
view_group_resConfig_table_deleteSuccessful=Sie haben [{0}] VerlaufseintrÀge gelöscht
+view_group_resConfig_table_failFetch=Erhalt der Gruppen Ressourcen Config History
fehlgeschlagen
+view_group_resConfig_table_msg1=Mitglieder Historie fÃŒr Status jeder einzelnen Ressource
ansehen
view_group_resConfig_table_statusDetails=Status Details
view_group_resConfig_table_statusFailure=Diese Konfigurationsaktualisierung ist
fehlgeschlagen
view_group_resConfig_table_statusInprogress=Diese Gruppen Konfigurationsaktualisierung
lÀuft noch
view_group_resConfig_table_statusNochange=Es wurden keine Ãnderungen an dieser Gruppen
Konfiguration vorgenommen
view_group_resConfig_table_statusSuccess=Diese Gruppen Konfigurationsaktualisierung ist
fehlgeschlagen
+view_group_resConfig_table_title=Gruppen Ressourcen Konfigurationsverlauf
view_group_resConfig_table_viewMemberHistory=Mitglieder Historie ansehen
view_group_resConfig_table_viewSettings=Einstellungen ansehen
view_group_resConfig_view_groupProperties=Gruppen-Eigenschaften
@@ -1738,15 +2252,19 @@ view_group_resConfig_view_noperm=Sie haben nicht die Berechtigung,
um die Konfig
# #view_group_resConfig_edit_saveTooltip = Update the configurations of all group
members
# #view_group_resConfig_edit_valid = All configuration properties have valid values, so
the configuration can now be saved
view_group_summary_compatible=Kompatible
+view_group_summary_descUpdateFailure=Konnte Beschreibung der Ressourcen Gruppe mit ID
[{0}] nicht Àndern
view_group_summary_descUpdateSuccessful=Sie haben die Beschreibung dieser
Ressourcen-Gruppe geÀndert.
# #view_group_summary_descUpdateFailure = Failed to change the description of the
resource group with ID [{0}]
# #view_group_summary_descUpdateSuccessful = You have changed the description of this
resource group
view_group_summary_dynamic=Dynamisch
+view_group_summary_dynamicNote=Dynamische Gruppen Namen und Beschreibungen werden
gemanagt und können daher nicht bearbeitet werden
# #view_group_summary_dynamicNote = Dynamic group names and descriptions are managed, and
therefore are not editable
view_group_summary_groupDefinition=Gruppen-Definition
view_group_summary_memberCount=Anzahl Mitglieder
view_group_summary_memberType=Mitglieds-Typ
view_group_summary_mixed=Gemischt
+view_group_summary_nameUpdateFailure=Ãnderung des Namens der Ressourcen Gruppe mit ID
[{0}] nicht Àndern - konnte ihn nicht von [{1}] zu [{2}] Àndern
+view_group_summary_nameUpdateSuccessful=Sie haben den Namen der Ressourcen Gruppe mit ID
[{0}] von [{1}] zu [{2}] geÀndert
# #view_group_summary_nameUpdateFailure = Failed to change the name of the resource group
with ID [{0}] - could not change from [{1}] to [{2}]
# #view_group_summary_nameUpdateSuccessful = You have changed the name of the resource
group with ID [{0}] from [{1}] to [{2}]
view_group_summary_recursive=Rekursiv
@@ -1758,11 +2276,18 @@ view_inventory_allGroups=Alle Gruppen
view_inventory_allResources=Alle Ressourcen
view_inventory_collectionInterval=Erfassungs-Intervall
view_inventory_dynagroupDefs=Dynagroup-Definitionen
+view_inventory_eventDetails_loadFailed=Ein Fehler ist beim Laden der Ereignisdetails
aufgetreten
+view_inventory_eventHistory_deleteFailed=Konnte die ausgewÀhlten Ereignisse fÌr [{0}]
nicht löschen
+view_inventory_eventHistory_deleteSuccessful=Sie haben [{0}] Ereignisse fÃŒr [{1}]
erfolgreich gelöscht
# #view_inventory_eventDetails_loadFailed = An error occurred loading the event details
# #view_inventory_eventHistory_deleteFailed = Failed to deleted selected events for
[{0}]
# #view_inventory_eventHistory_deleteSuccessful = You have successfully deleted [{0}]
events for [{1}]
view_inventory_eventHistory_details=Details
view_inventory_eventHistory_detailsFilter=Filter fÃŒr Details
+view_inventory_eventHistory_groupEventHistory=Gruppen Ereignisse Verlauf
+view_inventory_eventHistory_purgeFailed=Konnte Ereignisse fÃŒr [{0}] nicht bereinigen
+view_inventory_eventHistory_purgeSuccessful=Sie haben [{0}] Ereignisse fÃŒr [{1}]
erfolgreich bereinigt
+view_inventory_eventHistory_resourceEventHistory=Verlauf Ressourcen Ereignisse
# #view_inventory_eventHistory_groupEventHistory = Group Event History
# #view_inventory_eventHistory_purgeFailed = Failed to purge events for [{0}]
# #view_inventory_eventHistory_purgeSuccessful = You have successfully purged [{0}]
events for [{1}]
@@ -1770,10 +2295,15 @@ view_inventory_eventHistory_detailsFilter=Filter fÃŒr Details
view_inventory_eventHistory_severity=Schwere
view_inventory_eventHistory_severityFilter=Filter fÃŒr Schwere
view_inventory_eventHistory_sourceFilter=Filter fÃŒr Quelle
+view_inventory_eventHistory_sourceLocation=Speicherort Quelle
# #view_inventory_eventHistory_sourceLocation = Source Location
view_inventory_eventHistory_timestamp=Zeitunkt
view_inventory_groups=Gruppen
view_inventory_groups_children=Kinder
+view_inventory_groups_deleteFailed=Konnte die gewÀhlten Ressourcen-Gruppen nicht
löschen
+view_inventory_groups_deleteSuccessful=Sie haben die gewÀhlten Ressourcen Gruppen
erfolgreich gelöscht
+view_inventory_groups_descendants=Abkömmlinge
+view_inventory_groups_loadFailed=Konnte die zusammengesetzten Gruppendaten nicht laden
# #view_inventory_groups_deleteFailed = Failed to delete the selected resource groups
# #view_inventory_groups_deleteSuccessful = You have successfully deleted the selected
resource groups
# #view_inventory_groups_descendants = Descendants
@@ -1782,18 +2312,38 @@ view_inventory_ignoredResources=Ignorierte Ressourcen
view_inventory_mixed=gemischt
view_inventory_platforms=Platformen
view_inventory_problemGroups=Gruppen mit Problemen
+view_inventory_resource_loadFailed=Ressource mit [{0}] existiert nicht oder ist nicht
zugÀnglich
# #view_inventory_resource_loadFailed = Resource with id [{0}] does not exist or is not
accessible
view_inventory_resources_deleteConfirm=Sind Sie sicher, dass Sie die ausgewÀhlten
Ressourcen löschen wollen?
view_inventory_resources_deleteFailed=Löschen der ausgewÀhlten Ressourcen ist
fehlgeschlagen
+view_inventory_resources_deleteFailed2=Löschen der gewÀhlten Ressourcen fehlgeschlagen.
Verbindung mit dem Agent nicht möglich. Dies kann darauf hindeuten, dass der Agent nicht
in Betrieb ist.
+view_inventory_resources_deleteSuccessful=Eine Anfrage zur DurchfÃŒhrung einer
Ressourcenlöschung wurde erfolgreich bei dem/den Agent(en) eingereicht.
+view_inventory_resources_disableConfirm=Sind Sie sicher, dass Sie die ausgewÀhlten
Ressourcen deaktivieren wollen? Vom Agent gemeldete, deaktivierte VerfÃŒgbarkeiten werden
ignoriert. Die Deaktivierung kann fÃŒr Ressourcen von Nutzen sein, von denen erwartet
wird, dass sie als Teil der normalen Operationen oder Wartung auÃer Betrieb sind.
view_inventory_resources_disableFailed=Deaktivierung der ausgewÀhlten Ressourcen ist
fehlgeschlagen
+view_inventory_resources_disableSuccessful=Sie haben die gewÀhlten Ressourcen und deren
untergeordnete Ressourcen erfolgreich deaktiviert, [{0}] Ressourcen.
+view_inventory_resources_enableConfirm=Sind Sie sicher, dass Sie die ausgewÀhlten
Ressourcen deaktivieren wollen? Wenn aktiviert, so wird die VerfÃŒgbarkeit auf UNKNOWN
(unbekannt) eingestellt, bis die Agenten das nÀchste Mal zur VerfÌgbarkeit der
Ressourcen Bericht erstatten. Bei den Agenten wird um die möglichst schnelle
Berichterstattung der aktuellen VerfÃŒgbarkeiten angefragt.
view_inventory_resources_enableFailed=Aktivierung der ausgewÀhlten Ressourcen ist
fehlgeschlagen.
+view_inventory_resources_enableSuccessful=Sie haben die gewÀhlten Ressourcen und deren
untergeordnete Ressourcen erfolgreich aktiviert, [{0}] Ressourcen.
+view_inventory_resources_ignoreConfirm=Sind Sie sicher, dass die gewÀhlten Ressourcen
ignoriert werden sollen? Sie werden dann nicht mehr im Inventar angezeigt.
# #view_inventory_resources_deleteSuccessful = A request to perform the resource deletion
has been submitted successfully to the agent(s).
# #view_inventory_resources_disableSuccessful = You have successfully disabled the
selected resources and their children, [{0}] resources.
# #view_inventory_resources_ignoreConfirm = Are you sure you want the selected resources
to be ignored? They will no longer show up in inventory.
view_inventory_resources_ignoreFailed=Konnte die Ressourcen nicht ignorieren
+view_inventory_resources_ignoreSkipAllPlatforms=Sie können Plattformen nicht ignorieren.
Alle Ihre Auswahlen sind Plattformen, daher geschieht nichts. Falls Sie eine Plattform
nicht mehr managen wollen, so beenden Sie deren assoziierten Agent und entfernen Sie die
Plattform aus dem Inventar.
+view_inventory_resources_ignoreSkipSomePlatforms=Sie können Plattformen nicht
ignorieren. Die [{0}] Plattformen, die Sie gewÀhlt haben, werden Ìbersprungen. Falls Sie
eine Plattform nicht mehr managen wollen, so beenden Sie deren assoziierten Agent und
entfernen Sie die Plattform aus dem Inventar.
# #view_inventory_resources_ignoreSkipAllPlatforms = You cannot ignore platforms. All of
your selections are platforms so nothing will be done. If you no longer want to manage a
platform, shutdown its associated agent and uninventory the platform.
# #view_inventory_resources_ignoreSkipSomePlatforms = You cannot ignore platforms. The
[{0}] platforms you selected will be skipped. If you no longer want to manage a platform,
shutdown its associated agent and uninventory the platform.
view_inventory_resources_ignoreSuccessful=Sie haben die ausgewÀhlten Ressourcen
erfolgreich ignoriert
+view_inventory_resources_ignoreSuccessfulSkipPlatforms=Sie haben einige der gewÀhlten
Ressourcen erfolgreich ignoriert, jedoch wurden die [{0}] Plattformen, die Sie gewÀhlt
haben, ÃŒbersprungen. Falls Sie eine Plattform nicht mehr managen wollen, so beenden Sie
deren assoziierten Agent und entfernen Sie die Plattform aus dem Inventar.
+view_inventory_resources_loadFailed=Konnte die zusammengesetzten Ressourcendaten nicht
laden
+view_inventory_resources_members=Mitglieder Ressourcen
+view_inventory_resources_unignoreConfirm=Sind Sie sicher, dass das Ignorieren der
gewÀhlten Ressourcen aufheben wollen? Sie werden dann wieder im Inventar angezeigt.
+view_inventory_resources_unignoreFailed=Konnte das Ignorieren fÃŒr die Ressourcen nicht
aufheben.
+view_inventory_resources_unignoreSuccessful=Sie haben erfolgreich das Ignorieren der
ausgewÀhlten Ressourcen aufgehoben.
+view_inventory_resources_uninventoryConfirm=Sind Sie sicher, dass Sie die ausgewÀhlten
Ressourcen aus dem Inventar entfernen wollen? Beachten Sie dass - falls eine gewÀhlte
Ressource noch vorhanden ist - sie beim nÀchsten Discovery Scan des Agents aufgespÌrt
wird.
+view_inventory_resources_uninventoryFailed=Entfernung der ausgewÀhlten Ressourcen aus
dem Inventar ist fehlgeschlagen
+view_inventory_resources_uninventoryStorageConfirm=Sie sind im indestenseine Ressource
aus dem Inventar zu entfernen, die vom Storage Cluster verwendet wird. Um in Zukunft
Fehler zu vermeiden, sollten Sie "undeploy the node" (Undeployment des Knotens)
vor diesem Schritt ausfÌhren. Möchten Sie wirklich auf eigenes Risiko fortfahren?
+view_inventory_resources_uninventorySuccessful=Sie haben die ausgewÀhlten Ressourcen
erfolgreich aus dem Inventar entfernt
# #view_inventory_resources_ignoreSuccessfulSkipPlatforms = You have successfully ignored
some of the selected resources, however, the [{0}] platforms you selected were skipped.
Platforms cannot be ignored. If you no longer want to manage a platform, shutdown its
associated agent and uninventory the platform.
# #view_inventory_resources_loadFailed = Failed to load resource composite data
# #view_inventory_resources_members = Member Resources
@@ -1873,6 +2423,11 @@ view_operationHistoryDetails_status=Status
view_operationHistoryList_button_forceDelete=Löschen erzwingen
view_operationHistoryList_button_runOperation=Operation ausfÃŒhren
view_operationHistoryList_cancelConfirm=Sind Sie sicher, dass Sie die gewÀhlten
Operationen abbrechen möchten? HINWEIS\: Nur diejenigen der gewÀhlten Operationen, die
den Status "in progress" ("im Gange") besitzen, werden abgebrochen.
+view_operationHistoryList_cancelFailure=Die Anfrage zum Abbruch wurde fÃŒr die Operation
mit der Historien ID [{0}] ist fehlgeschlagen.
+view_operationHistoryList_cancelSubmitted=Anfragen zum Abbruch von [{0}] "in
progress" Operationen (im Gange) wurden eingereicht.
+view_operationHistoryList_cancelSuccess=Die Anfrage zum Abbruch wurde fÃŒr die Operation
mit der Historien ID [{0}] erfolgreich eingereicht.
+view_operationHistoryList_deleteFailure=Konnte Operations Historie [{0}] nicht löschen.
+view_operationHistoryList_deletePartialSuccess=Es wurden [{0}] Operations
Historienelemente gelöscht, aber Löschen fehlgeschlagen fÌr Elemente mit den folgenden
IDs\: {1}
# #view_operationHistoryList_cancelConfirm = Are you sure you want to cancel the selected
operations? NOTE: Only those selected operations that are currently "in
progress" will be attempted to be canceled.
# #view_operationHistoryList_cancelFailure = The cancel request failed for the operation
with the history ID of [{0}].
# #view_operationHistoryList_cancelSubmitted = Requests to cancel [{0}] "in
progress" operations have been submitted.
@@ -1906,7 +2461,10 @@ view_portlet_defaultName_group_config_updates=Gruppen\:
Aktualisierungen der Kon
view_portlet_defaultName_group_events=Gruppen\: Events
view_portlet_defaultName_group_metrics=Gruppen\: Metriken
view_portlet_defaultName_group_oobs=Gruppen\: OOB
+view_portlet_defaultName_group_operations=Gruppe\: Operationen
+view_portlet_defaultName_group_pkg_hisory=Gruppe\: Paketverlauf
view_portlet_defaultName_inventorySummary=InventarÃŒbersicht
+view_portlet_defaultName_mashup=Mashup
# #view_portlet_defaultName_mashup = Mashup
view_portlet_defaultName_message=Nachricht
view_portlet_defaultName_operations=KÃŒrzlich ausgefÃŒhrte Operationen
@@ -1914,6 +2472,7 @@ view_portlet_defaultName_platformSummary=Platformauslastung
view_portlet_defaultName_problemResources=Nicht verfÃŒgbare Resourcen oder mit Alarmen
view_portlet_defaultName_recentAlerts=KÌrzlich ausgelöste Alarme
view_portlet_defaultName_recentlyAddedResources=Zuletzt hinzugefÃŒgte Ressourcen
+view_portlet_defaultName_resourceMetric=Charts fÃŒr Ressourcen-Metriken
view_portlet_defaultName_resource_alerts=Ressource\: Alarme
view_portlet_defaultName_resource_bundles=Ressource\: Bundle Deployments
view_portlet_defaultName_resource_config_updates=Ressource\:
Konfigurationsaktualisierungen
@@ -1925,6 +2484,10 @@ view_portlet_defaultName_resource_pkg_hisory=Ressource\:
Paketverlauf
view_portlet_factory_invalidPortlet=Dies ist ein obsoletes Portlet, das nicht mehr
gÌltig ist. Bitte löschen Sie es.
view_portlet_graph_configure_metricDefinition_graph=Die ID der Metrik, die dargestellt
werden soll
view_portlet_graph_configure_resource_graph=Die Ressource deren Metrik dargestellt werden
soll
+view_portlet_help_autodiscovery=Dieses Portlet gestattet das Importieren oder Ignorieren
von neu aufgefundenen Ressourcen. Importierte Ressourcen werden dem Inventar zur
Beobachtung und Verwaltung hinzugefÃŒgt. Ignorierte Ressourcen werden nicht importiert und
bleiben der Ansicht verborgen falls das Ignorieren nicht explizit aufgehoben wird.
+view_portlet_help_bundle_deps=Dieses Portlet zeigt die relevante Bundle Deployments an,
basierend auf den konfigurierten Anzeigekriterien.
+view_portlet_help_config_updates=Dieses Portlet zeigt aktuelle KonfigurationsÀnderungen,
die konsistent mit Konfigurationseinstellungen sind.
+view_portlet_help_eventcounts=Dieses Portlet zeigt EreigniszÀhlungen an, die konsistent
mit den konfigurierten Anzeigekriterien sind.
# #view_portlet_graph_configure_title = Graph Config
# #view_portlet_graph_configure_title_desc = Configuration of the graph portlet
# #view_portlet_graph_help_msg = This Portlet supports the graphing of a resource
metric.
@@ -1932,12 +2495,23 @@ view_portlet_graph_configure_resource_graph=Die Ressource deren
Metrik dargestel
# #view_portlet_graph_help_unconfigured = This graph is unconfigured, click the settings
button to configure.
# #view_portlet_graph_title = Resource Graph
view_portlet_help_favoriteResources=Dieses Portlet zeigt die Lesezeichen des Benutzers
fÃŒr Ressourcen
+view_portlet_help_graph=Dieses Portlet zeigt das Ressourcen Metrik Diagramm an.
view_portlet_help_inventorySummary=Dieses Portlet zeigt eine Ãbersicht ÃŒber das fÃŒr
den Benutzer sichtbare Inventar
view_portlet_help_mashup=Dieses Portlet zeigt den Inhalt eines HTTP-Requests in einem
IFrame dar.
view_portlet_help_message=Dieses Portlet zeigt eine statische HTML-Seite an. Die
<i>Nachricht</i> kann konfiguriert werden.
+view_portlet_help_metrics=Dieses Portlet liefert eine grafische Darstellung relevanter
metrischer Daten basierend auf den konfigurierten Anzeigekriterien.
view_portlet_help_none=FÃŒr dieses Portlet ist keine Hilfe verfÃŒgbar
view_portlet_help_oobs=Dieses Portlet zeigt Metriken, die aus dem Baseband gelaufen sind
+view_portlet_help_operations=Dieses Portlet zeigt die zuletzt ausgefÃŒhrten Operationen
fÃŒr das Inventar des aktuellen Benutzers an.
+view_portlet_help_operations_criteria=Dieses Portlet zeigt Operationen an, die konsistent
mit den konfigurierten Anzeigekriterien sind.
+view_portlet_help_pkg_history=Dieses Portlet zeigt die relevante Paket Historie an,
basierend auf den konfigurierten Anzeigekriterien.
+view_portlet_help_platformSummary=Dieses Portlet zeigt die Auslastungsdaten (wie etwa
aktuelle CPU- und Speicherauslastung) fÃŒr Plattform-Ressourcen an, auf die der aktuelle
Benutzer zugreifen kann.
view_portlet_help_problemResources=Dieses Portlet zeigt die "alerted" oder
"unavailable" Ressourcen des aktuellen Benutzers an.
+view_portlet_help_recentAlerts=Dieses Portlet zeigt Alarm Meldungen an, die aktuell am
sichtbaren Inventar des Benutzers herausgegeben werden.
+view_portlet_help_recentDrifts=Dieses Portlet zeigt den aktuellen Datei Drift am
sichtbaren Inventar des Benutzers an.
+view_portlet_help_recentlyAdded=Dieses Portlet zeigt Ressourcen an, die aktuell in das
Inventar importiert wurden.
+view_portlet_help_scheduledOperations=Dieses Portlet zeigt die als nÀchstes terminierten
Operationen fÃŒr das Inventar des aktuellen Benutzers an.
+view_portlet_help_tagCloud=Dieses Portlet zeigt die relative Tag ZÀhlungen fÌr das
Inventar des aktuellen Benutzers an.
# #view_portlet_help_recentAlerts = This portlet displays alerts recently fired on the
current user''s viewable inventory.
# #view_portlet_help_recentDrifts = This portlet displays recent file drift on the
current user''s viewable inventory.
view_portlet_inventory_error1=Konnte die InventarÃŒbersicht nicht laden
@@ -1946,7 +2520,9 @@ view_portlet_inventory_tooltip_expand=Klicken, um mehr Details fÃŒr
diese Ressou
view_portlet_message_title=Nachricht
# #view_portlet_message_unconfigured = Message not yet configured, click the settings
button to setup this portlet.
view_portlet_operations_config_completed=Fertiggestellte Operationen
+view_portlet_operations_config_completed_enable=Ob die Gruppierung fertiggestellter
Operationsergebnisse fÃŒr das Dashboard aktiviert werden soll.
view_portlet_operations_config_completed_maximum=Maximale Anzahl anzuzeigender
abgeschlossener Operationen.
+view_portlet_operations_config_scheduled_enable=Ob die Gruppierung terminierter
Operationsergebnisse fÃŒr das Dashboard aktiviert werden soll.
view_portlet_operations_config_scheduled_maximum=Maximale Anzahl anzuzeigender geplanter
Operationen.
# #view_portlet_operations_config_completed_enable = Whether to enable completed
operations results grouping for dashboard.
# #view_portlet_operations_config_completed_maximum = Maximum number of Completed
operations to display.
@@ -1958,11 +2534,16 @@ view_portlet_operations_disabled=(Ergebnisse derzeit deaktiviert.
Ãndern Sie di
view_portlet_platform_platform_error_1=Laden der Plattform Metriken fehlgeschlagen
view_portlet_platform_type_error_1=Konnte Typdaten nicht laden
view_portlet_problemResources_config_display_maximum=Maximale Anzahl anzuzeigender
Problemressourcen.
+view_portlet_problemResources_config_display_range=Problem Ressourcen um so viele Stunden
rÃŒckwirkend anzeigen.
view_portlet_problemResources_config_display_range2=Von {0} bis {1}
view_portlet_problemResources_maxDisplaySetting=Maximaler Ressourcen.
+view_portlet_recentAlerts_config_members=Mitglieder auswÀhlen
+view_portlet_recentAlerts_config_priority_label=PrioritÀt Alarme
# #view_portlet_recentAlerts_config_members = Select Members
# #view_portlet_recentAlerts_config_priority_label = priority Alerts,
view_portlet_recentAlerts_config_when=innerhalb der letzten
+view_portlet_recentAlerts_fail_msg=Laden von fÃŒr Alarm Filterung zugewiesenen Ressourcen
fehlgeschlagen.
+view_portlet_recentlyAdded_error1=Laden zuletzt hinzugefÃŒgter Ressourcen fehlgeschlagen
view_portlet_recentlyAdded_setting_addedPlatforms=zuletzt hinzugefÃŒgte Plattformen
# #view_portlet_recentlyAdded_approved_platforms = recently approved platforms on
dashboard.
# #view_portlet_recentlyAdded_error1 = Failed to load recently added resources
@@ -1974,6 +2555,9 @@ view_remoteAgentInstall_agentStatusDefault=-Klicken Sie auf
SchaltflÀche Status
# #view_remoteAgentInstall_agentStatusDefault = -Click Update Status Button-
view_remoteAgentInstall_buttonFindAgent=Agent suchen
view_remoteAgentInstall_connInfo=Verbindungsinformationen
+view_remoteAgentInstall_error_1=Fehler bei der Suche nach dem Pfad der
Agent-Installation
+view_remoteAgentInstall_error_2=Bei der Suche in Speicherorten konnte kein installierter
Agent gefunden werden
+view_remoteAgentInstall_error_3=Konnte keinen an oder unter [{0}] installierten Agent
finden
# #view_remoteAgentInstall_connInfo = Connection Information
# #view_remoteAgentInstall_error_1 = Error occurred while trying to find agent install
path
# #view_remoteAgentInstall_error_2 = Could not find an agent installed when looking in
common locations
@@ -2003,6 +2587,7 @@ view_reportsTop_description=Dieser Abschnitt bietet Zugang zu
applikationsweiten
view_reportsTop_title=Berichte
view_reports_alertDefinitions=Alarmierungskriterien
view_reports_alertDefinitions_parentHover=Klicken, um zur ÃŒbergeordneten
Alarm-Definition zu gelangen
+view_reports_alertDefinitions_resTypeLoadError=Erhalt von Ressourcentyp Vorlage nicht
möglich - Ansicht von Alarm Vorlage nicht möglich.
# #view_reports_alertDefinitions_resTypeLoadError = Cannot get the template resource type
- unable to view the alert template.
view_reports_driftCompliance=Drift-Ãbereinstimmung
view_reports_inventorySummary_failFetch=Konnte die Inventar-Zusammenfassung nicht laden
@@ -2012,11 +2597,15 @@ view_resourceResourceGroupList_error_fetchFailure=Abruf der
Gruppen der Ressourc
view_resourceResourceGroupList_error_updateFailure=Fehler beim Aktualisieren der
zugewiesenen Ressourcen-Gruppen.
view_resourceResourceGroupList_message_updateSuccess=Gruppenmitgliedschaft aktualisiert
fÃŒr [{0}].
view_resource_inventory_activity_changed_by=GeÀndert von
+view_resource_inventory_activity_criteria_no_recent_events=Keine EreigniszÀhlungen
basieren auf Anzeigekriterien.
view_resource_inventory_activity_no_recent_alerts=Es liegen keine aktuellen Alarme vor
view_resource_inventory_activity_no_recent_bundle_deploy=Es liegen keine aktuelle
BÃŒndel-Deployments vor
+view_resource_inventory_activity_no_recent_config_history=Keine KonfigurationsÀnderungen
Historie
view_resource_inventory_activity_no_recent_events=Keine Ereignisse in den letzten 24
Stunden
view_resource_inventory_activity_no_recent_metrics=Diese Ressource hat keine aktuellen
Metriken
view_resource_inventory_activity_no_recent_oob=Keine OOB Bedingungen gefunden
+view_resource_inventory_activity_no_recent_operations=Keine aktuelle Operations-Historie
+view_resource_inventory_activity_no_recent_pkg_history=Keine aktuelle Paket Historie
view_resource_inventory_childhistory_createdChild=Kind erstellt
view_resource_inventory_childhistory_deletedChild=Kind gelöscht
# #view_resourceResourceGroupList_error_fetchFailure = Failed to fetch
Resource''s groups.
@@ -2080,8 +2669,11 @@ view_resource_monitor_table_last=Live Wert
# #view_resource_monitor_table_last = Live Value
view_resource_monitor_table_max=Maximum
view_resource_monitor_table_min=Minimum
+view_resource_title_component_errors_cleanup=Nach Behebung dieses Problems, werden Sie
die Nachricht unten löschen mÌssen, um das 'managed component error' (Fehler bei
gemanagter Komponente) Symbol vom vorherigen Bildschirm zu löschen.
view_resource_title_component_errors_tooltip=Zeigt Fehler der gemanagten Ressource.
Klicken fÃŒr Details
view_resource_title_tagUpdateFailed=Fehler beim Aktualisieren der Ressourcen-Tags
+view_searchBar_buttonTooltip=Zum Anzeigen/Verbergen der Suchvorschlagsliste klicken.
Verbergen der Liste erfolgt auch durch DrÃŒcken auf Escape wenn der Fokus in der
Suchmuster Textbox ist.
+view_searchBar_savedSearch_buttonTooltip=Klicken Sie, um in den Saved Search
(Gespeicherte Suche) Modus umzuschalten. Wenn aktiv, speichern Sie das aktuelle Muster,
indem Sie einen Namen eingeben und auf die Eingabetaste klicken. Bearbeiten Sie eine
bestehende Suche, indem Sie sie in der Liste auswÀhlen, das Muster oder den Namen
aktualisieren und im NamenstextkÀstchen auf Eingabe drÌcken. Das Löschen erfolgt durch
Doppelklicken des Listeneintrags.
# #view_searchBar_buttonTooltip = Click to hide/show the search suggestion list. Also
hide the list by hitting Escape when focus is in the search pattern text box.
# #view_searchBar_savedSearch_buttonTooltip = Click to toggle Saved Search mode. When
active, save the current pattern by entering a name and hitting return. Edit an existing
search by selecting it in the list, updating the pattern or name, and hitting return in
the name text box. Delete by double-clicking the list entry.
view_searchBar_savedSearch_confirmDelete=Die gespeicherte Suche mit dem Namen [{0}]
löschen?
@@ -2101,6 +2693,7 @@ view_searchGUI_loginStatus=Kann Login-Status nicht bestimmen,
ÃŒberprÃŒfen Sie d
view_selector_assigned=Zugewiesen {0}
view_selector_available=VerfÃŒgbar {0}
view_subTab_error_disabled=Kann den deaktivierten Unter-Reiter [{0}] nicht anwÀhlen.
+view_summaryDashboard_resetConfirm=Auf standardmÀÃiges Ãbersichts-Dashboard
zurÃŒcksetzen (lokale Ãnderungen gehen verloren)?
view_summaryOverviewForm_error_descriptionChangeFailure=Konnte die Beschreibung der
Ressource mit der id {0} nicht von [{1}] auf [{2}] Àndern.
view_summaryOverviewForm_error_locationChangeFailure=Konnte den Ort der Ressource mit der
id {0} nicht von [{1}] auf [{2}] Àndern.
view_summaryOverviewForm_error_nameChangeFailure=Konnte den Namen der Ressource mit der
id {0} nicht von [{1}] auf [{2}] Àndern.
@@ -2204,6 +2797,7 @@ view_tree_common_contextMenu_type_name_label=Typ\: {0}
view_tree_common_createFailed_autoCluster=Erstellung oder Aktualisierung von autocluster
Backing Gruppe fehlgeschlagen
view_tree_common_loadFailed_children=Konnte die Kinder fÃŒr den Knoten nicht laden
view_tree_common_loadFailed_create=Konnte die Ansicht fÃŒr diesen Knoten nicht erzeugen
+view_tree_common_loadFailed_descendants=Konnte Abkömmlinge fÌr Baumansicht nicht laden
# #view_tree_common_loadFailed_descendants = Failed to load descendants for tree
view_tree_common_loadFailed_generic=Konnte die Daten fÃŒr den Bau nicht laden
view_tree_common_loadFailed_group=Konnte die Gruppe mit ID [{0}] nicht laden
@@ -2305,6 +2899,7 @@ widget_resourceFactoryWizard_execute1=Konnte keine neue Ressource
anlegen - es w
widget_resourceFactoryWizard_execute2=Erstellung einer neuen Ressource fehlgeschlagen.
Verbindung mit dem Agent nicht möglich. Dies kann darauf hindeuten, dass der Agent nicht
in Betrieb ist.
widget_resourceFactoryWizard_execute3=Erstellung einer neuen Ressource fehlgeschlagen.
widget_resourceFactoryWizard_failedToDeleteVersion=Löschen der Paketversion
fehlgeschlagen wÀhrend Abbruch einer Ressourcenerstellung
+widget_resourceFactoryWizard_failedToGetType=Erhalt des Pakettyps fÃŒr neue Ressource
fehlgeschlagen
# widget_resourceFactoryWizard_execute2 = Failed to create a new resource. Cannot connect
to the agent. This may indicate that the agent is down.
# #widget_resourceFactoryWizard_failedToDeleteVersion = Failed to delete package version
while canceling a resource create
# #widget_resourceFactoryWizard_failedToGetType = Failed to get backing package type for
new resource
@@ -2316,12 +2911,16 @@ widget_resourceFactoryWizard_importWizardTitle=Importieren von
Ressourcen des Ty
widget_resourceFactoryWizard_importWizardWindowTitle=Wizard zum Import von Ressourcen
widget_resourceFactoryWizard_infoStepName=Information ÃŒber die Ressource
widget_resourceFactoryWizard_infoStep_loadFail=Konnte die verfÃŒgbaren Architekturen
nicht ermitteln
+widget_resourceFactoryWizard_nameComment=Nicht alle Management Plug-ins oder deren
gemanagte Ressourcen gestatten dem Agent die Einstellung des Namens fÃŒr eine neue
Ressource. Dieser Wert wird nur von Agent Plug-ins verwendet, die diese Möglichkeit
unterstÃŒtzen. FÃŒr Plug-ins, die dies nicht unterstÃŒtzen, kann die Ressource bei deren
Auffinden einen generischen oder anderen Namen erhalten.
widget_resourceFactoryWizard_namePrompt=Name der neuen Ressource
# widget_resourceFactoryWizard_nameComment = Not all management plug-ins or their managed
resources allow the agent to set the name for a new resource. This value will only be used
by agent plug-ins that support the capability. For plug-ins that do not support the
capability, the resource may receive a generic or different name when it is discovered.
widget_resourceFactoryWizard_templatePrompt=Vorlage fÃŒr die Verbindungseinstellungen
widget_resourceFactoryWizard_timeoutFailure=Timeout
+widget_resourceFactoryWizard_timeoutHelp=Eine Timeout Dauer, die - falls festgelegt - den
standardmÀÃigen Timeout fÃŒr die Erstellung der untergeordneten Ressource auÃer Kraft
setzt (am {0} Agent). Der standardmÀÃige Timeout ist auf 60 Sekunden eingestellt. Ein
höherer Wert kann von bei besonders langen ErstellungsvorgÀngen von Nutzen sein, wie
etwa bei dem Deployment einer groÃen Applikation. Wird in der Regel verwendet, wenn es
beim vorherigen Versuch zu einem Fehlschlagen aufgrund eines Timeout kam. Beachten Sie,
dass es bei einem Fehlschlagen aufgrund eines Timeout trotzdem möglich ist, dass das
Ressourcen Deployment erfolgreich verlief. Im Falle eines Timeout empfiehlt sich ein
Discovery Scan vor dem erneuten Versuch des Deployments der Ressource.
# #widget_resourceFactoryWizard_timeoutHelp = A timeout duration that if specified will
override the default timeout for child resource creation (on the {0} Agent). The default
timeout is set to 60 seconds. A higher value may be useful for particularly long create
actions, like deployment of a large application. Usually used if a previous attempt
suffered a timeout failure. Note that if there is a timeout failure, it is still possible
that the resource deployment succeeded. In the event of a timeout you may want to execute
a discovery scan before attempting to redeploy the resource.
widget_resourceFactoryWizard_uploadFailure=Konnte die Datei nicht hochladen
+widget_resourceFactoryWizard_uploadFileStepName=Laden Sie die Ressourcen Content Datei
hoch
+widget_resourceFactoryWizard_uploadInProgress=Datei wird hochgeladen ... Dies kann fÃŒr
groÃe Distributionsdateien mehrere Minuten dauern.
# ##widget_resourceFactoryWizard_timeoutFailure = Timed out
# #widget_resourceFactoryWizard_uploadFileStepName = Upload Resource Content File
# #widget_resourceFactoryWizard_uploadInProgress = The upload is in progress... This can
take several minutes to complete for large distribution files.
diff --git
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_ja.properties
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_ja.properties
index 328383c..aa366a0 100644
---
a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_ja.properties
+++
b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/coregui/client/Messages_ja.properties
@@ -1358,36 +1358,36 @@
view_alert_definition_notification_operation_editor_specific_resource=ãªãœãŒ
view_alert_definition_notification_role_editor_loadFailed=çŸåšã®ããŒã«ã決å®ã§ããŸãã
- 空ã§éå§ããŸã
view_alert_definition_notification_role_editor_restoreFailed=çŸåšã®ããŒã«ãå©çšã§ããŸãã
- 空ããéå§ããŸã
view_alert_definition_notification_role_editor_saveFailed=éžæãããããŒã«ãä¿åã§ããŸãã
-view_alert_definition_notification_user_editor_loadFailed=çŸåšã®ãŠãŒã¶ãŒã決å®ã§ããŸãã
- 空ããéå§ããŸã
-view_alert_definition_notification_user_editor_restoreFailed=çŸåšã®ãŠãŒã¶ãŒã䜿çšã§ããŸãã
- 空ããéå§ããŸã
+view_alert_definition_notification_user_editor_loadFailed=çŸåšã®ãŠãŒã¶ãŒã決å®ã§ããŸãã
- 空ã§éå§ããŸã
+view_alert_definition_notification_user_editor_restoreFailed=çŸåšã®ãŠãŒã¶ãŒã䜿çšã§ããŸãã
- 空ã§éå§ããŸã
view_alert_definition_notification_user_editor_saveFailed=éžæãããŠãŒã¶ãŒãä¿åã§ããŸãã
-view_alert_definition_recovery_editor_disable_when_fired=çºç«æéãç¡å¹ã«ãã
-view_alert_definition_recovery_editor_disable_when_fired_tooltip=ãã®ã¢ã©ãŒããçºç«ããåŸã«ç¡å¹ã«ãããã¹ããæå®ããŸããäžåºŠç¡å¹ã«ããããšããã®ã¢ã©ãŒãã¯æåã§å床æå¹ã«ãããããŸãã¯èªåçã«å床æå¹ã«ããããã®ãªã«ããªã¢ã©ãŒããèšå®ã§ããŸãã
+view_alert_definition_recovery_editor_disable_when_fired=çºçæã«ç¡å¹
+view_alert_definition_recovery_editor_disable_when_fired_tooltip=ãã®ã¢ã©ãŒããçºçããåŸã«ç¡å¹ã«ãªããã©ããã瀺ããŸããç¡å¹ã«ãªã£ãã¢ã©ãŒãã¯ãæäœæ¥ã§å床æå¹ã«ã§ãããªã«ããªã¢ã©ãŒããèšå®ããŠèªåçã«å床æå¹ã«ããããšãå¯èœã§ãã
view_alert_definition_recovery_editor_loadFailed=ãªã«ããªã¡ãã¥ãŒãæ§ç¯ã§ããŸãã
view_alert_definition_recovery_editor_none_available=ãªã
view_alert_definition_recovery_editor_recovery_alert=ã¢ã©ãŒãã®ãªã«ããª
-view_alert_definition_recovery_editor_recovery_alert_tooltip=ã¢ã©ãŒããåŒãèµ·ããããåŸã«ãªã«ããªããã(ã€ãŸããå床æå¹å)ã¿ãŒã²ããã¢ã©ãŒãããªã«ããªã¢ã©ãŒããå®çŸ©ããã®ã§ã¯ãªãã®ãªãããã§ã¢ã©ãŒããéžæããªãã§ãã ããã
+view_alert_definition_recovery_editor_recovery_alert_tooltip=ã¢ã©ãŒããåŒãèµ·ããããåŸã«ãªã«ããªããã
(åæå¹åãªã©)
ã¿ãŒã²ããã¢ã©ãŒãããªã«ããªã¢ã©ãŒããå®çŸ©ããå Žåã®ã¿ã¢ã©ãŒããéžæããŠãã ããã
view_alert_definitions_create_failure=ã¢ã©ãŒãå®çŸ©ã®äœæã«å€±æããŸãã
view_alert_definitions_create_success=ã¢ã©ãŒãå®çŸ©ã®äœæã«æåããŸãã
view_alert_definitions_delete_confirm=éžæãããã¢ã©ãŒãå®çŸ©ãåé€ããŸãã?
view_alert_definitions_delete_failure=éžæãããã¢ã©ãŒãå®çŸ©ãåé€ããã®ã«å€±æããŸãã
-view_alert_definitions_delete_success={0}
ã¢ã©ãŒãå®çŸ©ãåé€ããã®ã«æåããŸãã
+view_alert_definitions_delete_success={0}
ã®ã¢ã©ãŒãå®çŸ©ãæ£åžžã«åé€ããŸãã
view_alert_definitions_disable_confirm=éžæãããã¢ã©ãŒãå®çŸ©ãç¡å¹ã«ããŸãã?
view_alert_definitions_disable_failure=éžæãããã¢ã©ãŒãå®çŸ©ãç¡å¹ã«ããã®ã«å€±æããŸãã
-view_alert_definitions_disable_success={0}
ã¢ã©ãŒãå®çŸ©ãç¡å¹ã«ããã®ã«æåããŸãã
-view_alert_definitions_enable_confirm=éžæãããã¢ã©ãŒãå®çŸ©ãã«ããŸãã?
+view_alert_definitions_disable_success={0} ã®ã¢ã©ãŒãå®çŸ©ãç¡å¹ã«ããŸãã
+view_alert_definitions_enable_confirm=éžæãããã¢ã©ãŒãå®çŸ©ãæå¹ã«ããŸãã?
view_alert_definitions_enable_failure=éžæãããã¢ã©ãŒãå®çŸ©ãæå¹ã«ããã®ã«å€±æããŸãã
-view_alert_definitions_enable_success={0}
ã¢ã©ãŒãå®çŸ©ãæå¹ã«ããã®ã«æåããŸãã
+view_alert_definitions_enable_success={0} ã®ã¢ã©ãŒãå®çŸ©ãæå¹ã«ããŸãã
view_alert_definitions_leaveUnsaved=ç·šéããã¢ã©ãŒãå®çŸ©ãä¿åããŸãã?
# #view_alert_definitions_leaveUnsaved = Do you want to save the modified alert
definition?
-view_alert_definitions_loadFailed=ã¢ã©ãŒãå®çŸ©ããŒã¿ãåãåºãã®ã«å€±æããŸãã
-view_alert_definitions_loadFailed_single=ID {0}
ã®ä»ããã¢ã©ãŒãå®çŸ©ã®ããŒã¿ãåãåºãã®ã«å€±æããŸãã
+view_alert_definitions_loadFailed=ã¢ã©ãŒãå®çŸ©ããŒã¿ã®ååŸã«å€±æããŸãã
+view_alert_definitions_loadFailed_single=ID {0}
ã®ã¢ã©ãŒãå®çŸ©ã®ããŒã¿ãååŸã§ããŸããã§ãã
view_alert_definitions_table_title_group=ã°ã«ãŒãã¢ã©ãŒãå®çŸ©
view_alert_definitions_table_title_resource=ãªãœãŒã¹ã¢ã©ãŒãå®çŸ©
view_alert_definitions_update_failure=ã¢ã©ãŒãå®çŸ©ã®æŽæ°ã«å€±æããŸãã
view_alert_definitions_update_success=ã¢ã©ãŒãå®çŸ©ã®æŽæ°ã«æåããŸãã
-view_alert_details_field_ack_at=次ã®å Žæã§ç¢ºèªæžã¿ã§ã
-view_alert_details_field_ack_by=次ã®äººã«ãã£ãŠç¢ºèªæžã¿ã§ã
+view_alert_details_field_ack_at=確èªå Žæ\:
+view_alert_details_field_ack_by=確èªè
\:
view_alert_details_field_parent_definition=芪å®çŸ©
# #view_alert_details_field_parent_definition = Parent definition
view_alert_details_field_recovery_info=ãªã«ããªæ
å ±
@@ -1395,12 +1395,12 @@ view_alert_details_field_resource_ancestry=ãªãœãŒã¹ã®ç¥å
view_alert_details_field_watched_resource=ãŠã©ããããããªãœãŒã¹
# #view_alert_details_field_resource_ancestry = Resource Ancestry
# #view_alert_details_field_watched_resource = Watched Resource
-view_alert_details_loadFailed=ã¢ã©ãŒãã®è©³çŽ°ãåãåºãã®ã«å€±æããŸãã
+view_alert_details_loadFailed=ã¢ã©ãŒã詳现ã®ååŸã«å€±æããŸãã
view_alerts_ack_confirm=éžæãããã¢ã©ãŒãã確èªããŸãã?
view_alerts_ack_confirm_all=ãã®ãœãŒã¹ãããã¹ãŠã®ã¢ã©ãŒãã確èªããŸãã?
-view_alerts_ack_failure=ID {0}
ã®ä»ããã¢ã©ãŒãã確èªããã®ã«å€±æããŸãã
-view_alerts_ack_failure_all=ãã®ãœãŒã¹ãããã¹ãŠã®ã¢ã©ãŒãã確èªããã®ã«å€±æããŸãã
-view_alerts_ack_success={0} ã¢ã©ãŒãã®ç¢ºèªã«æåããŸãã
+view_alerts_ack_failure=ID {0} ã®ã¢ã©ãŒãã確èªã§ããŸããã§ãã
+view_alerts_ack_failure_all=ãã®ãœãŒã¹ãããã¹ãŠã®ã¢ã©ãŒãã確èªã§ããŸããã§ãã
+view_alerts_ack_success={0} ã¢ã©ãŒãã確èªããŸãã
view_alerts_delete_confirm=éžæãããã¢ã©ãŒããåé€ããŸãã?
view_alerts_delete_confirm_all=ãã®ãœãŒã¹ãããã¹ãŠã®ã¢ã©ãŒããåé€ããŸãã?
view_alerts_delete_failure=ID {0}
ã®ä»ããã¢ã©ãŒããåé€ããã®ã«å€±æããŸãã
@@ -1408,8 +1408,8 @@
view_alerts_delete_failure_all=ãã®ãœãŒã¹ãããã¹ãŠã®ã¢ã©ãŒãã
view_alerts_delete_success={0} ã¢ã©ãŒããåé€ããã®ã«æåããŸãã
view_alerts_field_ack_status=ã¹ããŒã¿ã¹
view_alerts_field_ack_status_ack=ç¢ºèª ({0})
-view_alerts_field_ack_status_ackHover={1} ã«ãã㊠{0}
ã«ãã£ãŠç¢ºèªãããŸãã
-view_alerts_field_ack_status_noAck=æªç¢ºèª
+view_alerts_field_ack_status_ackHover={1} ã«ãã㊠{0} ã確èª
+view_alerts_field_ack_status_noAck=確èªãªã
view_alerts_field_ack_status_noAckHover=ãŸã 確èªãããŠããŸãã
view_alerts_field_ack_subject=確èªãµããžã§ã¯ã
view_alerts_field_ack_time=確èªæå»
@@ -1422,8 +1422,8 @@ view_alerts_field_modified_time=ä¿®æ£æå»
view_alerts_field_parent=芪
view_alerts_field_priority=åªå
床
view_alerts_field_protected=ä¿è·ãããŠãã
-view_alerts_field_protected_tooltip=ããtrueãªãããã®å®çŸ©ã¯èŠªå®çŸ©ã«ããå€æŽããä¿è·ãããŠããŸããä»ã®èšèã§èšãã°ããã®èŠªå®çŸ©èšå®ã¯ãã®å®çŸ©ãäžæžãããŸããã
-view_alerts_loadFailed=ã¢ã©ãŒãããŒã¿ãåãåºãã®ã«ããŸãã
+view_alerts_field_protected_tooltip=true
ã®å Žåããã®å®çŸ©ã¯ä¿è·ããã芪å®çŸ©ãå€æŽã§ããŸããããã£ãŠã芪å®çŸ©ã®èšå®ã¯ãã®å®çŸ©ãäžæžãã§ããŸããã
+view_alerts_loadFailed=ã¢ã©ãŒãããŒã¿ã®ååŸã«å€±æããŸãã
view_alerts_table_filter_priority=åªå
床ãã£ã«ã¿ãŒ
view_alerts_table_title_group=ã°ã«ãŒãã¢ã©ãŒãå±¥æŽ
view_alerts_table_title_resource=ãªãœãŒã¹ã¢ã©ãŒãå±¥æŽ
@@ -1455,7 +1455,7 @@
view_autoDiscoveryQ_unignoreInProgress=éžæããããªãœãŒã¹ã®ç¡èŠã
view_autoDiscoveryQ_unignoreSuccessful=éžæãããªãœãŒã¹ã®ç¡èŠè§£é€ã«æåããŸãã
view_autoDiscoveryQ_uninventoried=ã€ã³ãã³ããªç»é²ãããªã
view_bundleGroup_assignFailPerm=ãã³ãã«ããã®ãã³ãã«ã°ã«ãŒããžå²ãåœãŠãæš©å©ããããŸããã管çè
ãžåãåãããŠãã ããã
-view_bundleGroup_deleteConfirm=ãã®ãã³ãã«ã°ã«ãŒããåé€ããŠãããããã§ãã?
å¯äžå²ãåœãŠããããã³ãã«ã°ã«ãŒãã®ãã³ãã«ãå²ãåœãŠè§£é€ãšãªããé²èŠ§ã«ã°ããŒãã«
View Bundles ããŒããã·ã§ã³ãå¿
èŠãšãªããŸãã
+view_bundleGroup_deleteConfirm=ãã®ãã³ãã«ã°ã«ãŒããåé€ããŠãããããã§ãã?
å¯äžå²ãåœãŠããããã³ãã«ã°ã«ãŒãã®ãã³ãã«ãå²ãåœãŠè§£é€ãšãªããé²èŠ§ã«ã°ããŒãã«ã®ããã³ãã«ã®è¡šç€ºãããŒããã·ã§ã³ãå¿
èŠãšãªããŸãã
view_bundleGroup_deletesFailure=ãã³ãã«ã°ã«ãŒããåé€ã§ããŸããã§ãã
view_bundleGroup_deletesSuccessful=ãã³ãã«ã°ã«ãŒããæ£åžžã«åé€ããŸãã
view_bundleGroup_unassignFailPerm=ãã®ãã³ãã«ã°ã«ãŒããããã³ãã«ãå²ãåœãŠè§£é€ããæš©å©ããããŸããã管çè
ã«åãåãããŠãã ããã
@@ -1473,22 +1473,22 @@ view_bundle_bundleType=ãã³ãã«ã¿ã€ã
view_bundle_bundleVersion=ãã³ãã«ããŒãžã§ã³
view_bundle_bundleVersions=ãã³ãã«ããŒãžã§ã³
view_bundle_createWizard_bundleDistro=ãã³ãã«é
åž
-view_bundle_createWizard_cancelFailure=ãã³ãã« [{0}], ããŒãžã§ã³ \= [{1}]
ã®äœæã®å®å
šãªãã£ã³ã»ã«ã«å€±æããŸãã -
ãã³ãã«ã¯ããŒã¿ããŒã¹ã«ãŸã æ®ã£ãŠãããããããŸãã
+view_bundle_createWizard_cancelFailure=ãã³ãã« [{0}]ãããŒãžã§ã³ \= [{1}]
ã®äœæãå®å
šã«ãã£ã³ã»ã«ã§ããŸããã§ãã -
ãã³ãã«ããŸã ååšããå¯èœæ§ããããŸãã
view_bundle_createWizard_cancelFailurePerm=ãŠãŒã¶ãŒãããŒããã·ã§ã³ãäœæããåé€ããªãã£ãããããã³ãã«
[{0}]ãããŒãžã§ã³ \= [{1}] ã®äœæãå®å
šã«ãã£ã³ã»ã«ã§ããŸããã§ããã管çè
ã«ãããã³ãã«ã®åé€ãå¿
èŠã«ãªããšäºæ³ãããŸãã
# #view_bundle_createWizard_cancelFailurePerm = Failed to fully cancel the creation of
bundle [{0}], version = [{1}] because the user has create but not delete permissions. The
bundle will likley need to be removed by an administrator.
-view_bundle_createWizard_cancelSuccessful=ãã³ãã« [{0}], ããŒãžã§ã³ \= [{1}]
ã®äœæããã£ã³ã»ã«ããŸãã
-view_bundle_createWizard_clickToUploadRecipe=ã¬ã·ããã¡ã€ã«ã®ããŒãããããã«ã¯ãªãã¯ããŠãã ãã
-view_bundle_createWizard_createFailure=ãã³ãã«ãäœæããã®ã«å€±æããŸãã
+view_bundle_createWizard_cancelSuccessful=ãã³ãã« [{0}]ãããŒãžã§ã³ \= [{1}]
ã®äœæããã£ã³ã»ã«ããŸãã
+view_bundle_createWizard_clickToUploadRecipe=ã¯ãªãã¯ãããšã¬ã·ããã¡ã€ã«ãããŒãããŸã
+view_bundle_createWizard_createFailure=ãã³ãã«ãäœæã«å€±æããŸãã
view_bundle_createWizard_createSuccessful=ããŒãžã§ã³ [{1}] ã® [{0}]
ãšããååã®ãã³ãã«ã®äœæã«æåããŸãã
view_bundle_createWizard_enterRecipe=æ£ããã¬ã·ããæäŸããŠãã ãã
-view_bundle_createWizard_enterUrl=ãã³ãã«é
åžãã¡ã€ã«ãããŠã³ããŒãã§ããæ£ããURLãå
¥åããŠãã ãã
+view_bundle_createWizard_enterUrl=ãã³ãã«é
åžãã¡ã€ã«ãããŠã³ããŒãã§ããæ£ãã URL ãå
¥åããŠãã ãã
view_bundle_createWizard_failedToUploadDistroFile=ãã³ãã«é
åžãã¡ã€ã«ã®ã¢ããããŒãã«å€±æããŸãã
view_bundle_createWizard_failedToUploadFile=ãã³ãã«ãã¡ã€ã«ã®ã¢ããããŒãã«å€±æããŸãã
view_bundle_createWizard_groupsStep_assign=æå¹ãªãã³ãã«ã°ã«ãŒãã 1
ã€ä»¥äžå²ãåœãŠãŸã\:
view_bundle_createWizard_groupsStep_assigned=æ°ãããã³ãã«ããŒãžã§ã³ã¯æ¢åã®ãã³ãã«çšã§ããã³ãã«ã°ã«ãŒãã®å²ãåœãŠãç¶æ¿ããŸã\:
view_bundle_createWizard_groupsStep_failedAssign=æåã®ãã³ãã«ã°ã«ãŒãããããŒãžã§ã³
[{1}] ã® [{0}]
ãšããååã®ãã³ãã«ãžå²ãåœãŠã§ããŸããã§ãããäœæãŠã£ã¶ãŒãããã£ã³ã»ã«ãã管çè
ã«å ±åããŠãã ããã
view_bundle_createWizard_groupsStep_failedGetAssignable=å²ãåœãŠå¯èœãªãã³ãã«ã°ã«ãŒãã決å®ã§ããŸããã§ãããäœæãŠã£ã¶ãŒãããã£ã³ã»ã«ãã管çè
ã«å ±åããŠãã ããã
-view_bundle_createWizard_groupsStep_help=æ°ãããã³ãã«ã¯ããã®ãã³ãã«ã®æåã®ããŒãžã§ã³ãã¢ããããŒãããæã«äœæãããŸãããã®åŸãæ°ãããã³ãã«ã¯æåã®ãã³ãã«ã°ã«ãŒããžå²ãåœãŠãããŸããæ°ãããã³ãã«ã¯ãã°ããŒãã«ãŸãã¯ãã³ãã«ã°ã«ãŒãã¬ãã«ã«ãŠãCreate
Bundles
ããŒããã·ã§ã³ãæã€ãã³ãã«ã°ã«ãŒããžã®ã¿å²ãåœãŠã§ããŸãããŠãŒã¶ãŒãã°ããŒãã«ã®
Create ãŸã㯠View Bundles
ããŒããã·ã§ã³ãæã£ãŠãããšããã³ãã«ã°ã«ãŒãã¯å²ãåœãŠãããŸããããã®å Žå以å€ã¯ãæäœã§ã
1 ã€ã®ãã³ãã«ã°ã«ãŒããå²ãåœãŠãå¿
èŠããããŸãã
+view_bundle_createWizard_groupsStep_help=æ°ãããã³ãã«ã¯ããã®ãã³ãã«ã®æåã®ããŒãžã§ã³ãã¢ããããŒãããæã«äœæãããŸãããã®åŸãæ°ãããã³ãã«ã¯æåã®ãã³ãã«ã°ã«ãŒããžå²ãåœãŠãããŸããæ°ãããã³ãã«ã¯ãã°ããŒãã«ãŸãã¯ãã³ãã«ã°ã«ãŒãã¬ãã«ã«ãŠãããã³ãã«ã®äœæãããŒããã·ã§ã³ãæã€ãã³ãã«ã°ã«ãŒããžã®ã¿å²ãåœãŠã§ããŸãããŠãŒã¶ãŒãã°ããŒãã«ã®ãäœæãããã³ããã³ãã«ã®è¡šç€ºã
ããŒããã·ã§ã³ãæã£ãŠãããšããã³ãã«ã°ã«ãŒãã¯å²ãåœãŠãããŸããããã®å Žå以å€ã¯ãæäœã§ã
1 ã€ã®ãã³ãã«ã°ã«ãŒããå²ãåœãŠãå¿
èŠããããŸãã
view_bundle_createWizard_groupsStep_leaveUnassigned=æ°ãããã³ãã«ã¯å²ãåœãŠãªãã§ãã ããã
view_bundle_createWizard_groupsStep_noAssignable=å²ãåœãŠã§ãããã³ãã«ã°ã«ãŒãããŠãŒã¶ãŒãæã£ãŠããªããããæåã®ãã³ãã«ããŒãžã§ã³ãäœæã§ããŸãããäœæãŠã£ã¶ãŒãããã£ã³ã»ã«ãã管çè
ã«å ±åããŠãã ããã
view_bundle_createWizard_groupsStep_noneAssigned=æ°ãããã³ãã«ããŒãžã§ã³ãæäœã§ã
1 ã€ã®ãã³ãã«ã°ã«ãŒããžå²ãåœãŠãå¿
èŠããããŸãã
@@ -1509,7 +1509,7 @@
view_bundle_createWizard_groupsStep_unassigned=æ°ãããã³ãã«ããŒãžã§
view_bundle_createWizard_loadBundleFileFailure=ãµãŒããŒãããã³ãã«ãã¡ã€ã«æ
å ±ã®ååŸãã§ããŸãã
view_bundle_createWizard_noAdditionalFilesNeeded=ãã®ãã³ãã«ã®ããã«ã¢ããããŒããããå¿
èŠãããè¿œå ãã¡ã€ã«ã¯ãããŸãã
view_bundle_createWizard_noBundleTypesAvail=ãã³ãã«ã¿ã€ããå©çšã§ããŸãã
-view_bundle_createWizard_noBundleTypesSupported=ãã³ãã«ã¿ã€ãã¯äžã€ããµããŒããããŠããŸãã
-
ãã³ãã«ãããã€ã¡ã³ãããµããŒãããæ£ãããã©ã°ã€ã³ããããã€ããªããã°ãªããŸãã
+view_bundle_createWizard_noBundleTypesSupported=ãµããŒãããããã³ãã«ã¿ã€ãã¯ãããŸãã
-
ãã³ãã«ãããã€ã¡ã³ãããµããŒãããæ£ãããã©ã°ã€ã³ããããã€ããå¿
èŠããããŸã
view_bundle_createWizard_provideBundleDistro=ãã³ãã«é
åžã®æäŸ
view_bundle_createWizard_recipeOption=ã¬ã·ã
view_bundle_createWizard_title=ãã³ãã«äœæ
@@ -1527,7 +1527,7 @@ view_bundle_createWizard_urlUserName=ãŠãŒã¶ãŒå
# #view_bundle_createWizard_urlUserName = User name
view_bundle_createWizard_windowTitle=ãã³ãã«äœæãŠã£ã¶ãŒã
view_bundle_createWizard_youMustChooseOne=ãã³ãã«ãäœæããããã®ãªãã·ã§ã³ãéžæããªããã°ãªããŸãã
-view_bundle_deleteConfirm=ãã®ãã³ãã«ãåé€ããŠãããããã§ãã?
ãã®ãã³ãã«ã®ãã¹ãŠã®ããŒãžã§ã³ãå®å
ããããã€ãåé€ãããŸãã
+view_bundle_deleteConfirm=ãã®ãã³ãã«ãåé€ããŠãããããã§ãã?
ãã®ãã³ãã«ã®ãã¹ãŠã®ããŒãžã§ã³ãå®å
ããããã€ãåé€ãããŸããããªã¢ãŒããã·ã³ã®å
容ã¯åé€ãããŸããã
view_bundle_deploy=ãããã€
view_bundle_deployDir=ãããã€ãã£ã¬ã¯ããª
view_bundle_deployWizard_createGroup_error_1=ã°ã«ãŒããäœæãããŸããã§ããããããã€ã¡ã³ãã®ã°ã«ãŒãã¯ç©ºã«ã¯ã§ããŸããã
@@ -1547,23 +1547,23 @@
view_bundle_deployWizard_deploymentScheduledDetail_concise=ãã³ãã«ããã
view_bundle_deployWizard_destinationCreatedDetail=ãã£ã¹ã¯ãªãã·ã§ã³ [{1}]
ã®ä»ãããããã€ã¡ã³ã [{0}] ãäœæããŸãã
view_bundle_deployWizard_destinationCreatedDetail_concise=å®å
[{0}] ãäœæããŸãã
view_bundle_deployWizard_error_1=ãã£ã³ã»ã«ã«ã€ããŠã®æ°ãããããã€ã¡ã³ãã®åé€ã«å€±æããŸãã
-view_bundle_deployWizard_error_10=å®å
ã®äœæã«å€±æããŸãããããã¯ãã§ã«ååšãããããããŸããã
(泚æïŒå®å
ãã¥ãŒããæ¢åã®å®å
ãããã€ã®ãã)
+view_bundle_deployWizard_error_10=å®å
ã®äœæã«å€±æããŸãããå®å
ã¯ãã§ã«ååšããå¯èœæ§ããããŸã (å®å
ãã¥ãŒãããããã€ãããæ¢åã®å®å
)ã
view_bundle_deployWizard_error_11=å®çŸ©æžã¿ãããã€ã¡ã³ãã®æ€çŽ¢ã«å€±æããŸãã
view_bundle_deployWizard_error_12=å®çŸ©æžã¿ãã³ãã«ã®æ€çŽ¢ã«å€±æããŸãã
-view_bundle_deployWizard_error_2=ãã£ã³ã»ã«ã«ã€ããŠã®æ°ããå®å
ã®åé€ã«å€±æããŸãã
+view_bundle_deployWizard_error_2=ãã£ã³ã»ã«ã§æ°ããå®å
ã®åé€ã«å€±æããŸãã
view_bundle_deployWizard_error_3=ãããã€ã¡ã³ãã®ã¹ã±ãžã¥ãŒã«ã«å€±æããŸãã\!
view_bundle_deployWizard_error_4=ãããã€ã¡ã³ãã®ã¹ã±ãžã¥ãŒã«ã«å€±æããŸãã\:
{0}
view_bundle_deployWizard_error_5=ãããã€ã¡ã³ãã®äœæã«å€±æããŸãã\!
view_bundle_deployWizard_error_6=ãããã€ã¡ã³ãã®äœæã«å€±æããŸãã\:
{0}
view_bundle_deployWizard_error_7=ãããã€ã¡ã³ãåã®ååŸã«å€±æããŸãã
-view_bundle_deployWizard_error_8=ããããããŠã³ããæ£ãããªãœãŒã¹ã°ã«ãŒããéžæããªããã°ãªããŸãã
+view_bundle_deployWizard_error_8=ããããããŠã³ã¡ãã¥ãŒããæ£ãããªãœãŒã¹ã°ã«ãŒããéžæããªããã°ãªããŸãã
view_bundle_deployWizard_error_9=次ããŒãžã§ã®æ°ããå®å
ã®åé€ã«å€±æããŸãã
view_bundle_deployWizard_error_noBundleConfig=ãã³ãã«ã¿ãŒã²ããæ
å ±ã®ååŸã«å€±æããŸãããéžæããã°ã«ãŒãã¯ãã³ãã«ãããã€ã¡ã³ãã®ã¿ãŒã²ããã«æãåŸãæ£åœãªäºæã°ã«ãŒãã§ãã?
view_bundle_deployWizard_getConfigSkip=ãã®ãã³ãã«ããŒãžã§ã³ã«èšå®ã¯å¿
èŠãããŸãã
view_bundle_deployWizard_getConfigStep=ãããã€ã¡ã³ãã®èšå®
view_bundle_deployWizard_getDestStep=æ°ããå®å
-view_bundle_deployWizard_getDest_deployDir=ã«ãŒããããã€ãã£ã¬ã¯ã㪠(å®å
ãã©ãããã©ãŒã äžã§ã®)
-view_bundle_deployWizard_getDest_deployDir_help=ãã®ãã³ãã«ããããã€ããããã£ã¬ã¯ããªããã®ãã£ã¬ã¯ããªã¯ãã¹ãŠã®ãªãœãŒã¹ã«é¢ãããã¹ãŠã®ãããã€çšãšããŠåããã®ã䜿ãããŸãããå®å
ã®åºæ¬ãã£ã¬ã¯ããªã®å Žæã«å¯Ÿããçžå¯Ÿãã£ã¬ã¯ããªã«ãªããŸãããã®ããšã¯ãç°ãªãã¿ãŒã²ãããªãœãŒã¹ã«ã€ããŠåºæ¬ãã£ã¬ã¯ããªã®é
眮ãã©ãã«ããããšããããšã«äŸåããŠããã®çµ¶å¯Ÿãã£ã¬ã¯ããªã¯ç°ãªãã¿ãŒã²ãããªãœãŒã¹ã«ãã£ãŠç°ãªããã¹ã«ãªãå¯èœæ§ãããããšãæå³ããŠããŸãã
+view_bundle_deployWizard_getDest_deployDir=ãããã€ã¡ã³ããã£ã¬ã¯ããª
+view_bundle_deployWizard_getDest_deployDir_help=ãã®ãã³ãã«ããããã€ããããã£ã¬ã¯ããªããã®ãã£ã¬ã¯ããªã¯ãã¹ãŠã®ãªãœãŒã¹ã®ãã¹ãŠã®ãããã€ã¡ã³ãã§åããã®ã䜿ãããŸãããå®å
ã®ããŒã¹ãã£ã¬ã¯ããªã®å Žæã«çžå¯ŸããŸãããã£ãŠãã¿ãŒã²ãããªãœãŒã¹äžã§ããŒã¹ãšãªãå Žæã«å¿ããŠã絶察ãã£ã¬ã¯ããªã¯ã¿ãŒã²ãããªãœãŒã¹ã«ãã£ãŠç°ãªããã¹ãæã€å¯èœæ§ããããŸãã
view_bundle_deployWizard_getDest_desc=å®å
ã®èª¬æ
view_bundle_deployWizard_getDest_destBaseDirName=åºæ¬ã®é
眮
view_bundle_deployWizard_getDest_group_help=ã¡ã³ããŒããã¹ãŠã®ãã³ãã«ãããã€ã®ããã®å®å
ã¿ãŒã²ãããšãªããããªã°ã«ãŒãããã³ãã«ãããã€ããµããŒããããªãœãŒã¹ãå«ãäºæã°ã«ãŒãã®ã¿ãéžæå¯èœã§ãã
@@ -1578,10 +1578,10 @@
view_bundle_deployWizard_getOptions_deployLater=åŸã§ãããã€ãã
view_bundle_deployWizard_getOptions_deployNow=ä»ãããããã€ãã
view_bundle_deployWizard_getOptions_deployTime=ãããã€æå»
view_bundle_deployWizard_selectBundleStep=ãããã€ãã³ãã«ã®éžæ
-view_bundle_deployWizard_selectBundle_single=ãããã€ã®ããã«åäžãã³ãã«ã ããéžæããŠãã ãã
+view_bundle_deployWizard_selectBundle_single=ãããã€ã«åäžã®ãã³ãã«ã®ã¿ãéžæããŠãã ãã
view_bundle_deployWizard_selectVersionStep=ãã³ãã«ããŒãžã§ã³ãéžæããŠãã ãã
view_bundle_deployWizard_selectVersion_latest=ææ°ããŒãžã§ã³ [{0}]
-view_bundle_deployWizard_selectVersion_live=åäœããŒãžã§ã³ [{0}]
+view_bundle_deployWizard_selectVersion_live=ã©ã€ãããŒãžã§ã³ [{0}]
view_bundle_deployWizard_selectVersion_select=ãªã¹ãããããŒãžã§ã³ãéžæããŠãã ãã\:
view_bundle_deployWizard_title=ãã³ãã«ãããã€ã®ãŠã£ã¶ãŒã
view_bundle_deploy_action=ã¢ã¯ã·ã§ã³
@@ -1607,20 +1607,20 @@ view_bundle_deployments=ãããã€
view_bundle_dest_backToBundle=ãã³ãã«ãžæ»ã
view_bundle_dest_baseDirName=åºæ¬ã®é
眮
view_bundle_dest_created=äœæããã
-view_bundle_dest_deleteConfirm=ãã®ãã³ãã«å®å
ãåé€ããŠãããããã§ãã?
ããã¯ããŒã¿ããŒã¹ããåé€ããã ãã§ããã€ãŸãããªã¢ãŒããã·ã³ã®ãã®å®å
ã«ãããã€ããããã¹ãŠã®ãã³ãã«ã®å
容ã¯æ®ãç¶ããŸã
+view_bundle_dest_deleteConfirm=ãã®ãã³ãã«å®å
ãåé€ããŠãããããã§ãã?
ããã¯ããŒã¿ããŒã¹ããã®ã¿åé€ãããŸããã€ãŸãããªã¢ãŒããã·ã³ã®ãã®å®å
ã«ãããã€ããããã¹ãŠã®ãã³ãã«ã®å
容ã¯åé€ãããŸããã
view_bundle_dest_deleteFailure=ãã³ãã«å®å
[{0}] ã®åé€ã«å€±æããŸãã
view_bundle_dest_deleteSuccessful=ãã³ãã«å®å
[{0}] ã®åé€ã«æåããŸãã
view_bundle_dest_deployDir=ãããã€ãã£ã¬ã¯ããª
view_bundle_dest_group=ã°ã«ãŒã
view_bundle_dest_lastDeployedVersion=æåŸã«ãããã€ãããããŒãžã§ã³
-view_bundle_dest_lastDeploymentDate=æåŸã®ãããã€ããããæ¥ä»
+view_bundle_dest_lastDeploymentDate=æåŸã®ãããã€ã¡ã³ãã®æ¥ä»
view_bundle_dest_lastDeploymentStatus=æåŸã®ãããã€ã¡ã³ãã¹ããŒã¿ã¹
view_bundle_dest_loadFailure=ãã³ãã«ã®å®å
ãããŒãããã®ã«å€±æããŸãã
view_bundle_dest_loadFailureVersionInfo=ãããã€ãããããŒãžã§ã³æ
å ±ã®ããŒãã«å€±æããŸãã
-view_bundle_dest_purgeConfirm=ãã®æäœã¯ãã¹ãŠã®ãªã¢ãŒããã·ã³ãããã³ãã«ã³ã³ãã³ããé€å»ããŸããããããã§ãã?
-view_bundle_dest_purgeFailure=ãªã¢ãŒããã·ã³ã®äžéšãããã¯ãã¹ãŠããã®ãã³ãã«å®å
[{0}] ã®é€å»ã«å€±æããŸãã
-view_bundle_dest_purgeSuccessful=ãªã¢ãŒããã·ã³ã®äžéšãããã¯ãã¹ãŠããã®ãã³ãã«å®å
[{0}] ã®é€å»ã«æåããŸãã
-view_bundle_dest_revertConfirm=ããã¯ãã¹ãŠã®ãªã¢ãŒããã·ã³ã以åã®ãã³ãã«ãããã€ã¡ã³ããžæ»ããŸãããããããŠãããããã§ãã?
+view_bundle_dest_purgeConfirm=ãã®æäœã¯ãã¹ãŠã®ãªã¢ãŒããã·ã³ãããã³ãã«ã³ã³ãã³ããããŒãžããŸããããããã§ãã?
+view_bundle_dest_purgeFailure=ãªã¢ãŒããã·ã³ã®äžéšãããã¯ãã¹ãŠãããã³ãã«å®å
[{0}] ã®ããŒãžã«å€±æããŸãã
+view_bundle_dest_purgeSuccessful=ãªã¢ãŒããã·ã³ã®äžéšãããã¯ãã¹ãŠãããã³ãã«å®å
[{0}] ãæ£åžžã«ããŒãžããŸãã
+view_bundle_dest_revertConfirm=ããã¯ãã¹ãŠã®ãªã¢ãŒããã·ã³ã以åã®ãã³ãã«ãããã€ã¡ã³ããžæ»ããŸããå®è¡ããŠãããããã§ãã?
view_bundle_dest_tagUpdateFailure=ãã³ãã«å®å
ã¿ã°ã®æŽæ°ã«å€±æããŸãã
view_bundle_dest_tagUpdateSuccessful=ãã³ãã«å®å
ã¿ã°ã®æŽæ°ã«æåããŸãã
view_bundle_destinations=å®å
@@ -1650,28 +1650,28 @@
view_bundle_list_singleLoadFailure=ãããã€ãããåäžãã³ãã« [{0}]
view_bundle_list_tagUpdateFailure=ãã³ãã«ã¿ã°ã®æŽæ°ã«å€±æããŸãã
view_bundle_list_tagUpdateSuccessful=ãã³ãã«ã¿ã°ã®æŽæ°ã«æåããŸãã
view_bundle_list_versionsCount=ããŒãžã§ã³æ°
-view_bundle_purge=é€å»
-view_bundle_recipe=ãªã·ã
-view_bundle_resDeployDS_loadFailure=ãã³ãã«ãªãœãŒã¹ãããã€ã®ããŒãã«å€±æããŸãã
+view_bundle_purge=ããŒãž
+view_bundle_recipe=ã¬ã·ã
+view_bundle_resDeployDS_loadFailure=ãã³ãã«ãªãœãŒã¹ãããã€ã¡ã³ãã®ããŒãã«å€±æããŸãã
view_bundle_revert=åãæ¶ã
view_bundle_revertWizard_confirmStep_confirmation=åäœäžã®ãããã€ã以åã®ãããã€ãžåãæ¶ãäžã§ããç¶ç¶ããã«ã¯"次ãž"ãã¯ãªãã¯ããŠãã ããã
view_bundle_revertWizard_confirmStep_failedToFindLiveDeployment=åäœäžã®ãããã€ãèŠã€ãããŸãããåãæ¶ããã§ããŸããã
view_bundle_revertWizard_confirmStep_liveDeployment=åäœäžã®ãããã€
view_bundle_revertWizard_confirmStep_name=åãæ¶ããããã€ç¢ºèª
-view_bundle_revertWizard_confirmStep_noLiveDeployment=ãã®å®å
[{0}] çšã®åäœäžã®ãããã€ã¯èŠã€ãããŸããã§ãã
-view_bundle_revertWizard_confirmStep_noLiveDeployment_concise=ãã®å®å
çšã®åäœäžã®ãããã€ã¯èŠã€ãããŸããã§ãã
-view_bundle_revertWizard_confirmStep_noPriorDeployment=以åã®ããã〠[{1}]
ãååšããªãã®ã§åäœäžã®ããã〠[{0}]
ã¯åãæ¶ãããšãã§ããŸããã§ãã
-view_bundle_revertWizard_confirmStep_noPriorDeployment_concise=以åã®ãããã€ãååšããªãã®ã§åäœäžã®ãããã€ã¯åãæ¶ãããšãã§ããŸããã§ãã
-view_bundle_revertWizard_confirmStep_prevDeployment=以åã®ãããã€
-view_bundle_revertWizard_getInfoStep_cleanDeploy=ãããã€ãåé€ããŸãã?
(ããã¯å€ããæ¢åã®ãããã€ãã£ã¬ã¯ããªãåãæ¶ããããã€ãéå§ããåã«åé€ããŸã)
-view_bundle_revertWizard_getInfoStep_getNameFailure=åãæ¶ããããã€åã®ååŸã«å€±æããŸãã
+view_bundle_revertWizard_confirmStep_noLiveDeployment=å®å
[{0}] çšã®åäœäžã®ãããã€ã¡ã³ãã¯èŠã€ãããŸããã§ãã
+view_bundle_revertWizard_confirmStep_noLiveDeployment_concise=å®å
çšã®åäœäžã®ãããã€ã¡ã³ãã¯èŠã€ãããŸããã§ãã
+view_bundle_revertWizard_confirmStep_noPriorDeployment=å®å
[{1}]
ã®ä»¥åã®ãããã€ã¡ã³ããååšããªããããåäœäžã®ãããã€ã¡ã³ã
[{0}] ã¯åãæ¶ãããšãã§ããŸããã§ãã
+view_bundle_revertWizard_confirmStep_noPriorDeployment_concise=以åã®ãããã€ãååšããªãããåäœäžã®ãããã€ã¯åãæ¶ãããšãã§ããŸããã§ãã
+view_bundle_revertWizard_confirmStep_prevDeployment=以åã®ãããã€ã¡ã³ã
+view_bundle_revertWizard_getInfoStep_cleanDeploy=ãããã€ã¡ã³ããåé€ããŸãã?
(ããã«ããããããã€ã¡ã³ãã®åãæ¶ããéå§ããåã«ãæ¢åã®å€ããããã€ãã£ã¬ã¯ããªãåé€ãããŸã)
+view_bundle_revertWizard_getInfoStep_getNameFailure=åãæ¶ããããã€ã¡ã³ãåã®ååŸã«å€±æããŸãã
view_bundle_revertWizard_getInfoStep_name=åãæ¶ãæ
å ±ã®æäŸ
view_bundle_revertWizard_getInfoStep_revertDeployDesc=ãããã€èšè¿°ã®åãæ¶ã
view_bundle_revertWizard_getInfoStep_revertDeployDescFull=[åãæ¶ã å] {0}
[åãæ¶ã åŸ] {1}
view_bundle_revertWizard_getInfoStep_revertDeployName=ãããã€åã®åãæ¶ã
view_bundle_revertWizard_revertStep_name=å®å
ãã©ãããã©ãŒã ãžãã³ãã«ããããã€
view_bundle_revertWizard_revertStep_reverting=åãæ¶ãäž...
-view_bundle_revertWizard_revertStep_scheduled=ãããã€ã®åãæ¶ãã®ã¹ã±ãžã¥ãŒã«ã«æåããŸããã
+view_bundle_revertWizard_revertStep_scheduled=ãããã€ã¡ã³ãã®åãæ¶ãã®ã¹ã±ãžã¥ãŒã«ã«æåããŸããã
view_bundle_revertWizard_revertStep_scheduledDetails=ãªãœãŒã¹ã°ã«ãŒã [{1}]
ãããã³ãã«ããã〠[{0}]
ã®åãæ¶ãã®ã¹ã±ãžã¥ãŒã«ã«æåããŸãã
view_bundle_revertWizard_revertStep_scheduledFailure=ãããã€ã®åãæ¶ãã®ã¹ã±ãžã¥ãŒã«ã«å€±æããŸãã
view_bundle_revertWizard_title=ãã³ãã«åãæ¶ã
@@ -1684,7 +1684,7 @@
view_bundle_tree_unassigned_name=å²ãåœãŠãããŠããªããã³ãã«
view_bundle_version_backToBundle=ãã³ãã«ãžæ»ã
view_bundle_version_bundleVersionTagUpdateFailure=ãã³ãã«ããŒãžã§ã³ã¿ã°ã®æŽæ°ã«å€±æããŸãã
view_bundle_version_bundleVersionTagUpdateSuccessful=ãã³ãã«ããŒãžã§ã³ã¿ã°ã®æŽæ°ã«æåããŸãã
-view_bundle_version_deleteConfirm=ãã®ãã³ãã«ããŒãžã§ã³ãåé€ããŠãããããã§ãã?
+view_bundle_version_deleteConfirm=ãã®ãã³ãã«ããŒãžã§ã³ãåé€ããŠãããããã§ãã?
ãªã¢ãŒããã·ã³ã®ã³ã³ãã³ãã¯åé€ãããŸããã
view_bundle_version_deleteFailure=ãã®ãã³ãã«ããŒãžã§ã³ [{0}]
ãåé€ããã®ã«å€±æããŸãã
view_bundle_version_deleteSuccessful=ãã³ãã«ããŒãžã§ã³ [{0}]
ã®åé€ã«æåããŸãã
view_bundle_version_loadFailure=ãã³ãã«ããŒãžã§ã³ã®ããŒãã«å€±æããŸãã
@@ -1722,7 +1722,7 @@ view_configEdit_msg_4=ãªã¹ãã«è¿œå ãããã¢ã€ãã
view_configEdit_properties=ããããã£
view_configEdit_property=ããããã£ãŒ
# #view_configEdit_property = Property
-view_configEdit_tooltip_1=ãªã¹ãããéžæãããã¢ã€ãã ãåé€ããŸã
+view_configEdit_tooltip_1=ãªã¹ãããéžæãããã¢ã€ãã ãåé€ããŸã
view_configEdit_tooltip_2=ãªã¹ãã«ã¢ã€ãã ãè¿œå ããŸã
view_configEdit_unset=æªèšå®ã«ããŸãã?
# #view_configEdit_unset = Unset?
@@ -1749,12 +1749,12 @@
view_configurationHistoryList_table_statusInprogress=ãã®èšå®ã®æŽæ°ã¯ãŸ
view_configurationHistoryList_table_statusNochange=ãã®èšå®ã¯å€æŽãããŸããã§ãã
view_configurationHistoryList_table_statusSuccess=ãã®èšå®ã®æŽæ°ã¯æåããŸãã
view_configurationHistoryList_title=èšå®å±¥æŽ
-view_connectionSettingsDetails_allPropertiesValid=ãã¹ãŠã®ã³ãã¯ã·ã§ã³èšå®ã¯æ£ããå€ã§ãã®ã§ããã®èšå®ã¯ä¿åå¯èœã§ã
-view_connectionSettingsDetails_error_updateFailure=ã³ãã¯ã·ã§ã³èšå®ã®æŽæ°ã«å€±æããŸãã
-view_connectionSettingsDetails_messageConcise_updateSuccess=ã³ãã¯ã·ã§ã³èšå®ãæŽæ°ãããŸãã
-view_connectionSettingsDetails_messageDetailed_updateSuccess=ãªãœãŒã¹ [{0}
ã®ããã®ã³ãã¯ã·ã§ã³èšå®ãæŽæ°ãããŸãã
-view_connectionSettingsDetails_noPermission=ãã®ãªãœãŒã¹ã®ã³ãã¯ã·ã§ã³èšå®ãç·šéããæš©éããããŸãã
-view_connectionSettingsDetails_somePropertiesInvalid=次ã®ã³ãã¯ã·ã§ã³èšå®ã¯äžæ£ãªå€\:
{0} ã§ããèšå®ãä¿åããåã«èšæ£ããªããã°ãªããŸããã
+view_connectionSettingsDetails_allPropertiesValid=ãã¹ãŠã®æ¥ç¶èšå®ã®å€ãæå¹ã§ãããããèšå®ãä¿åã§ããŸãã
+view_connectionSettingsDetails_error_updateFailure=æ¥ç¶èšå®ã®æŽæ°ã«å€±æããŸãã
+view_connectionSettingsDetails_messageConcise_updateSuccess=æ¥ç¶èšå®ã®æŽæ°ãéå§ãããŸããã
+view_connectionSettingsDetails_messageDetailed_updateSuccess=ãªãœãŒã¹ [{0}
ã®æ¥ç¶èšå®ã®æŽæ°ãéå§ãããŸããã
+view_connectionSettingsDetails_noPermission=ãã®ãªãœãŒã¹ã®æ¥ç¶èšå®ãç·šéããæš©éããããŸãã
+view_connectionSettingsDetails_somePropertiesInvalid=次ã®æ¥ç¶èšå®ã®å€ã¯ç¡å¹ã§ã\:
{0}ãèšå®ãä¿åããã«ã¯ãå€ãä¿®æ£ããå¿
èŠããããŸãã
view_core_loggedOut=ãã°ã¢ãŠã
view_core_noRecentAlerts=ã¬ããŒããã¹ãæè¿ã®ã¢ã©ãŒãã¯ååšããŸãã
view_core_recentAlerts=[{0}] åã®æè¿ã®ã¢ã©ãŒãããããŸãã -
æè¿ã®ã¢ã©ãŒãã¬ããŒããžã¯ãªãã¯ããŠãã ãã
@@ -1797,8 +1797,8 @@ view_drift_category_fileNew=æ°èŠã«æ€åºããããã¡ã€ã«
view_drift_category_fileRemoved=åé€ãã¡ã€ã«
view_drift_confirm_deleteAllDefs=ããªããæ€åºå®çŸ©ããã¹ãŠåé€ããŸãã?
view_drift_confirm_deleteDefs=éžæããããªããæ€åºå®çŸ©ãåé€ããŸãã?
-view_drift_confirm_deleteTemplate=èŠå\!
ãã®ãã³ãã¬ãŒããåé€ãããšãã¢ã¿ãããããããªããå®çŸ©ããã¹ãŠåé€ãããŸããã¢ã¿ãããããå®çŸ©ã¯ãããã®ã¹ãããã·ã§ãããšãšãã«ã·ã¹ãã ããæ°žä¹
çã«åé€ãããŸããã§ã¿ãããããå®çŸ©ã¯åé€ãããŸãããæ¬åœã«ç¶ç¶ããŠãããããã§ãã?
-view_drift_failure_deleteDefs=ããã€ãããããã¯ãã¹ãŠã®ããªããæ€åºå®çŸ©ã®åé€ã«å€±æããŸãã
+view_drift_confirm_deleteTemplate=èŠå\!
ãã®ãã³ãã¬ãŒããåé€ãããšãã¢ã¿ãããããããªããå®çŸ©ããã¹ãŠåé€ãããŸããã¢ã¿ãããããå®çŸ©ã¯ãããã®ã¹ãããã·ã§ãããšãšãã«ã·ã¹ãã ããæ°žä¹
çã«åé€ãããŸãããã¿ãããããå®çŸ©ã¯åé€ãããŸãããæ¬åœã«ç¶ç¶ããŠãããããã§ãã?
+view_drift_failure_deleteDefs=äžéšãããã¯ãã¹ãŠã®ããªããæ€åºå®çŸ©ã®åé€ã«å€±æããŸãã
view_drift_failure_deleteTemplates=ããªãããã³ãã¬ãŒãã®äžéšãŸãã¯ãã¹ãŠãåé€ã§ããŸããã§ããã
view_drift_failure_detectNow=ããªããæ€åºå®è¡ãªã¯ãšã¹ãã®éä¿¡ã«å€±æããŸãã
view_drift_failure_load=ããªããã€ã³ã¹ã¿ã³ã¹ã®åãåºãã«å€±æããŸãã
@@ -1834,35 +1834,35 @@ view_drift_table_title_initialSnapshot=å®çŸ© [{0}]
ã®ããã®åæã¹ãã
view_drift_table_title_snapshot=å®çŸ© [{1}] ã®ããã®ã¹ãããã·ã§ãã [{0}]
view_drift_table_title_templateSnapshot=ãã³ãã¬ãŒã [{0}]
ã®ããã®ãã³çããããã¹ãããã·ã§ãã
view_drift_wizard_addDef_failure=ããªããæ€åºå®çŸ©ã[{0}]ãã®æ°èŠè¿œå ã«å€±æããŸãã
-view_drift_wizard_addDef_infoStepHelp=åããªããæ€åºå®çŸ©ã¯ããªããã¢ãã¿ãªã³ã°ãå®è¡ãããäžåŒã®ãã¡ã€ã«ãèšè¿°ããŸãããã®å®çŸ©ã¯æå¹ãŸãã¯ç¡å¹ã«ããããæ€åºã®å®è¡ééãå®çŸ©ããããåºæ¬ãã£ã¬ã¯ããªãšãã¡ã€ã«ãã£ã«ã¿(ãªãã·ã§ã³)ãæå®ããããšãã§ããŸããããªããæ€åºãæäŸãããªãœãŒã¹ã¿ã€ãããšã«ãéå§ããå®çŸ©ãšããŠäœ¿çšããããã®äžã€ä»¥äžã®æ¢å®ã®ãã³ãã¬ãŒããååšããŸãã
-view_drift_wizard_addDef_infoStepName=ãã®æ°èŠããªããæ€åºå®çŸ©ã®ãã³ãã¬ãŒããéžæããŠãã ãã
+view_drift_wizard_addDef_infoStepHelp=åããªããæ€åºå®çŸ©ã¯ãããªããã®ç£èŠãå®è¡ããããã¡ã€ã«ãèšè¿°ããŸããå®çŸ©ã¯æå¹ãŸãã¯ç¡å¹ã«ã§ããæ€åºå®è¡ã®ééãå®çŸ©ããããŒã¹ãã£ã¬ã¯ããªãšãªãã·ã§ã³ã®ãã¡ã€ã«ãã£ã«ã¿ãŒãæå®ããŸããããªããæ€åºãæäŸãããªãœãŒã¹ã¿ã€ãããšã«ãæåã®å®çŸ©ãšããŠäœ¿çšã§ãã
1
ã€ä»¥äžã®äºåå®çŸ©ãã³ãã¬ãŒãããããŸãããã®ãã³ãã¬ãŒãã¯ç·šéå¯èœã§ãã
+view_drift_wizard_addDef_infoStepName=æ°èŠããªããæ€åºå®çŸ©ã®ãã³ãã¬ãŒããéžæããŠãã ãã
view_drift_wizard_addDef_success=æ°èŠããªããæ€åºå®çŸ© [{0}]
ã®è¿œå ã«æåããŸããããšãŒãžã§ã³ãã¯æŽæ°ãããŸãã
view_drift_wizard_addDef_templatePrompt=ããªããå®çŸ©ãã³ãã¬ãŒã
-view_drift_wizard_addDef_title=ã¿ã€ãã®ãªãœãŒã¹ [{0}]
ã®ããã®ããªããæ€åºå®çŸ©ãè¿œå ããŠãã ãã
+view_drift_wizard_addDef_title=ã¿ã€ã [{0}]
ã®ãªãœãŒã¹ã®ããªããæ€åºå®çŸ©ãè¿œå
view_drift_wizard_addDef_windowTitle=ããªããæ€åºå®çŸ©ãŠã£ã¶ãŒãã®è¿œå
view_drift_wizard_addTemplate_failure=æ°èŠããªããæ€åºãã³ãã¬ãŒã [{0}]
ã®è¿œå ã«å€±æããŸãã
-view_drift_wizard_addTemplate_infoStepHelp=åããªãããã³ãã¬ãŒãã¯æ¢åã®ãã³ãã¬ãŒããã掟çããŠäœæã§ããŸããããã¯æ¢åãã³ãã¬ãŒãã«é¡äŒŒãããã®ãããã©ã°ã€ã³ãå®çŸ©ãããã³ãã¬ãŒãããæ°èŠãã³ãã¬ãŒããæ§ç¯ããçŽ æ©ãæ¹æ³ãæäŸããŸããããªããå®çŸ©ã®ããã«ããã®ãã³ãã¬ãŒãã¯ããªãããç£èŠãå®è¡ããäžåŒã®ãã¡ã€ã«ãèšè¿°ããŸããç¶æ³ã«ãã£ãŠã¯ããã®ãã³ãã¬ãŒãããå°åºãããå®çŸ©ã¯ãã®ãã¡ã€ã«ã»ããã®å€æŽããä»ã®èšå®ã®å€æŽãèš±ããããèš±ããªãã£ããããŸãããã³ãã¬ãŒãåã¯äžã€ã®ãªãœãŒã¹ã¿ã€ãå
ã§ãŠããŒã¯ã§ãªããã°ãªããŸããã
+view_drift_wizard_addTemplate_infoStepHelp=åããªãããã³ãã¬ãŒãã¯æ¢åã®ãã³ãã¬ãŒããåºã«ããŸããããã«ãããæ¢åã®ãã³ãã¬ãŒããšäŒŒãŠããæ°èŠãã³ãã¬ãŒããããã©ã°ã€ã³ãå®çŸ©ããããã³ãã¬ãŒããåºã«ããæ°èŠãã³ãã¬ãŒããè¿
éã«æ§ç¯ã§ããŸãããã©ããå®çŸ©ãšåæ§ã«ããã³ãã¬ãŒãã¯ããªããç£èŠãå®è¡ããããã¡ã€ã«ãèšè¿°ããŸãããã³ãã¬ãŒããåºã«ããå®çŸ©ã®ãã¡ã€ã«ã»ãããŸãã¯ä»ã®èšå®ã®å€æŽã¯ãç¶æ³ã«å¿ããŠèš±å¯ãŸãã¯æåŠãããŸãããã³ãã¬ãŒãåã¯ãªãœãŒã¹ã¿ã€ãå
ã§äžæã§ãªããã°ãªããŸããã
view_drift_wizard_addTemplate_infoStepName=éå§ãã³ãã¬ãŒãã®éžæ
view_drift_wizard_addTemplate_success=æ°èŠããªãããã³ãã¬ãŒã [{0}]
ã®è¿œå ã«æåããŸãã
view_drift_wizard_addTemplate_title=ã¿ã€ã [{0}]
ã®ããªããå®çŸ©ãã³ãã¬ãŒããè¿œå ããŠãã ãã
view_drift_wizard_addTemplate_windowTitle=ããªããå®çŸ©ãã³ãã¬ãŒãå®çŸ©ãã³ãã¬ãŒããŠã£ã¶ãŒãã®è¿œå
-view_drift_wizard_pinTemplate_confirmNotPinned=ãã®ãã³ãã¬ãŒãã®ããã®çŸåšãšå°æ¥ã®åããªããå®çŸ©ããã£ãããã³çãããããšããã®ãã³ãã¬ãŒãã¯ãã®åæã¹ãããã·ã§ããããã³ãã¬ãŒãã®ãã³çããããã¹ãããã·ã§ãããšããŠèšå®ãããããã«ããŸãããã®ãã³ãã¬ãŒãã®æ¢åã®å®çŸ©ã¯æ°èŠã®åæã¹ãããã·ã§ãããžãªã»ãããããŸãããã®ãã³ãã¬ãŒãã®æ¢åå®çŸ©ã¯æ°èŠåæã¹ãããã·ã§ãããžãªã»ããããããã¹ãŠã®æ¢åã¹ãããã·ã§ããã¯åé€ãããŸãããã®ã¹ãããã·ã§ãããžã®ãã³ãã¬ãŒãã®ãã³çããç¶ããŸãã?
-view_drift_wizard_pinTemplate_confirmPinned=èŠå\!
ãã®ãã³ãã¬ãŒãã¯ãã§ã«ãã³çããããŠããŸãããã®ãã³ãã¬ãŒãã¯ãã®æ°èŠã¹ãããã·ã§ããã«å床ãã³çãããããšãå¯èœã§ãããã®ãã³ãã¬ãŒãã®ããã®çŸåšãšå°æ¥ã®åããªããå®çŸ©ããã£ãããã³çãããããšããã®ãã³ãã¬ãŒãã¯åæã¹ãããã·ã§ããããã®ãã³ãã¬ãŒããæã€ãã³çããããã¹ãããã·ã§ãããšããŠèšå®ãããããã«ããŸãããã®ãã³ãã¬ãŒãã®æ¢åå®çŸ©ã¯æ°èŠåæã¹ãããã·ã§ãããžãªã»ããããããã¹ãŠã®æ¢åã¹ãããã·ã§ããã¯åé€ãããŸãããã®æ°èŠã¹ãããã·ã§ãããæã€ãã³ãã¬ãŒãã®ãã³çããç¶ããŸãã?
+view_drift_wizard_pinTemplate_confirmNotPinned=ãã³ãã¬ãŒãã®çŸåšããã³ä»åŸã®ããªããå®çŸ©ããã³çãããããšããã³ãã¬ãŒãã®ãã³çããããã¹ãããã·ã§ããã«åæã¹ãããã·ã§ãããèšå®ãããŸãããã®ãã³ãã¬ãŒãã®æ¢åã®å®çŸ©ã¯æ°ããåæã¹ãããã·ã§ãããžãªã»ãããããæ¢åã®ã¹ãããã·ã§ããã¯ãã¹ãŠåé€ãããŸãããã³ãã¬ãŒãã®ã¹ãããã·ã§ãããžã®ãã³çããç¶è¡ããŸãã?
+view_drift_wizard_pinTemplate_confirmPinned=èŠå\!
ãã®ãã³ãã¬ãŒãã¯ãã§ã«ãã³çããããŠããŸãããã³ãã¬ãŒãããã®æ°èŠã¹ãããã·ã§ããã«å床ãã³çãããããšãå¯èœã§ããå床ãã³çããããšããã³ãã¬ãŒãã®çŸåšããã³ä»åŸã®ããªããå®çŸ©ãæã€åæã¹ãããã·ã§ããããã³ãã¬ãŒãã®ãã³çããããã¹ãããã·ã§ãããžèšå®ãããŸãããã®ãã³ãã¬ãŒãã®æ¢åã®å®çŸ©ã¯æ°ããåæã¹ãããã·ã§ãããžãªã»ãããããæ¢åã®ã¹ãããã·ã§ããã¯ãã¹ãŠåé€ãããŸãããã®æ°èŠã¹ãããã·ã§ãããæã€ãã³ãã¬ãŒããå床ãã³çãããŸãã?
view_drift_wizard_pinTemplate_duplicate_name_error=ãã³ãã¬ãŒãåã¯äžæã§ãªããã°ãªããŸãã
view_drift_wizard_pinTemplate_failure=ããªãããã³ãã¬ãŒã [{0}]
ãžã®ã¹ãããã·ã§ããããã³çãããã®ã«å€±æããŸãã
view_drift_wizard_pinTemplate_infoStepExistingTemplate=çŸåšã®ãã³ãã¬ãŒããžã®ãã³çã
-view_drift_wizard_pinTemplate_infoStepHelp=ãã³çãããããã³ãã¬ãŒããéžæããŠãã ããããã®ãã³ãã¬ãŒãã®ããã®çŸåšãšå°æ¥ã®åããªããå®çŸ©ããã£ãããã³çãããããšããã®ãã³ãã¬ãŒãã¯åæã¹ãããã·ã§ããããã®ãã³ãã¬ãŒããæã€ãã³çããããã¹ãããã·ã§ãããšããŠèšå®ãããæã€ããã«ãªããŸããããã«ããŸãããããŠãã®å®çŸ©èªèº«ã¯ãã³çãããããã®ãšããŠããŒã¯ãããŸããããã¯æåŸ
ããããã¡ã€ã«ã»ããããããªãããæ€åºããã®ã«äœ¿ãããŸãããã®ãã³ãã¬ãŒãã®ããã®æ¢åå®çŸ©ã¯æ°èŠã®åæã¹ãããã·ã§ããã«ãªã»ããããããã¹ãŠã®æ¢åã¹ãããã·ã§ããã¯åé€ãããããšã«æ³šæããŠãã ããã
+view_drift_wizard_pinTemplate_infoStepHelp=ãã³ãã¬ãŒãã®çŸåšããã³ä»åŸã®ããªããå®çŸ©ããã³çãããããšããã³ãã¬ãŒãã®ãã³çããããã¹ãããã·ã§ããã«åæã¹ãããã·ã§ãããèšå®ãããŸãããŸããå®çŸ©èªäœããã³çãããããšã¿ãªãããŸããããã¯ãæ³å®ããããã¡ã€ã«ã»ããããããªãããæ€åºããããã«äœ¿çšãããŸãããã®ãã³ãã¬ãŒãã®æ¢åã®å®çŸ©ã¯æ°ããåæã¹ãããã·ã§ãããžãªã»ãããããæ¢åã®ã¹ãããã·ã§ããã¯ãã¹ãŠåé€ãããããšã«æ³šæããŠãã ããã
view_drift_wizard_pinTemplate_infoStepName=ãã³çãããããã³ãã¬ãŒãã®éžæ
-view_drift_wizard_pinTemplate_infoStepNewTemplate=æ°èŠãã³ãã¬ãŒããžã®ãã³çã
(ã¹ãããã·ã§ããã®ããªããå®çŸ©ããå°åºããããã®)
-view_drift_wizard_pinTemplate_infoStepRadioHelp=ãã®ã¹ãããã·ã§ããã¯æ°èŠãŸãã¯æ¢åã®ããªãããã³ãã¬ãŒãã«ãã³çãããããšãå¯èœã§ãããã®''æ°èŠãã³ãã¬ãŒã''ãªãã·ã§ã³ã¯ããŠãŒã¶ãŒã®æã«ãã£ãŠä¿¡é Œããå®çŸ©ãã¹ãããã·ã§ãããããªãœãŒã¹ã¬ãã«ãã¿ã€ãã¬ãã«ã§ããã³ãã¬ãŒãåã§ããããã«ããŸãããã®æ°èŠãã³ãã¬ãŒãã¯ã次ã«ããã®ã¿ã€ãã®ã¡ã³ããŒã«å¯ŸããŠé©çšã§ããŸãããã®æ°èŠãã³ãã¬ãŒãã¯åææã¯ã¹ãããã·ã§ããã®ããªããå®çŸ©ã®ã³ããŒã§ããã次ã®ã¹ãããã§ç·šéããããšãã§ããŸãããã®ååã¯å€æŽãã¹ãã§ããã®ã¿ã€ãã®ãŠããŒã¯ãªããªãããã³ãã¬ãŒãåã§ãªããã°ãªããŸããã''æ¢åãã³ãã¬ãŒã''ãªãã·ã§ã³ã¯ããŠãŒã¶ãŒãéžæããã¹ãããã·ã§ãããæã€æ¢åãã³ãã¬ãŒãã«å¯ŸããŠããã³çã
ãŸãã¯å床ãã³çããã§ããããã«ããŸããæ£ããèšå®ããã«ã¯ããã®æ¢åãã³ãã¬ãŒãã¯åããã£ã¬ã¯ããªããã®ã¹ãããã·ã§ããå®çŸ©ãšããŠç£èŠã§ããªããã°ãªããŸãããã»ã¬ã¯ã·ã§ã³ããã¯ã¹ã¯æ£åœãªæ¢åã®ãã³ãã¬ãŒãã ãã衚瀺ããŸããããæ£åœã§ãªãæ¢åãã³ãã¬ãŒããååšãããšããŠããã®ãªãã·ã§ã³ã§ã¯éžæãããŸããã
+view_drift_wizard_pinTemplate_infoStepNewTemplate=æ°èŠãã³ãã¬ãŒããžã®ãã³çã
(ã¹ãããã·ã§ããã®ããªããå®çŸ©ãã掟ç)
+view_drift_wizard_pinTemplate_infoStepRadioHelp=ã¹ãããã·ã§ãããæ°èŠãŸãã¯æ¢åã®ããªãããã³ãã¬ãŒãã«ãã³çãã§ããŸãããæ°èŠãã³ãã¬ãŒãããªãã·ã§ã³ã䜿çšãããšããŠãŒã¶ãŒã¯ãªãœãŒã¹ã¬ãã«ã®ä¿¡é Œã§ããå®çŸ©ããã³ã¹ãããã·ã§ããããã¿ã€ãã¬ãã«ãžææ Œã§ããŸãããã®åŸãæ°èŠãã³ãã¬ãŒããã¿ã€ãã®ã¡ã³ããŒãžé©çšã§ããŸããæ°èŠãã³ãã¬ãŒãã¯ãæåã¯ã¹ãããã·ã§ããã®ããªããå®çŸ©ã®ã³ããŒã§ããã次ã®ã¹ãããã§ç·šéå¯èœã§ããã¿ã€ãã«ãŠäžæã®ããªãããã³ãã¬ãŒãåãšãªãããã«ãååãå€æŽããå¿
èŠããããŸãããæ¢åãã³ãã¬ãŒãããªãã·ã§ã³ã䜿çšãããšããŠãŒã¶ãŒã¯éžæãããã¹ãããã·ã§ãããæã€æ¢åã®ãã³ãã¬ãŒãããã³çããŸãã¯å床ãã³çãã§ããŸããæ¢åã®ãã³ãã¬ãŒãã¯ãã¹ãããã·ã
§ããã®å®çŸ©ãšåããã£ã¬ã¯ããªãç£èŠããå¿
èŠããããŸããéžæããã¯ã¹ã¯æå¹ãªæ¢åãã³ãã¬ãŒãã®ã¿ã衚瀺ããŸããæå¹ãªæ¢åãã³ãã¬ãŒãããªãå Žåããã®ãªãã·ã§ã³ãéžæã§ããŸããã
view_drift_wizard_pinTemplate_infoStepRadioTitle=ãã³ãã¬ãŒãã®éžæ
-view_drift_wizard_pinTemplate_infoStepSelectBlocked=æ¢åãã³ãã¬ãŒãã§ã¹ãããã·ã§ããã®å®çŸ©ãšåããã£ã¬ã¯ããªãç£èŠãããã®ã¯ååšããŸãããç¶ç¶ããã«''æ°èŠãã³ãã¬ãŒã''ãªãã·ã§ã³ãéžæããŠãã ããã
+view_drift_wizard_pinTemplate_infoStepSelectBlocked=ã¹ãããã·ã§ããã®å®çŸ©ãšåããã£ã¬ã¯ããªãç£èŠããæ¢åãã³ãã¬ãŒãã¯ãããŸãããç¶ç¶ããã«ã¯ãæ°èŠãã³ãã¬ãŒãããªãã·ã§ã³ãéžæããŠãã ããã
view_drift_wizard_pinTemplate_infoStepSelectTitle=æ¢åãã³ãã¬ãŒã
view_drift_wizard_pinTemplate_success=ããªãããã³ãã¬ãŒã [{0}]
ã®ãã³çãã«æåããŸãã
view_drift_wizard_pinTemplate_title=ã¿ã€ã [{2}]
ã®ããªãããã³ãã¬ãŒããžã®å®çŸ© [{1}] ã®ã¹ãããã·ã§ãã [{0}]
ããã³çã
view_drift_wizard_pinTemplate_windowTitle=ããªããå®çŸ©ãã³ãã¬ãŒããŠã£ã¶ãŒãã®ãã³çã
-view_dynagroup_children=åçã°ã«ãŒãã®å
-view_dynagroup_compatible=äºæ
+view_dynagroup_children=DynaGroup ã®å
+view_dynagroup_compatible=äºææ§
view_dynagroup_definitionAlreadyExists=ãã§ã«ãã®ååã®ã°ã«ãŒãå®çŸ©ãååšããŸã
view_dynagroup_definitionCreated=ã°ã«ãŒãå®çŸ©å [{0}]
ã®äœæã«æåããŸãã
view_dynagroup_definitionLoadFailure=ã°ã«ãŒãå®çŸ©ã®ããŒãã«å€±æããŸãã
@@ -1872,13 +1872,13 @@ view_dynagroup_deleteSuccessfulSelection=[{0}]
ã°ã«ãŒãå®çŸ©ã®åé€ã«æ
view_dynagroup_editing=[{0}] ãç·šéäž
view_dynagroup_exprBuilder_addExpression=åŒã®è¿œå
view_dynagroup_exprBuilder_comparisonType=æ¯èŒã¿ã€ã
-view_dynagroup_exprBuilder_comparisonType_contains=ãå«ã
-view_dynagroup_exprBuilder_comparisonType_endsWith=ã§çµãã
+view_dynagroup_exprBuilder_comparisonType_contains=次ãå«ã\:
+view_dynagroup_exprBuilder_comparisonType_endsWith=次ã§çµãã\:
view_dynagroup_exprBuilder_comparisonType_equals=çãã
-view_dynagroup_exprBuilder_comparisonType_startsWith=ã§éå§ãã
+view_dynagroup_exprBuilder_comparisonType_startsWith=次ãšéå§ãã\:
view_dynagroup_exprBuilder_comparisonType_tooltip=æ¯èŒã¿ã€ã
view_dynagroup_exprBuilder_definingPlugin=å®çŸ©ãã©ã°ã€ã³
-view_dynagroup_exprBuilder_definingPlugin_tooltip=æ€çŽ¢ã®ããã®ãã©ã°ã€ã³
+view_dynagroup_exprBuilder_definingPlugin_tooltip=æ€çŽ¢ãããã©ã°ã€ã³
view_dynagroup_exprBuilder_expression=åŒ
view_dynagroup_exprBuilder_expressionType=åŒã®ã¿ã€ã
view_dynagroup_exprBuilder_expressionType_pluginConfig=ãã©ã°ã€ã³èšå®
@@ -1902,7 +1902,7 @@
view_dynagroup_exprBuilder_noResourceTypes=--ãªãœãŒã¹ã¿ã€ããªã--
view_dynagroup_exprBuilder_pluginLoadFailure=ãã©ã°ã€ã³ã®ãªã¹ãã®ååŸãã§ããŸãã
view_dynagroup_exprBuilder_propLoadFailure=ããããã£ã®ãªã¹ãã®ååŸãã§ããŸãã
view_dynagroup_exprBuilder_propertyName=ããããã£å
-view_dynagroup_exprBuilder_propertyName_tooltip=åãåããçšã®ããããã£åãããã¯ãªãœãŒã¹ã¿ã€ããšåæ§ã«åŒã¿ã€ãã«ãã£ãŠå®çŸ©ãããŸãã
+view_dynagroup_exprBuilder_propertyName_tooltip=ã¯ãšãªããããããã£ãŒã®ååãåŒã¿ã€ãããã³ãªãœãŒã¹ã¿ã€ãã«ãã£ãŠå®çŸ©ãããŸãã
view_dynagroup_exprBuilder_resTypeLoadFailure=ãã©ã°ã€ã³ [{0}]
ã®ãªãœãŒã¹ã¿ã€ãã®ãªã¹ãã®ååŸãã§ããŸãã
view_dynagroup_exprBuilder_resource=ãªãœãŒã¹
view_dynagroup_exprBuilder_resourceType=ãªãœãŒã¹ã¿ã€ã
@@ -1913,12 +1913,12 @@ view_dynagroup_exprBuilder_resource_greatGrandparent=æŸç¥ç¶æ¯
view_dynagroup_exprBuilder_resource_greatGreatGrandparent=æŸç¥ç¶æ¯ã®èŠª
view_dynagroup_exprBuilder_resource_parent=芪
view_dynagroup_exprBuilder_resource_resource=ãªãœãŒã¹
-view_dynagroup_exprBuilder_resource_tooltip=ãªãœãŒã¹ã®ã¬ãã«ãæã¿ã®ãã®ã«éžæããŠãã ãããäŸãã°ã"芪"ãéžæãããšã芪ãªãœãŒã¹ãåŒã®æ®ãã®éšåã«äžèŽãããããªãªãœãŒã¹ãçºèŠã§ããŸãã
+view_dynagroup_exprBuilder_resource_tooltip=åžæã®ãªãœãŒã¹ã¬ãã«ãéžæããŸããããšãã°ãã芪ããéžæãããšã芪ãªãœãŒã¹ãä»ã®åŒãšäžèŽãããªãœãŒã¹ãèŠã€ããŸãã
view_dynagroup_exprBuilder_savedExpression=ä¿åãããåŒ
view_dynagroup_exprBuilder_title=åŒãã«ããŒ
view_dynagroup_exprBuilder_unset=èšå®è§£é€
-view_dynagroup_exprBuilder_unset_tooltip=èšå®è§£é€ã¯ããŒã¿ããŒã¹å
ã®nullå€ãæã€å€ãã®ãã¹ãŠãçºèŠããŸããããã¯ããŒã¿ããŒã¹ã¹ãã¢ãšåãåããããŒã¿ã®çç±ã«ãã"\="ãªãã¬ãŒã¿ã䜿ãããšã¯å¯èœã§ã¯ãããŸããã
-view_dynagroup_exprBuilder_value_tooltip=åãåããåŒã®ããã®æååå€
+view_dynagroup_exprBuilder_unset_tooltip=èšå®è§£é€ãæå®ãããšãnull
ã§ããå€ããã¹ãŠèŠã€ããŸããããŒã¿ããŒã¹ãããŒã¿ãä¿åããã³ã¯ãšãªããæ¹æ³ã«ãããã\=ãæŒç®åã¯äœ¿çšã§ããŸããã
+view_dynagroup_exprBuilder_value_tooltip=ã¯ãšãªããåŒã®æååå€
view_dynagroup_expression=åŒ
view_dynagroup_expressionBuilderIconTooltip=åŒãã«ããŒ...
view_dynagroup_expressionSet=åŒã»ãã
@@ -1938,34 +1938,34 @@ view_dynagroup_recalculationInterval=åèšç®ã®éé (å)
view_dynagroup_recalculationInterval_error=å€ã¯æŽæ°ã§ãªããã°ãªããŸãã
# view_dynagroup_recalculationInterval = \u518D\u8A08\u7B97\u9593\u9694 (min)
view_dynagroup_recursive=ååž°
-view_dynagroup_saveAndRecalculate=ä¿å & åèšç®
+view_dynagroup_saveAndRecalculate=ä¿åãšåèšç®
view_dynagroup_saveFailure=ã°ã«ãŒãå®çŸ©å [{0}] ã®ä¿åã«å€±æããŸãã
view_dynagroup_saveSuccessful=ã°ã«ãŒãå®çŸ©å [{0}] ã®ä¿åã«æåããŸãã
-view_dynagroup_singleSaveFailure=ãšã©ãŒãçºçããŸãã -
äžã€äœæãããã¹ãã§ãããã代ããã« [{0}] åäœãããŸãã
+view_dynagroup_singleSaveFailure=ãšã©ãŒãçºçããŸãã - 1
ã€äœæãããã¯ãã [{0}] åäœæãããŸãã
view_dynagroup_template_customExpression=ã«ã¹ã¿ã åŒ...
view_dynagroup_template_downedResources=ãã¹ãŠã®ãªãœãŒã¹ãçŸåšããŠã³ããŠããŸã
view_dynagroup_template_jbossas4_clusters=JBossAS 4 - ã¯ã©ã¹ã¿
-view_dynagroup_template_jbossas4_earClusters=JBossAS 4 - ã¯ã©ã¹ã¿å EARs
+view_dynagroup_template_jbossas4_earClusters=JBossAS 4 - ã¯ã©ã¹ã¿å EAR
view_dynagroup_template_jbossas4_hostingApp=JBossAS 4 -
ãã¹ãã£ã³ã°ããŠãã"èªåã®"ã¢ããªã±ãŒã·ã§ã³ã®ãã¹ãŠ
view_dynagroup_template_jbossas4_nonsecured=JBossAS 4 - ã»ãã¥ã¢ã§ãªããã¹ãŠ
-view_dynagroup_template_jbossas4_uniqueVersions=JBossAS 4 - ãŠããŒã¯ããŒãžã§ã³
+view_dynagroup_template_jbossas4_uniqueVersions=JBossAS 4 - äžæã®ããŒãžã§ã³
view_dynagroup_template_jbossas5_clusters=JBossAS 5/6 - ã¯ã©ã¹ã¿
view_dynagroup_template_platforms=ã€ã³ãã³ããªå
ã®ãã©ãããã©ãŒã ãªãœãŒã¹
-view_dynagroup_template_uniqueResourceTypes=ã€ã³ãã³ããªå
ã®ãŠããŒã¯ãªãœãŒã¹ã¿ã€ã
+view_dynagroup_template_uniqueResourceTypes=ã€ã³ãã³ããªå
ã®äžæã®ãªãœãŒã¹ã¿ã€ã
view_groupConfigEdit_member=ã¡ã³ããŒ
view_groupConfigEdit_noListProps=ã°ã«ãŒãèšå®ã§çŸåšãµããŒããããŠããªãããããã£ã®ãªã¹ã
-view_groupConfigEdit_saveReminder=èšå®ãå€æŽãããŠããŸã -
ãããã®å€æŽãä¿åããã®ãå¿ããªãã§ãã ããããããªããšå€±ãããŸãã
-view_groupConfigEdit_setAll=ãã¹ãŠã®å€ãèšå®\:
-view_groupConfigEdit_tooltip_1=ã¡ã³ããŒå€ã®éã -
ç·šéããããã«ã¢ã€ã³ã³ãã¯ãªãã¯ããŸã
+view_groupConfigEdit_saveReminder=èšå®ã®äžéšãå€æŽãããŸãã -
å€æŽãä¿åããªããšå€æŽå
容ã倱ãããŸãã\n
+view_groupConfigEdit_setAll=ãã¹ãŠã®å€ã次ã«èšå®\:
+view_groupConfigEdit_tooltip_1=ã¡ã³ããŒå€ãç°ãªããŸã -
ã¢ã€ã³ã³ãã¯ãªãã¯ããŠç·šéããŠãã ããã
view_groupConfigEdit_unset=èšå®è§£é€
view_groupConfigEdit_valsDiff=ã¡ã³ããŒå€ã®éã
-view_groupConfigEdit_valsDiffForProp=ãããã㣠[{0}] ã®ããã®ã¡ã³ããŒå€
+view_groupConfigEdit_valsDiffForProp=ãããã㣠[{0}] ã®ã¡ã³ããŒå€
view_groupCreateWizard_createFailure=ãªãœãŒã¹ã°ã«ãŒã [{0}]
ã®äœæã«å€±æããŸãã \: {1}
view_groupCreateWizard_createStepName=ã°ã«ãŒãèšå®
view_groupCreateWizard_createStep_group_exists=[{0}]
ãšããååã®ã°ã«ãŒãã¯ãã§ã«ååšããŸã
view_groupCreateWizard_createStep_recursive=ååž°
view_groupCreateWizard_createSuccessful_concise=[{0}]
ãšããååã®æ°èŠã®ãªãœãŒã¹ã°ã«ãŒããäœæããŸããã
-view_groupCreateWizard_createSuccessful_full=[{2}] ã¡ã³ããŒãªãœãŒã¹ãå«ã
åå [{1}] ã®æ°èŠ [{0}] ãªãœãŒã¹ã°ã«ãŒããäœæããŸããã
+view_groupCreateWizard_createSuccessful_full=[{2}]
ã¡ã³ããŒãªãœãŒã¹ãå«ãŸããåå [{1}] ãæã€æ°ãã [{0}]
ãªãœãŒã¹ã°ã«ãŒããäœæãããŸããã
view_groupCreateWizard_membersStepName=ã¡ã³ããŒã®éžæ
view_groupCreateWizard_title=ã°ã«ãŒãäœæ
view_groupCreateWizard_windowTitle=ã°ã«ãŒãäœæ
@@ -1993,22 +1993,22 @@
view_group_operationScheduleDetails_memberResource=ã¡ã³ããŒãªãœãŒã¹
view_group_operationScheduleDetails_value_parallel=䞊è¡å®è¡
view_group_operationScheduleDetails_value_sequential=以äžã«ç€ºããé
(ã¡ã³ããŒãªãœãŒã¹ããã©ãã°ã¢ã³ãããããããŠé çªãå€æŽ)
view_group_pluginConfig_edit_currentGroupProperties=çŸåšã®ã°ã«ãŒãããããã£
-view_group_pluginConfig_edit_invalid=次ã®ã³ãã¯ã·ã§ã³èšå®ããããã£ã«ã¯äžæ£ãªå€ãèšå®ãããŠããŸãã®ã§ãã³ãã¯ã·ã§ã³èšå®ãä¿åããããŸãã«ä¿®æ£ãããå¿
èŠããããŸã\: [{0}]
-view_group_pluginConfig_edit_noperm=ãã®ã°ã«ãŒãã³ãã¯ã·ã§ã³èšå®ãç·šéããæš©éããããŸãã
+view_group_pluginConfig_edit_invalid=次ã®æ¥ç¶èšå®ããããã£ãŒã«ã¯ç¡å¹ãªå€ãå«ãŸããŠããŸããç¡å¹ãªå€ãä¿®æ£ããªããšãèšå®ãä¿åã§ããŸãã\:
[{0}]
+view_group_pluginConfig_edit_noperm=ãã®ã°ã«ãŒãæ¥ç¶èšå®ãç·šéããæš©éããããŸãã
view_group_pluginConfig_edit_saveFailure=ã°ã«ãŒãå [{1}] ãšäºææ§ã®ãã
[{0}] ã®ããã®ã°ã«ãŒãèšå®æŽæ°ã®éå§ã«å€±æããŸãã
-view_group_pluginConfig_edit_saveInitiated_concise=ã°ã«ãŒãã³ãã¯ã·ã§ã³èšå®ã®æŽæ°ãéå§ãããŸãã
-view_group_pluginConfig_edit_saveInitiated_full=ã°ã«ãŒãã³ãã¯ã·ã§ã³èšå®ã®æŽæ°ã¯ã°ã«ãŒãå
[{1}] ãšäºææ§ã®ãã [{0}] ã®ããã«éå§ãããŸãã
-view_group_pluginConfig_edit_saveTooltip=ãã¹ãŠã®ã°ã«ãŒãã¡ã³ããŒã®ã³ãã¯ã·ã§ã³èšå®ãæŽæ°ããŸã
-view_group_pluginConfig_edit_valid=ãã¹ãŠã®ã³ãã¯ã·ã§ã³èšå®ããããã£ã«ã¯æ£ããå€ãèšå®ãããŠããŸãã®ã§ãã³ãã¯ã·ã§ã³èšå®ã¯ä¿åã§ããŸã
+view_group_pluginConfig_edit_saveInitiated_concise=ã°ã«ãŒãæ¥ç¶èšå®ã®æŽæ°ãéå§ãããŸãã
+view_group_pluginConfig_edit_saveInitiated_full=ã°ã«ãŒãæ¥ç¶èšå®ã®æŽæ°ãã[{1}]
ãšããååã® [{0}]
ãšäºææ§ã®ããã°ã«ãŒãã«å¯ŸããŠéå§ãããŸãã
+view_group_pluginConfig_edit_saveTooltip=ãã¹ãŠã®ã°ã«ãŒãã¡ã³ããŒã®æ¥ç¶èšå®ãæŽæ°ããŸã
+view_group_pluginConfig_edit_valid=ãã¹ãŠã®æ¥ç¶èšå®ããããã£ãŒã®å€ãæå¹ã§ãããããèšå®ãä¿åã§ããŸã
view_group_pluginConfig_members_fetchFailure=ã°ã«ãŒã [{0}]
ã®ã¡ã³ããŒã®ãã©ã°ã€ã³èšå®æŽæ°å±¥æŽã®ååŸã«å€±æããŸãã
-view_group_pluginConfig_members_fetchFailureConn=[{0}]
ã®ããã®ã¡ã³ããŒã³ãã¯ã·ã§ã³èšå®ã®åãåºãã«å€±æããŸãã
+view_group_pluginConfig_members_fetchFailureConn=[{0}]
ã®ã¡ã³ããŒæ¥ç¶èšå®ã®èªã¿åºãã«å€±æããŸãã
view_group_pluginConfig_members_fetchFailureConnInProgress=ã°ã«ãŒããã©ã°ã€ã³èšå®ã®æŽæ°ã¯çŸåšé²è¡äžã§ããã°ã«ãŒãèšå®ãé²èŠ§ããã«ã¯ãæŽæ°ãçµäºãããŸã§åŸ
æ©ããå¿
èŠããããŸãã
view_group_pluginConfig_members_statusDetails=ã¹ããŒã¿ã¹ã®è©³çŽ°
view_group_pluginConfig_members_statusFailure=ãã®èšå®ã®æŽæ°ã¯æªç¥ã®çç±ã«ãã倱æããŸãã
view_group_pluginConfig_members_statusInprogress=ãã®èšå®ã®æŽæ°ã¯ãŸã é²è¡äžã§ã
view_group_pluginConfig_members_statusNochange=ãã®èšå®ã¯å€æŽãããŸããã§ãã
view_group_pluginConfig_members_statusSuccess=ãã®èšå®ã®æŽæ°ã¯æåããŸãã
-view_group_pluginConfig_members_title=ã°ã«ãŒãã³ãã¯ã·ã§ã³èšå®ã®ã¡ã³ããŒå±¥æŽ
+view_group_pluginConfig_members_title=ã°ã«ãŒãæ¥ç¶èšå®ã®ã¡ã³ããŒå±¥æŽ
view_group_pluginConfig_table_clickStatusIcon=詳现ã¯ã¹ããŒã¿ã¹ã¢ã€ã³ã³ãã¯ãªãã¯ããŠãã ãã
view_group_pluginConfig_table_deleteFailure=ã°ã«ãŒããã©ã°ã€ã³èšå®å±¥æŽã®åé€ã«å€±æããŸãã
view_group_pluginConfig_table_deleteSuccessful=[{0}] ã®å±¥æŽãåé€ããŸãã
@@ -2019,11 +2019,11 @@
view_group_pluginConfig_table_statusFailure=ãã®ã°ã«ãŒãèšå®ã®æŽæ°ã¯
view_group_pluginConfig_table_statusInprogress=ãã®ã°ã«ãŒãèšå®ã®æŽæ°ã¯é²è¡äžã§ã
view_group_pluginConfig_table_statusNochange=ãã®ã°ã«ãŒãèšå®ã¯å€æŽãããŸããã§ãã
view_group_pluginConfig_table_statusSuccess=ãã®ã°ã«ãŒãèšå®ã®æŽæ°ã¯æåããŸãã
-view_group_pluginConfig_table_title=ã°ã«ãŒãã³ãã¯ã·ã§ã³èšå®å±¥æŽ
+view_group_pluginConfig_table_title=ã°ã«ãŒãæ¥ç¶èšå®å±¥æŽ
view_group_pluginConfig_table_viewMemberHistory=ã¡ã³ããŒå±¥æŽã®é²èŠ§
view_group_pluginConfig_table_viewSettings=èšå®ã®é²èŠ§
view_group_pluginConfig_view_groupProperties=ã°ã«ãŒãããããã£
-view_group_pluginConfig_view_noperm=ã³ãã¯ã·ã§ã³èšå®ã®é²èŠ§æš©éããããŸãã
+view_group_pluginConfig_view_noperm=æ¥ç¶èšå®ã®é²èŠ§æš©éããããŸãã
view_group_resConfig_edit_invalid=次ã®èšå®ããããã£ãŒã«ã¯ç¡å¹ãªå€ãå«ãŸããŠããŸããç¡å¹ãªå€ãä¿®æ£ããªããšãèšå®ãä¿åã§ããŸãã\:
[{0}]
view_group_resConfig_edit_loadFail=[{0}]
ã®ã¡ã³ããŒãªãœãŒã¹èšå®ã®èªã¿åºãã«å€±æããŸãã
view_group_resConfig_edit_noperm=ãã®ã°ã«ãŒãèšå®ãç·šéããæš©éããããŸãã
@@ -2635,7 +2635,7 @@
widget_resourceFactoryWizard_infoStep_loadFail=ã¢ãŒããã¯ãã£ãŒãå©çš
widget_resourceFactoryWizard_nameComment=管çãã©ã°ã€ã³ãŸãã¯ãããã®ç®¡ç察象ãªãœãŒã¹ã®äžéšã¯ããšãŒãžã§ã³ãã«ããæ°ãããªãœãŒã¹ã®ååèšå®ãèš±å¯ããŸããããã®å€ã¯ããã®æ©èœããµããŒããããšãŒãžã§ã³ããã©ã°ã€ã³ã®ã¿ã䜿çšããŸãããã®æ©èœããµããŒãããªããã©ã°ã€ã³ã®å ŽåããªãœãŒã¹ãçºèŠããããšãã«ãªãœãŒã¹ã«æ±çšãŸãã¯ç°ãªãååãä»ããããå¯èœæ§ããããŸãã
widget_resourceFactoryWizard_namePrompt=æ°èŠãªãœãŒã¹å
# widget_resourceFactoryWizard_nameComment = Not all management plug-ins or their managed
resources allow the agent to set the name for a new resource. This value will only be used
by agent plug-ins that support the capability. For plug-ins that do not support the
capability, the resource may receive a generic or different name when it is discovered.
-widget_resourceFactoryWizard_templatePrompt=ã³ãã¯ã·ã§ã³èšå®ãã³ãã¬ãŒã
+widget_resourceFactoryWizard_templatePrompt=æ¥ç¶èšå®ãã³ãã¬ãŒã
widget_resourceFactoryWizard_timeoutFailure=ã¿ã€ã ã¢ãŠãããŸãã
widget_resourceFactoryWizard_timeoutHelp=æå®ãããå ŽåãåãªãœãŒã¹äœæ
({0} ãšãŒãžã§ã³ãäž)
ã®ããã©ã«ãã®ã¿ã€ã ã¢ãŠãå€ãäžæžãããã¿ã€ã ã¢ãŠãã®æéã§ããããã©ã«ãã®ã¿ã€ã ã¢ãŠãå€ã¯
60
ç§ã§ãã倧åã¢ããªã±ãŒã·ã§ã³ã®ãããã€ã¡ã³ããªã©ãç¹ã«é·ãäœæäœæ¥ã§ã¯å€ã倧ãããããšããã§ããããéåžžã以åã®äœæãã¿ã€ã ã¢ãŠãã«ãã£ãŠå€±æã«çµãã£ãå Žåã«äœ¿çšãããŸããã¿ã€ã ã¢ãŠãã«ãã£ãŠå€±æããå Žåã§ãããªãœãŒã¹ã®ãããã€ã¡ã³ãã¯æåããå¯èœæ§ããããã泚æããŠãã ãããã¿ã€ã ã¢ãŠããçºçããå ŽåããªãœãŒã¹ãåãããã€ããåã«ãã£ã¹ã«ããªã¹ãã£ã³ãå®è¡ãããšããã§ãããã
# ##widget_resourceFactoryWizard_timeoutFailure = Timed out
commit 0d73a65bd3f55aadf877ee5bcdfa530b8fde2dd1
Author: Thomas Segismont <tsegismo(a)redhat.com>
Date: Tue Dec 10 13:42:16 2013 +0100
AS7 plugin minor changes: share base component logger and ASConnection verbose mode
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
index a6043c4..2451743 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
@@ -18,6 +18,8 @@
*/
package org.rhq.modules.plugins.jbossas7;
+import static org.rhq.modules.plugins.jbossas7.ASConnection.verbose;
+
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
@@ -82,6 +84,8 @@ import org.rhq.modules.plugins.jbossas7.json.Result;
public class BaseComponent<T extends ResourceComponent<?>> implements
AS7Component<T>, MeasurementFacet,
ConfigurationFacet, DeleteResourceFacet, CreateChildResourceFacet, OperationFacet {
+ private static final Log LOG = LogFactory.getLog(BaseComponent.class);
+
static final String INTERNAL = "_internal:";
static final int INTERNAL_SIZE = INTERNAL.length();
static final String EXPRESSION = "_expr:";
@@ -90,7 +94,11 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
public static final String MANAGED_SERVER = "Managed Server";
- final Log log = LogFactory.getLog(this.getClass());
+ /**
+ * @deprecated as of 4.10. Use your own logger or {@link #getLog()} method.
+ */
+ @Deprecated
+ final Log log = LOG;
ResourceContext<T> context;
Configuration pluginConfiguration;
@@ -101,7 +109,6 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
String key;
boolean includeRuntime;
- private boolean verbose = ASConnection.verbose;
private BaseServerComponent serverComponent;
protected ASConnection testConnection;
@@ -192,7 +199,7 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
Result res = getASConnection().execute(op);
if (!res.isSuccess()) {
- log.warn("Getting metric [" + req.getName() + "] at [
" + address + "] failed: "
+ getLog().warn("Getting metric [" + req.getName() + "]
at [ " + address + "] failed: "
+ res.getFailureDescription());
continue;
}
@@ -217,7 +224,7 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
addMetric2Report(report, req, val, resolveExpression);
}
} catch (NumberFormatException e) {
- log.warn("Non numeric input for [" + req.getName() +
"] : [" + val + "]");
+ getLog().warn("Non numeric input for [" + req.getName()
+ "] : [" + val + "]");
}
} else if (req.getDataType() == DataType.TRAIT) {
@@ -226,8 +233,8 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
ResolveExpression resolveExpressionOperation = new
ResolveExpression(expression);
Result result =
getASConnection().execute(resolveExpressionOperation);
if (!result.isSuccess()) {
- if (log.isWarnEnabled()) {
- log.warn("Skipping trait [" + req.getName()
+ if (getLog().isWarnEnabled()) {
+ getLog().warn("Skipping trait [" +
req.getName()
+ "] in measurement report. Could not resolve
expression [" + expression
+ "], failureDescription:" +
result.getFailureDescription());
continue;
@@ -250,8 +257,8 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
ResolveExpression resolveExpressionOperation = new
ResolveExpression(expression);
Result result = getASConnection().execute(resolveExpressionOperation);
if (!result.isSuccess()) {
- if (log.isWarnEnabled()) {
- log.warn("Skipping metric [" + req.getName()
+ if (getLog().isWarnEnabled()) {
+ getLog().warn("Skipping metric [" + req.getName()
+ "] in measurement report. Could not resolve expression
[" + expression
+ "], failureDescription:" +
result.getFailureDescription());
return;
@@ -354,7 +361,7 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
@Override
public void deleteResource() throws Exception {
- log.info("Removing AS7 resource [" + path + "]...");
+ getLog().info("Removing AS7 resource [" + path + "]...");
if (context.getResourceType().getName().equals(MANAGED_SERVER)) {
// We need to do two steps because of AS7-4032
@@ -461,7 +468,7 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
JsonNode uploadResult = uploadConnection.finishUpload();
if (verbose) {
- log.info(uploadResult);
+ getLog().info(uploadResult);
}
if (ASUploadConnection.isErrorReply(uploadResult)) {
@@ -496,7 +503,7 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
String deploymentName, String hash) {
boolean toServerGroup =
context.getResourceKey().contains("server-group=");
- log.info("Deploying [" + runtimeName + "] (toDomainOnly=" +
!toServerGroup + ")...");
+ getLog().info("Deploying [" + runtimeName + "]
(toDomainOnly=" + !toServerGroup + ")...");
ASConnection connection = getASConnection();
@@ -546,7 +553,7 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
resourceKey = serverGroupAddress.getPath();
if (verbose) {
- log.info("Deploy operation: " + cop);
+ getLog().info("Deploy operation: " + cop);
}
result = connection.execute(cop, 300);
@@ -556,14 +563,14 @@ public class BaseComponent<T extends
ResourceComponent<?>> implements AS7Compone
String failureDescription = result.getFailureDescription();
report.setErrorMessage(failureDescription);
report.setStatus(CreateResourceStatus.FAILURE);
- log.warn("Deploy of [" + runtimeName + "] failed: " +
failureDescription);
+ getLog().warn("Deploy of [" + runtimeName + "] failed: "
+ failureDescription);
} else {
report.setStatus(CreateResourceStatus.SUCCESS);
report.setResourceName(runtimeName);
report.setResourceKey(resourceKey);
report.getPackageDetails().setSHA256(hash);
report.getPackageDetails().setInstallationTimestamp(System.currentTimeMillis());
- log.info("Deploy of [" + runtimeName + "] succeeded - Resource
key is [" + resourceKey + "].");
+ getLog().info("Deploy of [" + runtimeName + "] succeeded -
Resource key is [" + resourceKey + "].");
}
return report;
@@ -656,7 +663,7 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
}
operation.addAdditionalProperty(pl.getName(), items);
} else {
- log.error("PropertyMap for " + prop.getName() + " not
yet supported");
+ getLog().error("PropertyMap for " + prop.getName() + "
not yet supported");
}
}
}
@@ -698,7 +705,7 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
PropertyDefinitionSimple pds = (PropertyDefinitionSimple) pd;
return getObjectForProperty(prop, pds);
} else {
- log.warn("Property [" + prop.getName() + "] is not understood
yet");
+ getLog().warn("Property [" + prop.getName() + "] is not
understood yet");
return null;
}
}
@@ -866,7 +873,7 @@ public class BaseComponent<T extends ResourceComponent<?>>
implements AS7Compone
if (defaultValue != null) {
multicastHost = defaultValue;
} else {
- log.error("Failed to resolve expression value
[" + expressionValue
+ getLog().error("Failed to resolve expression
value [" + expressionValue
+ "] of 'multicast-address'
attribute.");
}
}
@@ -912,4 +919,12 @@ public class BaseComponent<T extends
ResourceComponent<?>> implements AS7Compone
}
}
+ /**
+ * Get the logger for AS7 plugin resource components.
+ *
+ * @return
+ */
+ public static Log getLog() {
+ return LOG;
+ }
}
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
index 9a15a85..94c101f 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
@@ -1,5 +1,26 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
package org.rhq.modules.plugins.jbossas7;
+import static org.rhq.modules.plugins.jbossas7.ASConnection.verbose;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -29,7 +50,6 @@ import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.content.ContentFacet;
import org.rhq.core.pluginapi.content.ContentServices;
import org.rhq.core.pluginapi.content.FileContentDelegate;
-import org.rhq.core.pluginapi.inventory.CreateResourceReport;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceComponent;
import org.rhq.core.pluginapi.inventory.ResourceContext;
@@ -52,8 +72,8 @@ import org.rhq.modules.plugins.jbossas7.json.Result;
*/
public class DeploymentComponent extends BaseComponent<ResourceComponent<?>>
implements OperationFacet, ContentFacet {
+
private static final String DOMAIN_DATA_CONTENT_SUBDIR = "/data/content";
- private boolean verbose = ASConnection.verbose;
private File deploymentFile;
@Override
@@ -123,13 +143,13 @@ public class DeploymentComponent extends
BaseComponent<ResourceComponent<?>> imp
@Override
public DeployPackagesResponse deployPackages(Set<ResourcePackageDetails>
packages, ContentServices contentServices) {
- log.debug("Starting deployment..");
+ getLog().debug("Starting deployment..");
DeployPackagesResponse response = new DeployPackagesResponse();
if (packages.size() != 1) {
response.setOverallRequestResult(ContentResponseResult.FAILURE);
response.setOverallRequestErrorMessage("Can only deploy one package at a
time");
- log.warn("deployPackages can only deploy one package at a time");
+ getLog().warn("deployPackages can only deploy one package at a
time");
}
ResourcePackageDetails detail = packages.iterator().next();
@@ -145,7 +165,7 @@ public class DeploymentComponent extends
BaseComponent<ResourceComponent<?>> imp
}
ResourceType resourceType = context.getResourceType();
- log.info("Deploying " + resourceType.getName() + " Resource with
key [" + detail.getKey() + "]...");
+ getLog().info("Deploying " + resourceType.getName() + " Resource
with key [" + detail.getKey() + "]...");
try {
contentServices.downloadPackageBits(context.getContentContext(),
detail.getKey(), out, true);
@@ -158,7 +178,7 @@ public class DeploymentComponent extends
BaseComponent<ResourceComponent<?>> imp
JsonNode uploadResult = uploadConnection.finishUpload();
if (verbose) {
- log.info(uploadResult);
+ getLog().info(uploadResult);
}
if (ASUploadConnection.isErrorReply(uploadResult)) {
@@ -183,7 +203,7 @@ public class DeploymentComponent extends
BaseComponent<ResourceComponent<?>> imp
response.setOverallRequestResult(ContentResponseResult.FAILURE);
}
- log.info("Result of deployment of " + resourceType.getName() + "
Resource with key [" + detail.getKey() + "]: "
+ getLog().info("Result of deployment of " + resourceType.getName() +
" Resource with key [" + detail.getKey() + "]: "
+ response);
return response;
@@ -288,7 +308,7 @@ public class DeploymentComponent extends
BaseComponent<ResourceComponent<?>> imp
return deploymentFile;
}
} else {
- log.warn("Could not determine the location of the deployment - the
content descriptor wasn't found for deployment"
+ getLog().warn("Could not determine the location of the deployment -
the content descriptor wasn't found for deployment"
+ getAddress() + ".");
return null;
}
@@ -296,7 +316,7 @@ public class DeploymentComponent extends
BaseComponent<ResourceComponent<?>> imp
Boolean archive = (Boolean) content.get(0).get("archive");
if (archive != null && !archive) {
- log.debug("Exploded deployments not supported for retrieving the
content.");
+ getLog().debug("Exploded deployments not supported for retrieving the
content.");
return null;
}
@@ -338,7 +358,7 @@ public class DeploymentComponent extends
BaseComponent<ResourceComponent<?>> imp
}
deploymentFile = getDeploymentFileFromHash(hash, contentPath);
} else {
- log.warn("Failed to determine the deployment file of " +
getAddress()
+ getLog().warn("Failed to determine the deployment file of " +
getAddress()
+ " deployment. Neither path nor hash attributes were
available.");
}
@@ -362,7 +382,7 @@ public class DeploymentComponent extends
BaseComponent<ResourceComponent<?>> imp
return new File(relativeTo, path);
} else {
- log.warn("Unsupported property used as a base for deployment path
specification: " + relativeTo);
+ getLog().warn("Unsupported property used as a base for deployment
path specification: " + relativeTo);
return null;
}
}
@@ -394,8 +414,8 @@ public class DeploymentComponent extends
BaseComponent<ResourceComponent<?>> imp
FileContentDelegate fileContentDelegate = new FileContentDelegate();
sha256 = fileContentDelegate.retrieveDeploymentSHA(file,
context.getResourceDataDirectory());
} catch (Exception iex) {
- if (log.isDebugEnabled()) {
- log.debug("Problem calculating digest of package [" +
file.getPath() + "]." + iex.getMessage());
+ if (getLog().isDebugEnabled()) {
+ getLog().debug("Problem calculating digest of package [" +
file.getPath() + "]." + iex.getMessage());
}
}
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DomainDeploymentComponent.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DomainDeploymentComponent.java
index 54cffbf..532d403 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DomainDeploymentComponent.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DomainDeploymentComponent.java
@@ -1,3 +1,22 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
package org.rhq.modules.plugins.jbossas7;
import java.util.ArrayList;
@@ -49,7 +68,7 @@ public class DomainDeploymentComponent extends DeploymentComponent
implements Op
String resourceKey = context.getResourceKey();
resourceKey = resourceKey.substring(resourceKey.indexOf("=") + 1);
- log.info("Promoting [" + resourceKey + "] to server group(s)
[" + serverGroups + "]...");
+ getLog().info("Promoting [" + resourceKey + "] to server
group(s) [" + serverGroups + "]...");
PropertySimple simple = parameters.getSimple("enabled");
Boolean enabled = false;
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Ejb3BeanRuntimeComponent.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Ejb3BeanRuntimeComponent.java
index 7f7bf33..4f8d88a 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Ejb3BeanRuntimeComponent.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Ejb3BeanRuntimeComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2013 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,8 +13,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.modules.plugins.jbossas7;
@@ -163,12 +163,13 @@ public class Ejb3BeanRuntimeComponent extends
BaseComponent<BaseComponent<?>> {
} else {
OSGiVersion currentAsVersion = getASVersion();
if (currentAsVersion == null) {
- log.warn("Could not determine the AS version while reporting
unexpected result of method" +
- " stats. Request: " + request);
+ getLog().warn(
+ "Could not determine the AS version while reporting
unexpected result of method"
+ + " stats. Request: " + request);
} else if
(FIRST_VERSION_SUPPORTING_METHOD_STATS.compareTo(currentAsVersion) <= 0) {
- log.error("Unexpected type of results when querying method
stats for measurement request " +
- request + ". Expected map but got " + (value ==
null ? "null" :
- value.getClass().getName()));
+ getLog().error(
+ "Unexpected type of results when querying method stats
for measurement request " + request
+ + ". Expected map but got " + (value == null ?
"null" : value.getClass().getName()));
}
}
}
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java
index 5c02170..c70fd3d 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java
@@ -57,10 +57,8 @@ public class ManagedASComponent extends
BaseComponent<HostControllerComponent<?>
public void start(ResourceContext<HostControllerComponent<?>>
hostControllerComponentResourceContext)
throws InvalidPluginConfigurationException, Exception {
super.start(hostControllerComponentResourceContext);
-
logFileEventDelegate = new LogFileEventResourceComponentHelper(context);
logFileEventDelegate.startLogFileEventPollers();
-
}
@Override
@@ -87,7 +85,7 @@ public class ManagedASComponent extends
BaseComponent<HostControllerComponent<?>
try {
result = getASConnection().execute(getStatus);
} catch (Exception e) {
- log.warn(e.getMessage());
+ getLog().warn(e.getMessage());
return AvailabilityType.DOWN;
}
if (!result.isSuccess())
@@ -149,18 +147,21 @@ public class ManagedASComponent extends
BaseComponent<HostControllerComponent<?>
}
if ("null".equals(val)) {
- if (realName.equals("product-name"))
+ if (realName.equals("product-name")) {
val = "JBoss AS";
- else if (realName.equals("product-version"))
+ }
+ else if (realName.equals("product-version")) {
val =
getStringValue(props.get("release-version"));
- else
- log.debug("Value for " + realName + " was
'null' and no replacement found");
+ }
+ else if (getLog().isDebugEnabled()) {
+ getLog().debug("Value for " + realName + " was
'null' and no replacement found");
+ }
}
MeasurementDataTrait data = new MeasurementDataTrait(request, val);
report.addData(data);
}
- } else {
- log.debug("getSKMRequests failed: " +
res.getFailureDescription());
+ } else if (getLog().isDebugEnabled()) {
+ getLog().debug("getSKMRequests failed: " +
res.getFailureDescription());
}
}
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterConfigurationDiscovery.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterConfigurationDiscovery.java
index d8f3ea1..b58dfd4 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterConfigurationDiscovery.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterConfigurationDiscovery.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,14 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.modules.plugins.jbossas7;
+import static org.rhq.modules.plugins.jbossas7.ASConnection.verbose;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -109,7 +112,7 @@ public class ModClusterConfigurationDiscovery extends
SubsystemDiscovery {
}
}
- if (Boolean.getBoolean("as7plugin.verbose"))
+ if (verbose)
log.info("total path: [" + path + "]");
if (lookForChildren) {
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterContextComponent.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterContextComponent.java
index 836b6a7..d22aa32 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterContextComponent.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ModClusterContextComponent.java
@@ -1,3 +1,22 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2013 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
package org.rhq.modules.plugins.jbossas7;
import org.rhq.core.domain.configuration.Configuration;
@@ -27,7 +46,7 @@ public class ModClusterContextComponent extends ModClusterComponent
implements A
int indexOfSeparator = this.context.getResourceKey().indexOf(":");
context =
ProxyInfo.Context.fromString(this.context.getResourceKey().substring(indexOfSeparator +
1));
} catch (Exception e) {
- log.warn("Invalid resourcekey is being used for modcluster component:
" + e.getMessage());
+ getLog().warn("Invalid resourcekey is being used for modcluster
component: " + e.getMessage());
return AvailabilityType.DOWN;
}
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/SubsystemDiscovery.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/SubsystemDiscovery.java
index e8f8301..8b68f46 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/SubsystemDiscovery.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/SubsystemDiscovery.java
@@ -19,6 +19,8 @@
package org.rhq.modules.plugins.jbossas7;
+import static org.rhq.modules.plugins.jbossas7.ASConnection.verbose;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -112,7 +114,7 @@ public class SubsystemDiscovery implements
ResourceDiscoveryComponent<BaseCompon
}
}
- if (Boolean.getBoolean("as7plugin.verbose")) {
+ if (verbose) {
log.info("total path: [" + path + "]");
}
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/VHostComponent.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/VHostComponent.java
index 342bcba..4f67159 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/VHostComponent.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/VHostComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,8 +13,8 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.modules.plugins.jbossas7;
@@ -56,7 +56,7 @@ public class VHostComponent extends BaseComponent<VHostComponent>
implements Mea
}
report.addData(data);
} else
- log.warn("Could not get aliases for " + getAddress() +
": " + res.getFailureDescription());
+ getLog().warn("Could not get aliases for " + getAddress() +
": " + res.getFailureDescription());
} else {
leftovers.add(request);
}
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/WebRuntimeComponent.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/WebRuntimeComponent.java
index 072f4d7..9573cfb 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/WebRuntimeComponent.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/WebRuntimeComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -13,9 +13,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
+
package org.rhq.modules.plugins.jbossas7;
import java.io.File;
@@ -56,12 +57,12 @@ public class WebRuntimeComponent extends
BaseComponent<BaseComponent<?>> {
}
if (logFile != null) {
- if (log.isDebugEnabled()) {
+ if (getLog().isDebugEnabled()) {
if (logFile.isFile()) {
- log.debug("[" + resourceContext.getResourceKey() + "]
is using the response time log file ["
+ getLog().debug("[" + resourceContext.getResourceKey() +
"] is using the response time log file ["
+ logFile + "]");
} else {
- log.debug("The response time log file [" + logFile +
"] for ["
+ getLog().debug("The response time log file [" + logFile +
"] for ["
+ resourceContext.getResourceKey() + "] does not exist
yet.");
}
}
@@ -70,8 +71,8 @@ public class WebRuntimeComponent extends
BaseComponent<BaseComponent<?>> {
this.responseTimeLogParser.setExcludes(responseTimeConfig.getExcludes());
this.responseTimeLogParser.setTransforms(responseTimeConfig.getTransforms());
} else {
- if (log.isDebugEnabled()) {
- log.debug("Cannot monitor response time for [" +
resourceContext.getResourceKey()
+ if (getLog().isDebugEnabled()) {
+ getLog().debug("Cannot monitor response time for [" +
resourceContext.getResourceKey()
+ "] - unknown log file location");
}
}
@@ -96,12 +97,12 @@ public class WebRuntimeComponent extends
BaseComponent<BaseComponent<?>> {
this.responseTimeLogParser.parseLog(callTimeData);
report.addData(callTimeData);
} catch (Exception e) {
- log.error("Failed to retrieve call-time metric '" +
RESPONSE_TIME_METRIC + "' for "
+ getLog().error("Failed to retrieve call-time metric
'" + RESPONSE_TIME_METRIC + "' for "
+ context.getResourceType() + " Resource with key
[" + context.getResourceKey() + "].",
e);
}
} else {
- log.error("The '" + RESPONSE_TIME_METRIC + "'
metric is enabled for " + context.getResourceType()
+ getLog().error("The '" + RESPONSE_TIME_METRIC +
"' metric is enabled for " + context.getResourceType()
+ " Resource with key [" + context.getResourceKey()
+ "], but no value is defined for the '"
+
ResponseTimeConfiguration.RESPONSE_TIME_LOG_FILE_CONFIG_PROP + "' connection
property.");
// TODO: Communicate this error back to the server for display in the
GUI.
@@ -147,13 +148,13 @@ public class WebRuntimeComponent extends
BaseComponent<BaseComponent<?>> {
String logFileName = String.format("rt/%s%s_rt.log",
virtualHost, contextRoot);
logFile = new File(logDir, logFileName);
} else {
- if (log.isDebugEnabled()) {
- log.debug("Unknown context root for: " +
getAddress());
+ if (getLog().isDebugEnabled()) {
+ getLog().debug("Unknown context root for: " +
getAddress());
}
}
} else {
- if (log.isDebugEnabled()) {
- log.debug("Unknown virtual host for: " +
getAddress());
+ if (getLog().isDebugEnabled()) {
+ getLog().debug("Unknown virtual host for: " +
getAddress());
}
}
} catch (Exception e) {
commit acc51182c7b2aedb4112a2257ea4acede50dbddd
Author: John Sanda <jsanda(a)redhat.com>
Date: Mon Dec 9 22:02:45 2013 -0500
fixing bugs in foreach with criteria query
diff --git a/modules/enterprise/remoting/cli/src/main/samples/modules/util.js
b/modules/enterprise/remoting/cli/src/main/samples/modules/util.js
index 18c34b3..7de3db0 100644
--- a/modules/enterprise/remoting/cli/src/main/samples/modules/util.js
+++ b/modules/enterprise/remoting/cli/src/main/samples/modules/util.js
@@ -57,7 +57,7 @@ exports.foreach = function (obj, fn) {
MeasurementDefinition: function(criteria) { return
MeasurementDefinitionManager.findMeasurementDefinitionsByCriteria(criteria); },
JPADriftChangeSet: function(criteria) { return
DriftManager.findDriftChangeSetsByCriteria(criteria); },
JPADrift: function(criteria) { return DriftManager.findDriftsByCriteria(criteria);
},
- MeasurementSchedule: function(criteria) { return
MeasurementScheduleManager,findSchedulesByCriteria(criteria); },
+ MeasurementSchedule: function(criteria) { return
MeasurementScheduleManager.findSchedulesByCriteria(criteria); },
OperationDefinition: function(criteria) { return
OperationManager.findOperationDefinitionsByCriteria(criteria); },
ResourceOperationHistory: function(criteria) { return
OperationManager.findResourceOperationHistoriesByCriteria(criteria); },
ResourceType: function(criteria) { return
ResourceTypeManager.findResourceTypesByCriteria(criteria); },
@@ -79,24 +79,24 @@ exports.foreach = function (obj, fn) {
fn(iterator.next());
}
} else if (obj instanceof java.util.Map) {
- var iterator = obj.entrySet().iterator()
+ var iterator = obj.entrySet().iterator();
while (iterator.hasNext()) {
var entry = iterator.next();
fn(entry.key, entry.value);
}
} else if (obj instanceof Criteria) {
var criteria = obj;
- var executeQuery = criteriaExecutors[criteria.persistentClass];
+ var executeQuery = criteriaExecutors[criteria.persistentClass.simpleName];
if (executeQuery == null) {
throw "No criteria executor found for " + criteria.getClass().name +
". A new executor may need to be added to " +
"this script.";
}
- var currentPage = executeQuery();
+ var currentPage = executeQuery(criteria);
while (!currentPage.isEmpty()) {
- util.foreach(currentPage, fn);
+ this.foreach(currentPage, fn);
if (currentPage.pageControl == null && currentPage.pageControlOverrides ==
null) {
reachedEnd = true;
} else {
@@ -107,7 +107,7 @@ exports.foreach = function (obj, fn) {
}
currentPage.clear();
- currentPage = executeQuery();
+ currentPage = executeQuery(criteria);
}
}
} else { // assume we have a generic object
@@ -349,22 +349,4 @@ exports.asHash = function(configuration) {
})(configuration);
return ret;
-}
-
-exports.walkTree = function(root, visitorFn, nodesProperty, filterFn) {
- var nodes = root[nodesProperty];
- var stack = [];
- var pushChildNodesOntoStack = function(node) {
- exports.foreach(node[nodesProperty], function(childNode) {
- stack.push(childNode);
- });
- }
-
- pushChildNodesOntoStack(root);
-
- while (stack.length > 0) {
- var node = stack.pop();
- pushChildNodesOntoStack(node);
-
- }
}
\ No newline at end of file
commit ec2ad0ca872b6b377a8742bf1a9fabc4732598d8
Author: Simeon Pinder <spinder(a)fulliautomatix.conchfritter.com>
Date: Mon Dec 9 17:17:43 2013 -0500
BZ 1039664 - one more udpate to logged warning to refer to documentation.
diff --git
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
index 8f6d0b0..24e4995 100644
---
a/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
+++
b/modules/enterprise/server/server-control/src/main/java/org/rhq/server/control/RHQControl.java
@@ -140,7 +140,8 @@ public class RHQControl {
// but there are no other rpms other than the agent, so if we see
this jboss-on-* location, we know the agent is here.
log.warn("An agent RPM installation was found in ["
+ jonDir
- + "]!!! You will not be able to successfully run this older
agent anymore. You should manually remove it.");
+ + "]!!! You will not be able to successfully run this older
agent anymore. You should consult the "
+ +"install documentation about manually removing and/or
merging the old and new agent.");
return true;
} else {
return false;
commit b5acf065cbc30514263f30c29c35f8eb696e8407
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Mon Dec 9 15:37:43 2013 -0500
BZ 1037855 - related to the fix for BZ 971556 - the last commit for this BZ caused the
api check to fail.
putting back the obsolete, but public, constants and marking them as deprecated.
diff --git
a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerPluginConfigurationProperties.java
b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerPluginConfigurationProperties.java
index 7c30135..c2a1ba1 100644
---
a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerPluginConfigurationProperties.java
+++
b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/ApplicationServerPluginConfigurationProperties.java
@@ -45,6 +45,8 @@ public class ApplicationServerPluginConfigurationProperties {
public static final String SHUTDOWN_MBEAN_OPERATION_CONFIG_PROP =
"shutdownMBeanOperation";
public static final String SHUTDOWN_METHOD_CONFIG_PROP = "shutdownMethod";
public static final String SCRIPT_PREFIX_CONFIG_PROP = "scriptPrefix";
+ @Deprecated
+ public static final String AVAIL_CHECK_PERIOD_CONFIG_PROP =
"availabilityCheckPeriod";
private ApplicationServerPluginConfigurationProperties() {
}
diff --git
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/helper/ServerPluginConfiguration.java
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/helper/ServerPluginConfiguration.java
index 4695e61..d4c7e48 100644
---
a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/helper/ServerPluginConfiguration.java
+++
b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/helper/ServerPluginConfiguration.java
@@ -44,6 +44,8 @@ public class ServerPluginConfiguration {
public static final String LOG_DIR = "logDir";
public static final String PRODUCT_TYPE = "productType";
public static final String HOST_CONFIG_FILE = "hostConfigFile";
+ @Deprecated
+ public static final String AVAIL_CHECK_PERIOD_CONFIG_PROP =
"availabilityCheckPeriod";
}
private Configuration pluginConfig;
@@ -144,4 +146,13 @@ public class ServerPluginConfiguration {
hostConfigFile.toString() : null);
}
+ @Deprecated
+ public Integer getAvailabilityCheckPeriod() {
+ return 0;
+ }
+
+ @Deprecated
+ public void setAvailabilityCheckPeriod(Integer availabilityCheckPeriod) {
+ }
+
}
diff --git
a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java
b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java
index 873caaa..01c795f 100644
---
a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java
+++
b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java
@@ -139,6 +139,8 @@ public class JBossASServerComponent<T extends
ResourceComponent<?>> implements M
public static final String SHUTDOWN_MBEAN_OPERATION_CONFIG_PROP =
"shutdownMbeanOperation";
public static final String SHUTDOWN_METHOD_CONFIG_PROP = "shutdownMethod";
public static final String JAVA_HOME_PATH_CONFIG_PROP = "javaHomePath";
+ @Deprecated
+ public static final String AVAIL_CHECK_PERIOD_CONFIG_PROP =
"availabilityCheckPeriod";
public static final String BINDING_ADDRESS_CONFIG_PROP = "bindingAddress";