diff --git a/pom.xml b/pom.xml index 7aaa180ada2ba..8b30cf9642467 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT pom presto-root diff --git a/presto-accumulo/pom.xml b/presto-accumulo/pom.xml index 2b47a8b9b5718..28e526b6e4acd 100644 --- a/presto-accumulo/pom.xml +++ b/presto-accumulo/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-accumulo diff --git a/presto-atop/pom.xml b/presto-atop/pom.xml index 9c6595d14381d..e3aaca532eccd 100644 --- a/presto-atop/pom.xml +++ b/presto-atop/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-atop diff --git a/presto-base-jdbc/pom.xml b/presto-base-jdbc/pom.xml index 80d262f4a8814..610d0cb691599 100644 --- a/presto-base-jdbc/pom.xml +++ b/presto-base-jdbc/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-base-jdbc diff --git a/presto-benchmark-driver/pom.xml b/presto-benchmark-driver/pom.xml index ccb6e42a4f86a..81985736175d0 100644 --- a/presto-benchmark-driver/pom.xml +++ b/presto-benchmark-driver/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-benchmark-driver diff --git a/presto-benchmark-runner/pom.xml b/presto-benchmark-runner/pom.xml index 6a0b361e12a16..49a74f69519f8 100644 --- a/presto-benchmark-runner/pom.xml +++ b/presto-benchmark-runner/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-benchmark-runner diff --git a/presto-benchmark/pom.xml b/presto-benchmark/pom.xml index d7520ed4af030..d5ffc7d6b2e72 100644 --- a/presto-benchmark/pom.xml +++ b/presto-benchmark/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-benchmark diff --git a/presto-benchto-benchmarks/pom.xml b/presto-benchto-benchmarks/pom.xml index 91bab20b3a1b4..df95919a2df0f 100644 --- a/presto-benchto-benchmarks/pom.xml +++ b/presto-benchto-benchmarks/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-benchto-benchmarks diff --git a/presto-bigquery/pom.xml b/presto-bigquery/pom.xml index b6e7fbec21143..1addc689af808 100644 --- a/presto-bigquery/pom.xml +++ b/presto-bigquery/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-bigquery diff --git a/presto-blackhole/pom.xml b/presto-blackhole/pom.xml index 3308c0d0c9ed2..c355a94689039 100644 --- a/presto-blackhole/pom.xml +++ b/presto-blackhole/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-blackhole diff --git a/presto-bytecode/pom.xml b/presto-bytecode/pom.xml index 6001b3151fd20..5463d6bd24c03 100644 --- a/presto-bytecode/pom.xml +++ b/presto-bytecode/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-bytecode diff --git a/presto-cache/pom.xml b/presto-cache/pom.xml index 461783210ec2e..28f261c2e29c1 100644 --- a/presto-cache/pom.xml +++ b/presto-cache/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-cache diff --git a/presto-cassandra/pom.xml b/presto-cassandra/pom.xml index be90b5342c93b..8953b9dbb6d99 100644 --- a/presto-cassandra/pom.xml +++ b/presto-cassandra/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-cassandra diff --git a/presto-cli/pom.xml b/presto-cli/pom.xml index 4ec7ddaa88e47..5e79b4aba0ddb 100644 --- a/presto-cli/pom.xml +++ b/presto-cli/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-cli diff --git a/presto-client/pom.xml b/presto-client/pom.xml index 6f6cc5690df02..07e8ca839dfdf 100644 --- a/presto-client/pom.xml +++ b/presto-client/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-client diff --git a/presto-cluster-ttl-providers/pom.xml b/presto-cluster-ttl-providers/pom.xml index fa14c6bda44d7..2e0e201195bf3 100644 --- a/presto-cluster-ttl-providers/pom.xml +++ b/presto-cluster-ttl-providers/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-common/pom.xml b/presto-common/pom.xml index 17b90a6fa3b3f..28e05e1224555 100644 --- a/presto-common/pom.xml +++ b/presto-common/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-common diff --git a/presto-common/src/main/java/com/facebook/presto/common/block/BlockBuilderStatus.java b/presto-common/src/main/java/com/facebook/presto/common/block/BlockBuilderStatus.java index 1ee5f570a6912..83f4fb8afe2ec 100644 --- a/presto-common/src/main/java/com/facebook/presto/common/block/BlockBuilderStatus.java +++ b/presto-common/src/main/java/com/facebook/presto/common/block/BlockBuilderStatus.java @@ -74,7 +74,8 @@ private static int deepInstanceSize(Class clazz) int size = ClassLayout.parseClass(clazz).instanceSize(); for (Field field : clazz.getDeclaredFields()) { - if (!field.getType().isPrimitive()) { + // The !field.isSynthetic() condition is specifically for jacoco which adds synthetic members $jacocoData and $jacocoInit() to classes. + if (!field.getType().isPrimitive() && !field.isSynthetic()) { size += deepInstanceSize(field.getType()); } } diff --git a/presto-delta/pom.xml b/presto-delta/pom.xml index 85781efa277a5..157b13a4c8a23 100644 --- a/presto-delta/pom.xml +++ b/presto-delta/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-delta diff --git a/presto-delta/src/main/java/com/facebook/presto/delta/DeltaPageSourceProvider.java b/presto-delta/src/main/java/com/facebook/presto/delta/DeltaPageSourceProvider.java index 91b90f508b402..b5105a1e802af 100644 --- a/presto-delta/src/main/java/com/facebook/presto/delta/DeltaPageSourceProvider.java +++ b/presto-delta/src/main/java/com/facebook/presto/delta/DeltaPageSourceProvider.java @@ -33,6 +33,7 @@ import com.facebook.presto.parquet.RichColumnDescriptor; import com.facebook.presto.parquet.cache.MetadataReader; import com.facebook.presto.parquet.predicate.Predicate; +import com.facebook.presto.parquet.reader.ColumnIndexFilterUtils; import com.facebook.presto.parquet.reader.ParquetReader; import com.facebook.presto.spi.ColumnHandle; import com.facebook.presto.spi.ConnectorPageSource; @@ -55,6 +56,7 @@ import org.apache.parquet.hadoop.metadata.BlockMetaData; import org.apache.parquet.hadoop.metadata.FileMetaData; import org.apache.parquet.hadoop.metadata.ParquetMetadata; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; import org.apache.parquet.io.ColumnIO; import org.apache.parquet.io.MessageColumnIO; import org.apache.parquet.schema.GroupType; @@ -64,6 +66,7 @@ import java.io.FileNotFoundException; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -164,7 +167,8 @@ public ConnectorPageSource createPageSource( isParquetBatchReaderVerificationEnabled(session), typeManager, deltaTableLayoutHandle.getPredicate(), - fileFormatDataSourceStats); + fileFormatDataSourceStats, + false); return new DeltaPageSource( deltaColumnHandles, @@ -207,7 +211,8 @@ private static ConnectorPageSource createParquetPageSource( boolean verificationEnabled, TypeManager typeManager, TupleDomain effectivePredicate, - FileFormatDataSourceStats stats) + FileFormatDataSourceStats stats, + boolean columnIndexFilterEnabled) { AggregatedMemoryContext systemMemoryContext = newSimpleAggregatedMemoryContext(); @@ -243,9 +248,12 @@ private static ConnectorPageSource createParquetPageSource( Predicate parquetPredicate = buildPredicate(requestedSchema, parquetTupleDomain, descriptorsByPath); final ParquetDataSource finalDataSource = dataSource; ImmutableList.Builder blocks = ImmutableList.builder(); + List blockIndexStores = new ArrayList<>(); for (BlockMetaData block : footerBlocks.build()) { - if (predicateMatches(parquetPredicate, block, finalDataSource, descriptorsByPath, parquetTupleDomain)) { + Optional columnIndexStore = ColumnIndexFilterUtils.getColumnIndexStore(parquetPredicate, finalDataSource, block, descriptorsByPath, columnIndexFilterEnabled); + if (predicateMatches(parquetPredicate, block, finalDataSource, descriptorsByPath, parquetTupleDomain, columnIndexStore, columnIndexFilterEnabled)) { blocks.add(block); + blockIndexStores.add(columnIndexStore.orElse(null)); } } MessageColumnIO messageColumnIO = getColumnIO(fileSchema, requestedSchema); @@ -256,7 +264,10 @@ private static ConnectorPageSource createParquetPageSource( systemMemoryContext, maxReadBlockSize, batchReaderEnabled, - verificationEnabled); + verificationEnabled, + parquetPredicate, + blockIndexStores, + columnIndexFilterEnabled); ImmutableList.Builder namesBuilder = ImmutableList.builder(); ImmutableList.Builder typesBuilder = ImmutableList.builder(); diff --git a/presto-docs/pom.xml b/presto-docs/pom.xml index 88073b6399c70..561985d6dbc95 100644 --- a/presto-docs/pom.xml +++ b/presto-docs/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-docs diff --git a/presto-docs/src/main/sphinx/connector/pinot.rst b/presto-docs/src/main/sphinx/connector/pinot.rst index 7fd834b0cc932..8d4d89b944352 100644 --- a/presto-docs/src/main/sphinx/connector/pinot.rst +++ b/presto-docs/src/main/sphinx/connector/pinot.rst @@ -37,61 +37,61 @@ Catalog Properties The following catalog configuration properties are available: -======================================================== ============================================================ -Property Name Description -======================================================== ============================================================ -``pinot.controller-urls`` Pinot controller urls. -``pinot.controller-rest-service`` Alternative rest endpoint for Pinot controller requests. -``pinot.rest-proxy-url`` Pinot rest proxy url. -``pinot.allow-multiple-aggregations`` Push down a Pinot query with multiple aggregation functions, default is true. -``pinot.limit-large-for-segment`` Cap the number of rows returned when pushing down non-aggregation segment query, default is 2147483647. -``pinot.topn-large`` Cap the TOP/LIMIT value when pushing down broker query, default is 10000. -``pinot.thread-pool-size`` Parameter to init Pinot server query client, default is 30. -``pinot.min-connections-per-server`` Parameter to init Pinot server query client, default is 10. -``pinot.max-connections-per-server`` Parameter to init Pinot server query client, default is 30. -``pinot.max-backlog-per-server`` Parameter to init Pinot server query client, default is 30. -``pinot.idle-timeout`` Parameter to init Pinot server query client, default is 5 minutes. -``pinot.connection-timeout`` Connection Timeout to talk to Pinot servers, default is 1 minute. -``pinot.metadata-expiry`` Pinot metadata cache expiration time, default is 2 minutes. -``pinot.estimated-size-in-bytes-for-non-numeric-column`` Estimated byte size for non-numeric column, default is 20. -``pinot.service-header-param`` RPC service service header key, default is "RPC-Service". -``pinot.caller-header-param`` RPC service caller header key, default is "RPC-Caller". -``pinot.caller-header-value`` RPC service caller header value, default is "presto". -``pinot.forbid-broker-queries`` No broker request pushing down, default is false. -``pinot.forbid-segment-queries`` No segment query pushing down, fail the query if broker query pushing down is not possible, default is false. -``pinot.rest-proxy-service-for-query`` Use rest proxy endpoint for Pinot broker requests, default is false. -``pinot.use-date-trunc`` Use the new UDF dateTrunc in pinot that is more presto compatible, default is false. -``pinot.num-segments-per-split`` Number of segments of the same host per split, default is 1. -``pinot.ignore-empty-responses`` Ignore empty or missing pinot server responses, default is false. -``pinot.fetch-retry-count`` Retry count for retriable pinot data fetch calls, default is 2. -``pinot.non-aggregate-limit-for-broker-queries`` Max limit for non aggregate queries to the pinot broker, default is 25000. -``pinot.infer-date-type-in-schema`` Infer Pinot DAYS epoch column to Presto DATE type, default is true. -``pinot.infer-timestamp-type-in-schema`` Infer Pinot SECONDS epoch column to Presto TIMESTAMP type, default is true. -``pinot.mark-data-fetch-exceptions-as-retriable`` Retry Pinot request when failure, default is true. -``pinot.use-pinot-sql-for-broker-queries`` Use Pinot SQL syntax, otherwise PQL syntax, default is true. -``pinot.pushdown-topn-broker-queries`` Allow pushing down query pattern to broker: aggregation + groupBy + orderBy, default is false. -``pinot.use-streaming-for-segment-queries`` Use gRPC endpoint for pinot server queries, default is false. -``pinot.streaming-server-grpc-max-inbound-message-bytes`` Max inbound message bytes when init gRPC client, default is 128MB. -``pinot.use-proxy-for-broker-request`` Sending broker query to Pinot Proxy, default is false. -``pinot.use-proxy-grpc-endpoint`` Sending segment query to Pinot Proxy gRPC endpoint, default is false. -``pinot.proxy-grpc-host`` Pinot proxy gRPC host. -``pinot.proxy-grpc-port`` Pinot proxy gRPC port. -``pinot.use-https-for-controller`` Use https for controller requests, default is false. -``pinot.use-https-for-broker`` Use https for broker requests, default is false. -``pinot.use-https-for-proxy`` Use https for proxy requests, default is false. -``pinot.override-distinct-count-function`` Override 'distinctCount' function name, default is "distinctCount". -``pinot.extra-http-headers`` Extra headers when sending HTTP based pinot requests to Pinot controller/broker. -``pinot.extra-grpc-metadata`` Extra metadata when sending gRPC based pinot requests to Pinot broker/server/proxy. -======================================================== ============================================================ +========================================================== ============================================================================================================= +Property Name Description +========================================================== ============================================================================================================= +``pinot.controller-urls`` Pinot controller urls. +``pinot.controller-rest-service`` Alternative rest endpoint for Pinot controller requests. +``pinot.rest-proxy-url`` Pinot rest proxy url. +``pinot.allow-multiple-aggregations`` Push down a Pinot query with multiple aggregation functions, default is true. +``pinot.limit-large-for-segment`` Cap the number of rows returned when pushing down non-aggregation segment query, default is 2147483647. +``pinot.topn-large`` Cap the TOP/LIMIT value when pushing down broker query, default is 10000. +``pinot.thread-pool-size`` Parameter to init Pinot server query client, default is 30. +``pinot.min-connections-per-server`` Parameter to init Pinot server query client, default is 10. +``pinot.max-connections-per-server`` Parameter to init Pinot server query client, default is 30. +``pinot.max-backlog-per-server`` Parameter to init Pinot server query client, default is 30. +``pinot.idle-timeout`` Parameter to init Pinot server query client, default is 5 minutes. +``pinot.connection-timeout`` Connection Timeout to talk to Pinot servers, default is 1 minute. +``pinot.metadata-expiry`` Pinot metadata cache expiration time, default is 2 minutes. +``pinot.estimated-size-in-bytes-for-non-numeric-column`` Estimated byte size for non-numeric column, default is 20. +``pinot.service-header-param`` RPC service service header key, default is "RPC-Service". +``pinot.caller-header-param`` RPC service caller header key, default is "RPC-Caller". +``pinot.caller-header-value`` RPC service caller header value, default is "presto". +``pinot.forbid-broker-queries`` No broker request pushing down, default is false. +``pinot.forbid-segment-queries`` No segment query pushing down, fail the query if broker query pushing down is not possible, default is false. +``pinot.rest-proxy-service-for-query`` Use rest proxy endpoint for Pinot broker requests, default is false. +``pinot.use-date-trunc`` Use the new UDF dateTrunc in pinot that is more presto compatible, default is false. +``pinot.num-segments-per-split`` Number of segments of the same host per split, default is 1. +``pinot.ignore-empty-responses`` Ignore empty or missing pinot server responses, default is false. +``pinot.fetch-retry-count`` Retry count for retriable pinot data fetch calls, default is 2. +``pinot.non-aggregate-limit-for-broker-queries`` Max limit for non aggregate queries to the pinot broker, default is 25000. +``pinot.infer-date-type-in-schema`` Infer Pinot DAYS epoch column to Presto DATE type, default is true. +``pinot.infer-timestamp-type-in-schema`` Infer Pinot SECONDS epoch column to Presto TIMESTAMP type, default is true. +``pinot.mark-data-fetch-exceptions-as-retriable`` Retry Pinot request when failure, default is true. +``pinot.use-pinot-sql-for-broker-queries`` Use Pinot SQL syntax, otherwise PQL syntax, default is true. +``pinot.pushdown-topn-broker-queries`` Allow pushing down query pattern to broker: aggregation + groupBy + orderBy, default is false. +``pinot.use-streaming-for-segment-queries`` Use gRPC endpoint for pinot server queries, default is false. +``pinot.streaming-server-grpc-max-inbound-message-bytes`` Max inbound message bytes when init gRPC client, default is 128MB. +``pinot.use-proxy-for-broker-request`` Sending broker query to Pinot Proxy, default is false. +``pinot.use-proxy-grpc-endpoint`` Sending segment query to Pinot Proxy gRPC endpoint, default is false. +``pinot.proxy-grpc-host`` Pinot proxy gRPC host. +``pinot.proxy-grpc-port`` Pinot proxy gRPC port. +``pinot.use-https-for-controller`` Use https for controller requests, default is false. +``pinot.use-https-for-broker`` Use https for broker requests, default is false. +``pinot.use-https-for-proxy`` Use https for proxy requests, default is false. +``pinot.override-distinct-count-function`` Override 'distinctCount' function name, default is "distinctCount". +``pinot.extra-http-headers`` Extra headers when sending HTTP based pinot requests to Pinot controller/broker. E.g. k1:v1,k2:v2. +``pinot.extra-grpc-metadata`` Extra metadata when sending gRPC based pinot requests to Pinot broker/server/proxy. E.g. k1:v1,k2:v2. +========================================================== ============================================================================================================= Session Properties ^^^^^^^^^^^^^^^^^^ The following session properties are available: -======================================================== ============================================================ +======================================================== ================================================================== Property Name Description -======================================================== ============================================================ +======================================================== ================================================================== ``pinot.forbid_broker_queries`` Forbid queries to the broker. ``pinot.forbid_segment_queries`` Forbid segment queries. ``pinot.ignore_empty_responses`` Ignore empty or missing pinot server responses. @@ -105,7 +105,8 @@ Property Name Description ``pinot.num_segments_per_split`` Number of segments of the same host per split. ``pinot.limit_larger_for_segment`` Server query selection limit for large segment. ``pinot.override_distinct_count_function`` Override distinct count function to another function name. -======================================================== ============================================================ +``pinot.topn_large`` Cap the TOP/LIMIT value when pushing down broker query. +======================================================== ================================================================== Map Pinot Schema to Presto Schema --------------------------------- diff --git a/presto-docs/src/main/sphinx/installation/jdbc.rst b/presto-docs/src/main/sphinx/installation/jdbc.rst index 39e898fce647c..1e02f01d887f4 100644 --- a/presto-docs/src/main/sphinx/installation/jdbc.rst +++ b/presto-docs/src/main/sphinx/installation/jdbc.rst @@ -92,6 +92,8 @@ Name Description If neither this property nor ``ApplicationName`` are set, the source for the query will be ``presto-jdbc``. ``accessToken`` Access token for token based authentication. +``timeZoneId`` Timezone to be used for timestamp columns in query output. + Example: ``timeZoneId=UTC``. ``SSL`` Use HTTPS for connections ``SSLKeyStorePath`` The location of the Java KeyStore file that contains the certificate and private key to use for authentication. diff --git a/presto-docs/src/main/sphinx/optimizer/cost-based-optimizations.rst b/presto-docs/src/main/sphinx/optimizer/cost-based-optimizations.rst index 6308e04f56d96..a2fd1d03e70c8 100644 --- a/presto-docs/src/main/sphinx/optimizer/cost-based-optimizations.rst +++ b/presto-docs/src/main/sphinx/optimizer/cost-based-optimizations.rst @@ -25,8 +25,8 @@ session property, with the ``optimizer.join-reordering-strategy`` configuration property providing the default value. The valid values are: - * ``AUTOMATIC`` - full automatic join enumeration enabled - * ``ELIMINATE_CROSS_JOINS`` (default) - eliminate unnecessary cross joins + * ``AUTOMATIC`` (default) - full automatic join enumeration enabled + * ``ELIMINATE_CROSS_JOINS`` - eliminate unnecessary cross joins * ``NONE`` - purely syntactic join order If using ``AUTOMATIC`` and statistics are not available, or if for any other @@ -64,10 +64,10 @@ session property, with the ``join-distribution-type`` configuration property providing the default value. The valid values are: - * ``AUTOMATIC`` - join distribution type is determined automatically + * ``AUTOMATIC`` (default) - join distribution type is determined automatically for each join * ``BROADCAST`` - broadcast join distribution is used for all joins - * ``PARTITIONED`` (default) - partitioned join distribution is used for all join + * ``PARTITIONED`` - partitioned join distribution is used for all join Capping replicated table size ----------------------------- diff --git a/presto-docs/src/main/sphinx/release.rst b/presto-docs/src/main/sphinx/release.rst index 722f48e557088..f6d73bdedc6a9 100644 --- a/presto-docs/src/main/sphinx/release.rst +++ b/presto-docs/src/main/sphinx/release.rst @@ -5,6 +5,7 @@ Release Notes .. toctree:: :maxdepth: 1 + release/release-0.271 release/release-0.270 release/release-0.269 release/release-0.268 diff --git a/presto-docs/src/main/sphinx/release/release-0.271.rst b/presto-docs/src/main/sphinx/release/release-0.271.rst new file mode 100644 index 0000000000000..e3b0af19d4c11 --- /dev/null +++ b/presto-docs/src/main/sphinx/release/release-0.271.rst @@ -0,0 +1,33 @@ +============= +Release 0.271 +============= + +**Highlights** +============== + +**Details** +=========== + +General Changes +_______________ +* Fix reorder joins optimization where plan might not be optimal when original build side is larger than configured ``join-max-broadcast-table-size``. +* Add a new configuration property ``experimental.distinct-aggregation-large-block-size-threshold`` to define the threshold size beyond which the block will be spilled into a separate spill file. This can be overridden by ``distinct_aggregation_large_block_size_threshold`` session property. +* Add a new configuration property ``experimental.distinct-aggregation-large-block-spill-enabled`` to enable spilling of blocks that are larger than ``experimental.distinct-aggregation-large-block-size-threshold`` bytes into a separate spill file. This can be overridden by ``distinct_aggregation_large_block_spill_enabled`` session property. +* Add support for viewing expanded prepared query in Web UI. +* Test and fix cast from bigint to varchar. + +Hive Changes +____________ +* Fix ANALYZE TABLE for partitioned Hive tables with complex columns (array, map, struct). +* Improve performance of ANALYZE TABLE on hive tables with complex columns. + +Iceberg Changes +_______________ +* Remove the iceberg.catalog.uri config. Use hive.metastore.uri instead. +* Support ORC format caching module for iceberg connector. +* Support basic timestamp in the iceberg connector. + +**Credits** +=========== + +Abhishek Aggarwal, Amit Dutta, Arjun Gupta, Arunachalam Thirupathi, Beinan, Chunxu Tang, James Petty, James Sun, JySongWithZhangCe, Masha Basmanova, Mayank Garg, Neerad Somanchi, Otakar Trunecek, Pranjal Shankhdhar, Rebecca Schlussel, Rongrong Zhong, Sergii Druzkin, Shashwat Arghode, Swapnil Tailor, Timothy Meehan, Zitong Wei, abhiseksaikia, ericyuliu, mengdilin, singcha, v-jizhang diff --git a/presto-druid/pom.xml b/presto-druid/pom.xml index d6d4795f29f90..fdcb88673ab5c 100644 --- a/presto-druid/pom.xml +++ b/presto-druid/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-druid diff --git a/presto-elasticsearch/pom.xml b/presto-elasticsearch/pom.xml index 28a7270f6822f..39af73e0b6422 100644 --- a/presto-elasticsearch/pom.xml +++ b/presto-elasticsearch/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-elasticsearch Presto - Elasticsearch Connector diff --git a/presto-example-http/pom.xml b/presto-example-http/pom.xml index c1af89718b04d..d21a3abbe43d7 100644 --- a/presto-example-http/pom.xml +++ b/presto-example-http/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-example-http diff --git a/presto-expressions/pom.xml b/presto-expressions/pom.xml index 86d3a892df522..fa3b2dc6d5ed4 100644 --- a/presto-expressions/pom.xml +++ b/presto-expressions/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-expressions diff --git a/presto-function-namespace-managers/pom.xml b/presto-function-namespace-managers/pom.xml index af65b16750f0a..d90a37cdb1a13 100644 --- a/presto-function-namespace-managers/pom.xml +++ b/presto-function-namespace-managers/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-geospatial-toolkit/pom.xml b/presto-geospatial-toolkit/pom.xml index c2c454fc422ef..746e09c8638b2 100644 --- a/presto-geospatial-toolkit/pom.xml +++ b/presto-geospatial-toolkit/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-geospatial-toolkit diff --git a/presto-geospatial/pom.xml b/presto-geospatial/pom.xml index fee2310b592c5..c8d2126ba9822 100644 --- a/presto-geospatial/pom.xml +++ b/presto-geospatial/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-geospatial diff --git a/presto-google-sheets/pom.xml b/presto-google-sheets/pom.xml index f560c49f612d4..b3d6ebcc18820 100644 --- a/presto-google-sheets/pom.xml +++ b/presto-google-sheets/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-google-sheets diff --git a/presto-grpc-api/pom.xml b/presto-grpc-api/pom.xml index ae7f8e6fa9e20..97112aaa41b96 100644 --- a/presto-grpc-api/pom.xml +++ b/presto-grpc-api/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-grpc-testing-udf-server/pom.xml b/presto-grpc-testing-udf-server/pom.xml index 99e1057498c0e..f2d754787072c 100644 --- a/presto-grpc-testing-udf-server/pom.xml +++ b/presto-grpc-testing-udf-server/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-hive-common/pom.xml b/presto-hive-common/pom.xml index dc102db3b06ef..f46d28ee75c76 100644 --- a/presto-hive-common/pom.xml +++ b/presto-hive-common/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT diff --git a/presto-hive-function-namespace/pom.xml b/presto-hive-function-namespace/pom.xml index 13f0bb469db8e..616478375c603 100644 --- a/presto-hive-function-namespace/pom.xml +++ b/presto-hive-function-namespace/pom.xml @@ -4,7 +4,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-hive-function-namespace diff --git a/presto-hive-hadoop2/pom.xml b/presto-hive-hadoop2/pom.xml index 2b80d4afe9347..0d7892b5abe29 100644 --- a/presto-hive-hadoop2/pom.xml +++ b/presto-hive-hadoop2/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-hive-hadoop2 diff --git a/presto-hive-metastore/pom.xml b/presto-hive-metastore/pom.xml index 4bf28986c9565..146ab714dd7cb 100644 --- a/presto-hive-metastore/pom.xml +++ b/presto-hive-metastore/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-hive-metastore diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/CachingHiveMetastore.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/CachingHiveMetastore.java index e88a1b3457453..fae75c7e21688 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/CachingHiveMetastore.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/CachingHiveMetastore.java @@ -941,6 +941,19 @@ public void setPartitionLeases(MetastoreContext metastoreContext, String databas delegate.setPartitionLeases(metastoreContext, databaseName, tableName, partitionNameToLocation, leaseDuration); } + @Override + public long lock(MetastoreContext metastoreContext, String databaseName, String tableName) + { + tableCache.invalidate(getCachingKey(metastoreContext, hiveTableName(databaseName, tableName))); + return delegate.lock(metastoreContext, databaseName, tableName); + } + + @Override + public void unlock(MetastoreContext metastoreContext, long lockId) + { + delegate.unlock(metastoreContext, lockId); + } + public Set loadTablePrivileges(KeyAndContext loadTablePrivilegesKey) { return delegate.listTablePrivileges(loadTablePrivilegesKey.getContext(), loadTablePrivilegesKey.getKey().getDatabase(), loadTablePrivilegesKey.getKey().getTable(), loadTablePrivilegesKey.getKey().getPrincipal()); diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/ExtendedHiveMetastore.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/ExtendedHiveMetastore.java index dd66da57e4721..92b550dd861d6 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/ExtendedHiveMetastore.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/ExtendedHiveMetastore.java @@ -13,6 +13,7 @@ */ package com.facebook.presto.hive.metastore; +import com.facebook.presto.common.NotSupportedException; import com.facebook.presto.common.predicate.Domain; import com.facebook.presto.common.type.Type; import com.facebook.presto.hive.HiveType; @@ -117,4 +118,14 @@ List getPartitionNamesWithVersionByFilter( Set listTablePrivileges(MetastoreContext metastoreContext, String databaseName, String tableName, PrestoPrincipal principal); void setPartitionLeases(MetastoreContext metastoreContext, String databaseName, String tableName, Map partitionNameToLocation, Duration leaseDuration); + + default long lock(MetastoreContext metastoreContext, String databaseName, String tableName) + { + throw new NotSupportedException("Lock is not supported by default"); + } + + default void unlock(MetastoreContext metastoreContext, long lockId) + { + throw new NotSupportedException("Unlock is not supported by default"); + } } diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/file/FileHiveMetastore.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/file/FileHiveMetastore.java index c6c43326724d4..1bd819e1b9fdf 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/file/FileHiveMetastore.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/file/FileHiveMetastore.java @@ -28,6 +28,7 @@ import com.facebook.presto.hive.metastore.ExtendedHiveMetastore; import com.facebook.presto.hive.metastore.HiveColumnStatistics; import com.facebook.presto.hive.metastore.HivePrivilegeInfo; +import com.facebook.presto.hive.metastore.HiveTableName; import com.facebook.presto.hive.metastore.MetastoreContext; import com.facebook.presto.hive.metastore.MetastoreUtil; import com.facebook.presto.hive.metastore.Partition; @@ -45,6 +46,8 @@ import com.facebook.presto.spi.security.PrestoPrincipal; import com.facebook.presto.spi.security.RoleGrant; import com.facebook.presto.spi.statistics.ColumnStatisticType; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -81,6 +84,7 @@ import static com.facebook.presto.hive.HiveErrorCode.HIVE_METASTORE_ERROR; import static com.facebook.presto.hive.HiveErrorCode.HIVE_PARTITION_DROPPED_DURING_QUERY; import static com.facebook.presto.hive.metastore.HivePrivilegeInfo.HivePrivilege.OWNERSHIP; +import static com.facebook.presto.hive.metastore.HiveTableName.hiveTableName; import static com.facebook.presto.hive.metastore.MetastoreUtil.convertPredicateToParts; import static com.facebook.presto.hive.metastore.MetastoreUtil.extractPartitionValues; import static com.facebook.presto.hive.metastore.MetastoreUtil.getHiveBasicStatistics; @@ -123,6 +127,9 @@ public class FileHiveMetastore private final HdfsContext hdfsContext; private final FileSystem metadataFileSystem; + private final BiMap lockedHiveTables = HashBiMap.create(); + private long currentLockId; + private final JsonCodec databaseCodec = JsonCodec.jsonCodec(DatabaseMetadata.class); private final JsonCodec tableCodec = JsonCodec.jsonCodec(TableMetadata.class); private final JsonCodec partitionCodec = JsonCodec.jsonCodec(PartitionMetadata.class); @@ -1005,6 +1012,30 @@ public synchronized void setPartitionLeases(MetastoreContext metastoreContext, S throw new UnsupportedOperationException("setPartitionLeases is not supported in FileHiveMetastore"); } + @Override + public synchronized long lock(MetastoreContext metastoreContext, String databaseName, String tableName) + { + HiveTableName hiveTableName = hiveTableName(databaseName, tableName); + while (lockedHiveTables.containsValue(hiveTableName)) { + try { + Thread.sleep(10); + } + catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Waiting for lock interrupted"); + } + } + long lockId = ++currentLockId; + lockedHiveTables.put(lockId, hiveTableName); + return lockId; + } + + @Override + public synchronized void unlock(MetastoreContext metastoreContext, long lockId) + { + lockedHiveTables.remove(lockId); + } + private synchronized void setTablePrivileges( MetastoreContext metastoreContext, PrestoPrincipal grantee, diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/BridgingHiveMetastore.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/BridgingHiveMetastore.java index 2c8bd2b90d9cf..5332a8fa51b32 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/BridgingHiveMetastore.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/BridgingHiveMetastore.java @@ -378,4 +378,16 @@ public void setPartitionLeases(MetastoreContext metastoreContext, String databas { delegate.setPartitionLeases(metastoreContext, databaseName, tableName, partitionNameToLocation, leaseDuration); } + + @Override + public long lock(MetastoreContext metastoreContext, String databaseName, String tableName) + { + return delegate.lock(metastoreContext, databaseName, tableName); + } + + @Override + public void unlock(MetastoreContext metastoreContext, long lockId) + { + delegate.unlock(metastoreContext, lockId); + } } diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastore.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastore.java index dbeaef63df10d..496ab31865055 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastore.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastore.java @@ -114,6 +114,16 @@ default List getPartitionNamesWithVersionByFilter(Meta Set listTablePrivileges(MetastoreContext metastoreContext, String databaseName, String tableName, PrestoPrincipal principal); + default long lock(MetastoreContext metastoreContext, String databaseName, String tableName) + { + throw new UnsupportedOperationException(); + } + + default void unlock(MetastoreContext metastoreContext, long lockId) + { + throw new UnsupportedOperationException(); + } + default void setPartitionLeases(MetastoreContext metastoreContext, String databaseName, String tableName, Map partitionNameToLocation, Duration leaseDuration) { throw new UnsupportedOperationException(); diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastoreClient.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastoreClient.java index 37d233e1b99f1..e625cc0966dcd 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastoreClient.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/HiveMetastoreClient.java @@ -13,17 +13,21 @@ */ package com.facebook.presto.hive.metastore.thrift; +import org.apache.hadoop.hive.metastore.api.CheckLockRequest; import org.apache.hadoop.hive.metastore.api.ColumnStatisticsObj; import org.apache.hadoop.hive.metastore.api.Database; import org.apache.hadoop.hive.metastore.api.FieldSchema; import org.apache.hadoop.hive.metastore.api.HiveObjectPrivilege; import org.apache.hadoop.hive.metastore.api.HiveObjectRef; +import org.apache.hadoop.hive.metastore.api.LockRequest; +import org.apache.hadoop.hive.metastore.api.LockResponse; import org.apache.hadoop.hive.metastore.api.Partition; import org.apache.hadoop.hive.metastore.api.PrincipalType; import org.apache.hadoop.hive.metastore.api.PrivilegeBag; import org.apache.hadoop.hive.metastore.api.Role; import org.apache.hadoop.hive.metastore.api.RolePrincipalGrant; import org.apache.hadoop.hive.metastore.api.Table; +import org.apache.hadoop.hive.metastore.api.UnlockRequest; import org.apache.thrift.TException; import java.io.Closeable; @@ -146,4 +150,13 @@ List listRoleGrants(String name, PrincipalType principalType void setUGI(String userName) throws TException; + + LockResponse checkLock(CheckLockRequest request) + throws TException; + + LockResponse lock(LockRequest request) + throws TException; + + void unlock(UnlockRequest request) + throws TException; } diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastore.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastore.java index acadf5b544cac..a0acd2d82c4a6 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastore.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastore.java @@ -43,8 +43,10 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import org.apache.hadoop.hive.metastore.TableType; import org.apache.hadoop.hive.metastore.api.AlreadyExistsException; +import org.apache.hadoop.hive.metastore.api.CheckLockRequest; import org.apache.hadoop.hive.metastore.api.ColumnStatisticsObj; import org.apache.hadoop.hive.metastore.api.Database; import org.apache.hadoop.hive.metastore.api.FieldSchema; @@ -53,6 +55,11 @@ import org.apache.hadoop.hive.metastore.api.InvalidInputException; import org.apache.hadoop.hive.metastore.api.InvalidObjectException; import org.apache.hadoop.hive.metastore.api.InvalidOperationException; +import org.apache.hadoop.hive.metastore.api.LockComponent; +import org.apache.hadoop.hive.metastore.api.LockLevel; +import org.apache.hadoop.hive.metastore.api.LockRequest; +import org.apache.hadoop.hive.metastore.api.LockResponse; +import org.apache.hadoop.hive.metastore.api.LockState; import org.apache.hadoop.hive.metastore.api.MetaException; import org.apache.hadoop.hive.metastore.api.NoSuchObjectException; import org.apache.hadoop.hive.metastore.api.Partition; @@ -62,6 +69,7 @@ import org.apache.hadoop.hive.metastore.api.Table; import org.apache.hadoop.hive.metastore.api.UnknownDBException; import org.apache.hadoop.hive.metastore.api.UnknownTableException; +import org.apache.hadoop.hive.metastore.api.UnlockRequest; import org.apache.thrift.TException; import org.weakref.jmx.Flatten; import org.weakref.jmx.Managed; @@ -69,6 +77,7 @@ import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; +import java.net.InetAddress; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -77,6 +86,7 @@ import java.util.OptionalLong; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; import java.util.stream.Collectors; @@ -124,6 +134,9 @@ import static java.util.stream.Collectors.toSet; import static org.apache.hadoop.hive.common.FileUtils.makePartName; import static org.apache.hadoop.hive.metastore.api.HiveObjectType.TABLE; +import static org.apache.hadoop.hive.metastore.api.LockState.ACQUIRED; +import static org.apache.hadoop.hive.metastore.api.LockState.WAITING; +import static org.apache.hadoop.hive.metastore.api.LockType.EXCLUSIVE; import static org.apache.hadoop.hive.metastore.api.hive_metastoreConstants.HIVE_FILTER_FIELD_PARAMS; @ThreadSafe @@ -1309,6 +1322,100 @@ public Set listTablePrivileges(MetastoreContext metastoreCont } } + @Override + public long lock(MetastoreContext metastoreContext, String databaseName, String tableName) + { + try { + final LockComponent lockComponent = new LockComponent(EXCLUSIVE, LockLevel.TABLE, databaseName); + lockComponent.setTablename(tableName); + final LockRequest lockRequest = new LockRequest(Lists.newArrayList(lockComponent), + metastoreContext.getUsername(), + InetAddress.getLocalHost().getHostName()); + LockResponse lockResponse = stats.getLock().wrap(() -> getMetastoreClientThenCall(metastoreContext, client -> client.lock(lockRequest))).call(); + LockState state = lockResponse.getState(); + long lockId = lockResponse.getLockid(); + final AtomicBoolean acquired = new AtomicBoolean(state.equals(ACQUIRED)); + + try { + if (state.equals(WAITING)) { + retry() + .maxAttempts(Integer.MAX_VALUE - 100) + .stopOnIllegalExceptions() + .exceptionMapper(e -> { + if (e instanceof WaitingForLockException) { + // only retry on waiting for lock exception + return e; + } + else { + return new IllegalStateException(e.getMessage(), e); + } + }) + .run("lock", stats.getLock().wrap(() -> + getMetastoreClientThenCall(metastoreContext, client -> { + LockResponse response = client.checkLock(new CheckLockRequest(lockId)); + LockState newState = response.getState(); + if (newState.equals(WAITING)) { + throw new WaitingForLockException("Waiting for lock."); + } + else if (newState.equals(ACQUIRED)) { + acquired.set(true); + } + else { + throw new RuntimeException(String.format("Failed to acquire lock: %s", newState.name())); + } + return null; + }))); + } + } + finally { + if (!acquired.get()) { + unlock(metastoreContext, lockId); + } + } + + if (!acquired.get()) { + throw new RuntimeException("Failed to acquire lock"); + } + + return lockId; + } + catch (TException e) { + throw new PrestoException(HIVE_METASTORE_ERROR, e); + } + catch (Exception e) { + throw propagate(e); + } + } + + @Override + public void unlock(MetastoreContext metastoreContext, long lockId) + { + try { + retry() + .stopOnIllegalExceptions() + .run("unlock", + stats.getUnlock().wrap(() -> getMetastoreClientThenCall(metastoreContext, client -> { + client.unlock(new UnlockRequest(lockId)); + return null; + }))); + } + catch (TException e) { + throw new PrestoException(HIVE_METASTORE_ERROR, e); + } + catch (Exception e) { + throw propagate(e); + } + } + + private static class WaitingForLockException + extends RuntimeException + { + public WaitingForLockException(String message) + { + super(message); + } + } + private PrivilegeBag buildPrivilegeBag( String databaseName, String tableName, diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastoreClient.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastoreClient.java index fddefc67da263..c9c481f758e79 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastoreClient.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastoreClient.java @@ -14,6 +14,7 @@ package com.facebook.presto.hive.metastore.thrift; import com.google.common.collect.ImmutableList; +import org.apache.hadoop.hive.metastore.api.CheckLockRequest; import org.apache.hadoop.hive.metastore.api.ColumnStatistics; import org.apache.hadoop.hive.metastore.api.ColumnStatisticsDesc; import org.apache.hadoop.hive.metastore.api.ColumnStatisticsObj; @@ -26,6 +27,8 @@ import org.apache.hadoop.hive.metastore.api.GrantRevokeType; import org.apache.hadoop.hive.metastore.api.HiveObjectPrivilege; import org.apache.hadoop.hive.metastore.api.HiveObjectRef; +import org.apache.hadoop.hive.metastore.api.LockRequest; +import org.apache.hadoop.hive.metastore.api.LockResponse; import org.apache.hadoop.hive.metastore.api.MetaException; import org.apache.hadoop.hive.metastore.api.Partition; import org.apache.hadoop.hive.metastore.api.PartitionsStatsRequest; @@ -36,6 +39,7 @@ import org.apache.hadoop.hive.metastore.api.Table; import org.apache.hadoop.hive.metastore.api.TableStatsRequest; import org.apache.hadoop.hive.metastore.api.ThriftHiveMetastore; +import org.apache.hadoop.hive.metastore.api.UnlockRequest; import org.apache.thrift.TException; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; @@ -400,4 +404,25 @@ public void setUGI(String userName) { client.set_ugi(userName, new ArrayList<>()); } + + @Override + public LockResponse checkLock(CheckLockRequest request) + throws TException + { + return client.check_lock(request); + } + + @Override + public LockResponse lock(LockRequest request) + throws TException + { + return client.lock(request); + } + + @Override + public void unlock(UnlockRequest request) + throws TException + { + client.unlock(request); + } } diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastoreStats.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastoreStats.java index a95f9290972ff..89d2d4414da17 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastoreStats.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastoreStats.java @@ -50,6 +50,8 @@ public class ThriftHiveMetastoreStats private final HiveMetastoreApiStats listRoleGrants = new HiveMetastoreApiStats(); private final HiveMetastoreApiStats createRole = new HiveMetastoreApiStats(); private final HiveMetastoreApiStats dropRole = new HiveMetastoreApiStats(); + private final HiveMetastoreApiStats lock = new HiveMetastoreApiStats(); + private final HiveMetastoreApiStats unlock = new HiveMetastoreApiStats(); @Managed @Nested @@ -274,4 +276,18 @@ public HiveMetastoreApiStats getDropRole() { return dropRole; } + + @Managed + @Nested + public HiveMetastoreApiStats getLock() + { + return lock; + } + + @Managed + @Nested + public HiveMetastoreApiStats getUnlock() + { + return unlock; + } } diff --git a/presto-hive-metastore/src/test/java/com/facebook/presto/hive/metastore/thrift/MockHiveMetastoreClient.java b/presto-hive-metastore/src/test/java/com/facebook/presto/hive/metastore/thrift/MockHiveMetastoreClient.java index 30bfc40511167..b10bece3dcccb 100644 --- a/presto-hive-metastore/src/test/java/com/facebook/presto/hive/metastore/thrift/MockHiveMetastoreClient.java +++ b/presto-hive-metastore/src/test/java/com/facebook/presto/hive/metastore/thrift/MockHiveMetastoreClient.java @@ -24,11 +24,14 @@ import com.google.common.collect.Lists; import org.apache.hadoop.hive.metastore.TableType; import org.apache.hadoop.hive.metastore.Warehouse; +import org.apache.hadoop.hive.metastore.api.CheckLockRequest; import org.apache.hadoop.hive.metastore.api.ColumnStatisticsObj; import org.apache.hadoop.hive.metastore.api.Database; import org.apache.hadoop.hive.metastore.api.FieldSchema; import org.apache.hadoop.hive.metastore.api.HiveObjectPrivilege; import org.apache.hadoop.hive.metastore.api.HiveObjectRef; +import org.apache.hadoop.hive.metastore.api.LockRequest; +import org.apache.hadoop.hive.metastore.api.LockResponse; import org.apache.hadoop.hive.metastore.api.MetaException; import org.apache.hadoop.hive.metastore.api.NoSuchObjectException; import org.apache.hadoop.hive.metastore.api.Partition; @@ -39,6 +42,7 @@ import org.apache.hadoop.hive.metastore.api.SerDeInfo; import org.apache.hadoop.hive.metastore.api.StorageDescriptor; import org.apache.hadoop.hive.metastore.api.Table; +import org.apache.hadoop.hive.metastore.api.UnlockRequest; import org.apache.thrift.TException; import java.util.List; @@ -416,4 +420,22 @@ public void setUGI(String userName) { // No-op } + + @Override + public LockResponse checkLock(CheckLockRequest request) + { + throw new UnsupportedOperationException(); + } + + @Override + public LockResponse lock(LockRequest request) + { + throw new UnsupportedOperationException(); + } + + @Override + public void unlock(UnlockRequest request) + { + throw new UnsupportedOperationException(); + } } diff --git a/presto-hive/pom.xml b/presto-hive/pom.xml index 87c4cbf892839..cc48f713552a1 100644 --- a/presto-hive/pom.xml +++ b/presto-hive/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-hive diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientConfig.java b/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientConfig.java index ede8b0e5fe3f0..28b6abd0fdc52 100644 --- a/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientConfig.java +++ b/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientConfig.java @@ -155,6 +155,7 @@ public class HiveClientConfig private boolean s3SelectPushdownEnabled; private int s3SelectPushdownMaxConnections = 500; + private boolean streamingAggregationEnabled; private boolean isTemporaryStagingDirectoryEnabled = true; private String temporaryStagingDirectoryPath = "/tmp/presto-${USER}"; @@ -205,6 +206,9 @@ public class HiveClientConfig private boolean userDefinedTypeEncodingEnabled; + private boolean columnIndexFilterEnabled; + private boolean fileSplittable = true; + @Min(0) public int getMaxInitialSplits() { @@ -1353,6 +1357,19 @@ public HiveClientConfig setS3SelectPushdownMaxConnections(int s3SelectPushdownMa return this; } + public boolean isStreamingAggregationEnabled() + { + return streamingAggregationEnabled; + } + + @Config("hive.streaming-aggregation-enabled") + @ConfigDescription("Enable streaming aggregation execution") + public HiveClientConfig setStreamingAggregationEnabled(boolean streamingAggregationEnabled) + { + this.streamingAggregationEnabled = streamingAggregationEnabled; + return this; + } + public boolean isTemporaryStagingDirectoryEnabled() { return isTemporaryStagingDirectoryEnabled; @@ -1704,6 +1721,19 @@ public int getMaterializedViewMissingPartitionsThreshold() return this.materializedViewMissingPartitionsThreshold; } + @Config("hive.parquet-column-index-filter-enabled") + @ConfigDescription("enable using parquet column index filter") + public HiveClientConfig setReadColumnIndexFilter(boolean columnIndexFilterEnabled) + { + this.columnIndexFilterEnabled = columnIndexFilterEnabled; + return this; + } + + public boolean getReadColumnIndexFilter() + { + return this.columnIndexFilterEnabled; + } + @Config("hive.size-based-split-weights-enabled") public HiveClientConfig setSizeBasedSplitWeightsEnabled(boolean sizeBasedSplitWeightsEnabled) { @@ -1743,4 +1773,17 @@ public HiveClientConfig setUseRecordPageSourceForCustomSplit(boolean useRecordPa this.useRecordPageSourceForCustomSplit = useRecordPageSourceForCustomSplit; return this; } + + public boolean isFileSplittable() + { + return fileSplittable; + } + + @Config("hive.file-splittable") + @ConfigDescription("By default, this value is true. Set to false to make a hive file un-splittable when coordinator schedules splits.") + public HiveClientConfig setFileSplittable(boolean fileSplittable) + { + this.fileSplittable = fileSplittable; + return this; + } } diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/HiveMetadata.java b/presto-hive/src/main/java/com/facebook/presto/hive/HiveMetadata.java index 47c53c74e5949..8ae0c170a748a 100644 --- a/presto-hive/src/main/java/com/facebook/presto/hive/HiveMetadata.java +++ b/presto-hive/src/main/java/com/facebook/presto/hive/HiveMetadata.java @@ -63,6 +63,7 @@ import com.facebook.presto.spi.Constraint; import com.facebook.presto.spi.DiscretePredicates; import com.facebook.presto.spi.InMemoryRecordSet; +import com.facebook.presto.spi.LocalProperty; import com.facebook.presto.spi.MaterializedViewNotFoundException; import com.facebook.presto.spi.MaterializedViewStatus; import com.facebook.presto.spi.PrestoException; @@ -70,6 +71,7 @@ import com.facebook.presto.spi.RecordCursor; import com.facebook.presto.spi.SchemaTableName; import com.facebook.presto.spi.SchemaTablePrefix; +import com.facebook.presto.spi.SortingProperty; import com.facebook.presto.spi.SystemTable; import com.facebook.presto.spi.TableLayoutFilterCoverage; import com.facebook.presto.spi.TableNotFoundException; @@ -222,6 +224,7 @@ import static com.facebook.presto.hive.HiveSessionProperties.isSortedWriteToTempPathEnabled; import static com.facebook.presto.hive.HiveSessionProperties.isSortedWritingEnabled; import static com.facebook.presto.hive.HiveSessionProperties.isStatisticsEnabled; +import static com.facebook.presto.hive.HiveSessionProperties.isStreamingAggregationEnabled; import static com.facebook.presto.hive.HiveSessionProperties.isUsePageFileForHiveUnsupportedType; import static com.facebook.presto.hive.HiveSessionProperties.shouldCreateEmptyBucketFilesForTemporaryTable; import static com.facebook.presto.hive.HiveStorageFormat.AVRO; @@ -2758,14 +2761,46 @@ public ConnectorTableLayout getTableLayout(ConnectorSession session, ConnectorTa predicate = createPredicate(partitionColumns, partitions); } + // Expose ordering property of the table. + ImmutableList.Builder> localProperties = ImmutableList.builder(); + Optional> streamPartitionColumns = Optional.empty(); + if (table.getStorage().getBucketProperty().isPresent() && !table.getStorage().getBucketProperty().get().getSortedBy().isEmpty()) { + ImmutableSet.Builder streamPartitionColumnsBuilder = ImmutableSet.builder(); + + // streamPartitioningColumns is how we partition the data across splits. + // localProperty is how we partition the data within a split. + // 1. add partition columns to streamPartitionColumns + partitionColumns.forEach(streamPartitionColumnsBuilder::add); + + // 2. add sorted columns to streamPartitionColumns and localProperties + HiveBucketProperty bucketProperty = table.getStorage().getBucketProperty().get(); + Map columnHandles = hiveColumnHandles(table).stream() + .collect(toImmutableMap(HiveColumnHandle::getName, identity())); + bucketProperty.getSortedBy().forEach(sortingColumn -> { + ColumnHandle columnHandle = columnHandles.get(sortingColumn.getColumnName()); + localProperties.add(new SortingProperty<>(columnHandle, sortingColumn.getOrder().getSortOrder())); + streamPartitionColumnsBuilder.add(columnHandle); + }); + + // We currently only set streamPartitionColumns when it enables streaming aggregation and also it's eligible to enable streaming aggregation + // 1. When the bucket columns are the same as the prefix of the sort columns + // 2. When all rows of the same value group are guaranteed to be in the same split. We disable splitting a file when isStreamingAggregationEnabled is true to make sure the property is guaranteed. + List sortColumns = bucketProperty.getSortedBy().stream().map(SortingColumn::getColumnName).collect(toImmutableList()); + if (bucketProperty.getBucketedBy().size() <= sortColumns.size() + && bucketProperty.getBucketedBy().containsAll(sortColumns.subList(0, bucketProperty.getBucketedBy().size())) + && isStreamingAggregationEnabled(session)) { + streamPartitionColumns = Optional.of(streamPartitionColumnsBuilder.build()); + } + } + return new ConnectorTableLayout( hiveLayoutHandle, Optional.empty(), predicate, tablePartitioning, - Optional.empty(), + streamPartitionColumns, discretePredicates, - ImmutableList.of(), + localProperties.build(), Optional.of(hiveLayoutHandle.getRemainingPredicate())); } diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/HiveSessionProperties.java b/presto-hive/src/main/java/com/facebook/presto/hive/HiveSessionProperties.java index e51edc9f15042..2ef432311d66b 100644 --- a/presto-hive/src/main/java/com/facebook/presto/hive/HiveSessionProperties.java +++ b/presto-hive/src/main/java/com/facebook/presto/hive/HiveSessionProperties.java @@ -94,6 +94,7 @@ public final class HiveSessionProperties public static final String PARTITION_STATISTICS_BASED_OPTIMIZATION_ENABLED = "partition_stats_based_optimization_enabled"; private static final String OPTIMIZE_MISMATCHED_BUCKET_COUNT = "optimize_mismatched_bucket_count"; private static final String S3_SELECT_PUSHDOWN_ENABLED = "s3_select_pushdown_enabled"; + public static final String STREAMING_AGGREGATION_ENABLED = "streaming_aggregation_enabled"; public static final String SHUFFLE_PARTITIONED_COLUMNS_FOR_TABLE_WRITE = "shuffle_partitioned_columns_for_table_write"; public static final String TEMPORARY_STAGING_DIRECTORY_ENABLED = "temporary_staging_directory_enabled"; private static final String TEMPORARY_STAGING_DIRECTORY_PATH = "temporary_staging_directory_path"; @@ -130,10 +131,12 @@ public final class HiveSessionProperties public static final String VERBOSE_RUNTIME_STATS_ENABLED = "verbose_runtime_stats_enabled"; private static final String DWRF_WRITER_STRIPE_CACHE_ENABLED = "dwrf_writer_stripe_cache_enabled"; private static final String DWRF_WRITER_STRIPE_CACHE_SIZE = "dwrf_writer_stripe_cache_size"; + public static final String USE_COLUMN_INDEX_FILTER = "use_column_index_filter"; public static final String SIZE_BASED_SPLIT_WEIGHTS_ENABLED = "size_based_split_weights_enabled"; public static final String MINIMUM_ASSIGNED_SPLIT_WEIGHT = "minimum_assigned_split_weight"; private static final String USE_RECORD_PAGE_SOURCE_FOR_CUSTOM_SPLIT = "use_record_page_source_for_custom_split"; public static final String MAX_INITIAL_SPLITS = "max_initial_splits"; + public static final String FILE_SPLITTABLE = "file_splittable"; private final List> sessionProperties; @@ -412,6 +415,11 @@ public HiveSessionProperties(HiveClientConfig hiveClientConfig, OrcFileWriterCon "S3 Select pushdown enabled", hiveClientConfig.isS3SelectPushdownEnabled(), false), + booleanProperty( + STREAMING_AGGREGATION_ENABLED, + "Enable streaming aggregation execution", + hiveClientConfig.isStreamingAggregationEnabled(), + false), booleanProperty( TEMPORARY_STAGING_DIRECTORY_ENABLED, "Should use temporary staging directory for write operations", @@ -628,6 +636,11 @@ public HiveSessionProperties(HiveClientConfig hiveClientConfig, OrcFileWriterCon "Maximum size of DWRF stripe cache to be held in memory", orcFileWriterConfig.getDwrfStripeCacheMaxSize(), false), + booleanProperty( + USE_COLUMN_INDEX_FILTER, + "should use column index statistics filtering", + hiveClientConfig.getReadColumnIndexFilter(), + false), booleanProperty( SIZE_BASED_SPLIT_WEIGHTS_ENABLED, "Enable estimating split weights based on size in bytes", @@ -657,6 +670,11 @@ public HiveSessionProperties(HiveClientConfig hiveClientConfig, OrcFileWriterCon MAX_INITIAL_SPLITS, "Hive max initial split count", hiveClientConfig.getMaxInitialSplits(), + true), + booleanProperty( + FILE_SPLITTABLE, + "If a hive file is splittable when coordinator schedules splits", + hiveClientConfig.isFileSplittable(), true)); } @@ -877,6 +895,11 @@ public static boolean isS3SelectPushdownEnabled(ConnectorSession session) return session.getProperty(S3_SELECT_PUSHDOWN_ENABLED, Boolean.class); } + public static boolean isStreamingAggregationEnabled(ConnectorSession session) + { + return session.getProperty(STREAMING_AGGREGATION_ENABLED, Boolean.class); + } + public static boolean isStatisticsEnabled(ConnectorSession session) { return session.getProperty(STATISTICS_ENABLED, Boolean.class); @@ -1118,6 +1141,11 @@ public static DataSize getDwrfWriterStripeCacheeMaxSize(ConnectorSession session return session.getProperty(DWRF_WRITER_STRIPE_CACHE_SIZE, DataSize.class); } + public static boolean columnIndexFilterEnabled(ConnectorSession session) + { + return session.getProperty(USE_COLUMN_INDEX_FILTER, Boolean.class); + } + public static boolean isSizeBasedSplitWeightsEnabled(ConnectorSession session) { return session.getProperty(SIZE_BASED_SPLIT_WEIGHTS_ENABLED, Boolean.class); @@ -1137,4 +1165,9 @@ public static int getHiveMaxInitialSplitSize(ConnectorSession session) { return session.getProperty(MAX_INITIAL_SPLITS, Integer.class); } + + public static boolean isFileSplittable(ConnectorSession session) + { + return session.getProperty(FILE_SPLITTABLE, Boolean.class); + } } diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/StoragePartitionLoader.java b/presto-hive/src/main/java/com/facebook/presto/hive/StoragePartitionLoader.java index 5ebceacfcdbbc..f7a0583dc4d53 100644 --- a/presto-hive/src/main/java/com/facebook/presto/hive/StoragePartitionLoader.java +++ b/presto-hive/src/main/java/com/facebook/presto/hive/StoragePartitionLoader.java @@ -68,6 +68,8 @@ import static com.facebook.presto.hive.HiveMetadata.shouldCreateFilesForMissingBuckets; import static com.facebook.presto.hive.HiveSessionProperties.getMaxInitialSplitSize; import static com.facebook.presto.hive.HiveSessionProperties.getNodeSelectionStrategy; +import static com.facebook.presto.hive.HiveSessionProperties.isFileSplittable; +import static com.facebook.presto.hive.HiveSessionProperties.isStreamingAggregationEnabled; import static com.facebook.presto.hive.HiveSessionProperties.isUseListDirectoryCache; import static com.facebook.presto.hive.HiveUtil.getFooterCount; import static com.facebook.presto.hive.HiveUtil.getHeaderCount; @@ -260,11 +262,16 @@ public ListenableFuture loadPartition(HivePartitionMetadata partition, HiveSp return addSplitsToSource(splits, splitFactory, hiveSplitSource, stopped); } PathFilter pathFilter = isHudiParquetInputFormat(inputFormat) ? hoodiePathFilterLoadingCache.getUnchecked(configuration) : path1 -> true; + // Streaming aggregation works at the granularity of individual files // S3 Select pushdown works at the granularity of individual S3 objects, // Partial aggregation pushdown works at the granularity of individual files // therefore we must not split files when either is enabled. // Skip header / footer lines are not splittable except for a special case when skip.header.line.count=1 - boolean splittable = !s3SelectPushdownEnabled && !partialAggregationsPushedDown && getFooterCount(schema) == 0 && getHeaderCount(schema) <= 1; + boolean splittable = isFileSplittable(session) && + !isStreamingAggregationEnabled(session) && + !s3SelectPushdownEnabled && + !partialAggregationsPushedDown && + getFooterCount(schema) == 0 && getHeaderCount(schema) <= 1; // Bucketed partitions are fully loaded immediately since all files must be loaded to determine the file to bucket mapping if (tableBucketInfo.isPresent()) { diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/HdfsParquetDataSource.java b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/HdfsParquetDataSource.java index f3b83760e1c89..642f1abc117aa 100644 --- a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/HdfsParquetDataSource.java +++ b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/HdfsParquetDataSource.java @@ -20,9 +20,16 @@ import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; +import org.apache.parquet.format.Util; +import org.apache.parquet.format.converter.ParquetMetadataConverter; +import org.apache.parquet.hadoop.metadata.ColumnChunkMetaData; +import org.apache.parquet.internal.column.columnindex.ColumnIndex; +import org.apache.parquet.internal.column.columnindex.OffsetIndex; +import org.apache.parquet.internal.hadoop.metadata.IndexReference; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.Optional; import static com.facebook.presto.hive.HiveErrorCode.HIVE_CANNOT_OPEN_SPLIT; import static com.facebook.presto.hive.HiveErrorCode.HIVE_FILESYSTEM_ERROR; @@ -67,6 +74,30 @@ protected void readInternal(long position, byte[] buffer, int bufferOffset, int } } + @Override + public Optional readColumnIndex(ColumnChunkMetaData column) + throws IOException + { + IndexReference indexRef = column.getColumnIndexReference(); + if (indexRef == null) { + return Optional.empty(); + } + inputStream.seek(indexRef.getOffset()); + return Optional.of(ParquetMetadataConverter.fromParquetColumnIndex(column.getPrimitiveType(), Util.readColumnIndex(inputStream))); + } + + @Override + public Optional readOffsetIndex(ColumnChunkMetaData column) + throws IOException + { + IndexReference indexRef = column.getOffsetIndexReference(); + if (indexRef == null) { + return Optional.empty(); + } + inputStream.seek(indexRef.getOffset()); + return Optional.of(ParquetMetadataConverter.fromParquetOffsetIndex(Util.readOffsetIndex(inputStream))); + } + public static HdfsParquetDataSource buildHdfsParquetDataSource(FileSystem fileSystem, Path path, long start, long length, FileFormatDataSourceStats stats) { try { diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSourceFactory.java b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSourceFactory.java index fb1b4495f5379..00fe94538ded6 100644 --- a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSourceFactory.java +++ b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSourceFactory.java @@ -34,6 +34,7 @@ import com.facebook.presto.parquet.RichColumnDescriptor; import com.facebook.presto.parquet.cache.ParquetMetadataSource; import com.facebook.presto.parquet.predicate.Predicate; +import com.facebook.presto.parquet.reader.ColumnIndexFilterUtils; import com.facebook.presto.parquet.reader.ParquetReader; import com.facebook.presto.spi.ConnectorPageSource; import com.facebook.presto.spi.ConnectorSession; @@ -52,6 +53,7 @@ import org.apache.parquet.hadoop.metadata.BlockMetaData; import org.apache.parquet.hadoop.metadata.FileMetaData; import org.apache.parquet.hadoop.metadata.ParquetMetadata; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; import org.apache.parquet.io.ColumnIO; import org.apache.parquet.io.MessageColumnIO; import org.apache.parquet.schema.GroupType; @@ -63,6 +65,7 @@ import java.io.FileNotFoundException; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -94,6 +97,7 @@ import static com.facebook.presto.hive.HiveErrorCode.HIVE_CANNOT_OPEN_SPLIT; import static com.facebook.presto.hive.HiveErrorCode.HIVE_MISSING_DATA; import static com.facebook.presto.hive.HiveErrorCode.HIVE_PARTITION_SCHEMA_MISMATCH; +import static com.facebook.presto.hive.HiveSessionProperties.columnIndexFilterEnabled; import static com.facebook.presto.hive.HiveSessionProperties.getParquetMaxReadBlockSize; import static com.facebook.presto.hive.HiveSessionProperties.isParquetBatchReaderVerificationEnabled; import static com.facebook.presto.hive.HiveSessionProperties.isParquetBatchReadsEnabled; @@ -186,7 +190,8 @@ public Optional createPageSource( effectivePredicate, stats, hiveFileContext, - parquetMetadataSource)); + parquetMetadataSource, + columnIndexFilterEnabled(session))); } public static ConnectorPageSource createParquetPageSource( @@ -208,7 +213,8 @@ public static ConnectorPageSource createParquetPageSource( TupleDomain effectivePredicate, FileFormatDataSourceStats stats, HiveFileContext hiveFileContext, - ParquetMetadataSource parquetMetadataSource) + ParquetMetadataSource parquetMetadataSource, + boolean columnIndexFilterEnabled) { AggregatedMemoryContext systemMemoryContext = newSimpleAggregatedMemoryContext(); @@ -248,9 +254,12 @@ public static ConnectorPageSource createParquetPageSource( Predicate parquetPredicate = buildPredicate(requestedSchema, parquetTupleDomain, descriptorsByPath); final ParquetDataSource finalDataSource = dataSource; ImmutableList.Builder blocks = ImmutableList.builder(); + List blockIndexStores = new ArrayList<>(); for (BlockMetaData block : footerBlocks.build()) { - if (predicateMatches(parquetPredicate, block, finalDataSource, descriptorsByPath, parquetTupleDomain)) { + Optional columnIndexStore = ColumnIndexFilterUtils.getColumnIndexStore(parquetPredicate, finalDataSource, block, descriptorsByPath, columnIndexFilterEnabled); + if (predicateMatches(parquetPredicate, block, finalDataSource, descriptorsByPath, parquetTupleDomain, columnIndexStore, columnIndexFilterEnabled)) { blocks.add(block); + blockIndexStores.add(columnIndexStore.orElse(null)); hiveFileContext.incrementCounter("parquet.blocksRead", 1); hiveFileContext.incrementCounter("parquet.rowsRead", block.getRowCount()); hiveFileContext.incrementCounter("parquet.totalBytesRead", block.getTotalByteSize()); @@ -269,7 +278,10 @@ public static ConnectorPageSource createParquetPageSource( systemMemoryContext, maxReadBlockSize, batchReaderEnabled, - verificationEnabled); + verificationEnabled, + parquetPredicate, + blockIndexStores, + columnIndexFilterEnabled); ImmutableList.Builder namesBuilder = ImmutableList.builder(); ImmutableList.Builder typesBuilder = ImmutableList.builder(); diff --git a/presto-hive/src/test/java/com/facebook/presto/hive/HiveQueryRunner.java b/presto-hive/src/test/java/com/facebook/presto/hive/HiveQueryRunner.java index dc3252f03cf39..6b01a9a13d839 100644 --- a/presto-hive/src/test/java/com/facebook/presto/hive/HiveQueryRunner.java +++ b/presto-hive/src/test/java/com/facebook/presto/hive/HiveQueryRunner.java @@ -309,7 +309,7 @@ public static Session createMaterializeExchangesSession(Optional r ImmutableMap.of(), ImmutableMap.of())) .setSystemProperty(PARTITIONING_PROVIDER_CATALOG, HIVE_CATALOG) - .setSystemProperty(EXCHANGE_MATERIALIZATION_STRATEGY, ExchangeMaterializationStrategy.ALL.toString()) + .setSystemProperty(EXCHANGE_MATERIALIZATION_STRATEGY, ExchangeMaterializationStrategy.ALL.name()) .setSystemProperty(HASH_PARTITION_COUNT, "13") .setSystemProperty(COLOCATED_JOIN, "true") .setSystemProperty(GROUPED_EXECUTION, "true") diff --git a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveClientConfig.java b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveClientConfig.java index e3dec3b5fa76b..69f3e2b48bfa6 100644 --- a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveClientConfig.java +++ b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveClientConfig.java @@ -124,6 +124,7 @@ public void testDefaults() .setPartitionStatisticsBasedOptimizationEnabled(false) .setS3SelectPushdownEnabled(false) .setS3SelectPushdownMaxConnections(500) + .setStreamingAggregationEnabled(false) .setTemporaryStagingDirectoryEnabled(true) .setTemporaryStagingDirectoryPath("/tmp/presto-${USER}") .setTemporaryTableSchema("default") @@ -157,10 +158,12 @@ public void testDefaults() .setPartitionLeaseDuration(new Duration(0, TimeUnit.SECONDS)) .setMaterializedViewMissingPartitionsThreshold(100) .setLooseMemoryAccountingEnabled(false) + .setReadColumnIndexFilter(false) .setSizeBasedSplitWeightsEnabled(true) .setMinimumAssignedSplitWeight(0.05) .setUserDefinedTypeEncodingEnabled(false) - .setUseRecordPageSourceForCustomSplit(true)); + .setUseRecordPageSourceForCustomSplit(true) + .setFileSplittable(true)); } @Test @@ -245,6 +248,7 @@ public void testExplicitPropertyMappings() .put("hive.partition-statistics-based-optimization-enabled", "true") .put("hive.s3select-pushdown.enabled", "true") .put("hive.s3select-pushdown.max-connections", "1234") + .put("hive.streaming-aggregation-enabled", "true") .put("hive.temporary-staging-directory-enabled", "false") .put("hive.temporary-staging-directory-path", "updated") .put("hive.temporary-table-schema", "other") @@ -278,10 +282,12 @@ public void testExplicitPropertyMappings() .put("hive.loose-memory-accounting-enabled", "true") .put("hive.verbose-runtime-stats-enabled", "true") .put("hive.materialized-view-missing-partitions-threshold", "50") + .put("hive.parquet-column-index-filter-enabled", "true") .put("hive.size-based-split-weights-enabled", "false") .put("hive.user-defined-type-encoding-enabled", "true") .put("hive.minimum-assigned-split-weight", "1.0") .put("hive.use-record-page-source-for-custom-split", "false") + .put("hive.file-splittable", "false") .build(); HiveClientConfig expected = new HiveClientConfig() @@ -363,6 +369,7 @@ public void testExplicitPropertyMappings() .setPartitionStatisticsBasedOptimizationEnabled(true) .setS3SelectPushdownEnabled(true) .setS3SelectPushdownMaxConnections(1234) + .setStreamingAggregationEnabled(true) .setTemporaryStagingDirectoryEnabled(false) .setTemporaryStagingDirectoryPath("updated") .setTemporaryTableSchema("other") @@ -396,10 +403,12 @@ public void testExplicitPropertyMappings() .setPartitionLeaseDuration(new Duration(4, TimeUnit.HOURS)) .setMaterializedViewMissingPartitionsThreshold(50) .setLooseMemoryAccountingEnabled(true) + .setReadColumnIndexFilter(true) .setSizeBasedSplitWeightsEnabled(false) .setMinimumAssignedSplitWeight(1.0) .setUserDefinedTypeEncodingEnabled(true) - .setUseRecordPageSourceForCustomSplit(false); + .setUseRecordPageSourceForCustomSplit(false) + .setFileSplittable(false); ConfigAssertions.assertFullMapping(properties, expected); } diff --git a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveIntegrationSmokeTest.java b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveIntegrationSmokeTest.java index 45dbb39783393..f23cff3d4f758 100644 --- a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveIntegrationSmokeTest.java +++ b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveIntegrationSmokeTest.java @@ -83,6 +83,7 @@ import static com.facebook.presto.SystemSessionProperties.EXCHANGE_MATERIALIZATION_STRATEGY; import static com.facebook.presto.SystemSessionProperties.GROUPED_EXECUTION; import static com.facebook.presto.SystemSessionProperties.JOIN_DISTRIBUTION_TYPE; +import static com.facebook.presto.SystemSessionProperties.JOIN_REORDERING_STRATEGY; import static com.facebook.presto.SystemSessionProperties.PARTIAL_MERGE_PUSHDOWN_STRATEGY; import static com.facebook.presto.SystemSessionProperties.PARTITIONING_PROVIDER_CATALOG; import static com.facebook.presto.common.predicate.Marker.Bound.EXACTLY; @@ -123,6 +124,8 @@ import static com.facebook.presto.hive.HiveUtil.columnExtraInfo; import static com.facebook.presto.spi.security.SelectedRole.Type.ROLE; import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.BROADCAST; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.PARTITIONED; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static com.facebook.presto.sql.analyzer.FeaturesConfig.PartialMergePushdownStrategy.PUSH_THROUGH_LOW_MEMORY_OPERATORS; import static com.facebook.presto.sql.planner.optimizations.PlanNodeSearcher.searchFrom; import static com.facebook.presto.sql.planner.plan.ExchangeNode.Scope.REMOTE_MATERIALIZED; @@ -3321,7 +3324,7 @@ public void testMismatchedBucketing(Session session) " test_mismatch_bucketingN\n" + "ON key16=keyN"; - assertUpdate(withoutMismatchOptimization, writeToTableWithMoreBuckets, 15000, assertRemoteExchangesCount(4)); + assertUpdate(withoutMismatchOptimization, writeToTableWithMoreBuckets, 15000, assertRemoteExchangesCount(3)); assertQuery(withoutMismatchOptimization, "SELECT * FROM test_mismatch_bucketing_out32", "SELECT orderkey, comment, orderkey, comment, orderkey, comment from orders"); assertUpdate(withoutMismatchOptimization, "DROP TABLE IF EXISTS test_mismatch_bucketing_out32"); @@ -3340,11 +3343,19 @@ public void testMismatchedBucketing(Session session) } } + private Session noReorderJoins(Session session) + { + return Session.builder(session) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.name()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, PARTITIONED.name()) + .build(); + } + @Test public void testPartialMergePushdown() { - testPartialMergePushdown(getSession()); - testPartialMergePushdown(materializeExchangesSession); + testPartialMergePushdown(noReorderJoins(getSession())); + testPartialMergePushdown(noReorderJoins(materializeExchangesSession)); } public void testPartialMergePushdown(Session session) diff --git a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveLogicalPlanner.java b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveLogicalPlanner.java index fa48de7af4f0c..138bbbc7537c4 100644 --- a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveLogicalPlanner.java +++ b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveLogicalPlanner.java @@ -81,6 +81,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; +import static com.facebook.presto.SystemSessionProperties.JOIN_DISTRIBUTION_TYPE; import static com.facebook.presto.SystemSessionProperties.JOIN_REORDERING_STRATEGY; import static com.facebook.presto.SystemSessionProperties.OPTIMIZE_METADATA_QUERIES; import static com.facebook.presto.SystemSessionProperties.OPTIMIZE_METADATA_QUERIES_CALL_THRESHOLD; @@ -117,6 +118,7 @@ import static com.facebook.presto.hive.metastore.MetastoreUtil.toPartitionValues; import static com.facebook.presto.hive.metastore.StorageFormat.fromHiveStorageFormat; import static com.facebook.presto.parquet.ParquetTypeUtils.pushdownColumnNameForSubfield; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static com.facebook.presto.sql.analyzer.TypeSignatureProvider.fromTypes; import static com.facebook.presto.sql.planner.assertions.MatchResult.NO_MATCH; import static com.facebook.presto.sql.planner.assertions.MatchResult.match; @@ -2051,19 +2053,25 @@ public void testMaterializedViewJoinsWithOneTableAlias() MaterializedResult baseTable = computeActual(baseQuery); assertEquals(viewTable, baseTable); - assertPlan(getSession(), viewQuery, anyTree( - join(INNER, ImmutableList.of(equiJoinClause("l_nationkey", "r_nationkey")), - anyTree(PlanMatchPattern.constrainedTableScan(table1, - ImmutableMap.of( - "regionkey", multipleValues(BIGINT, ImmutableList.of(0L, 2L, 3L, 4L)), - "nationkey", multipleValues(BIGINT, - ImmutableList.of(0L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 18L, 19L, 20L, 21L, 22L, 23L))), - ImmutableMap.of("l_nationkey", "nationkey"))), - anyTree(PlanMatchPattern.constrainedTableScan(table2, - ImmutableMap.of("nationkey", multipleValues(BIGINT, - ImmutableList.of(0L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 18L, 19L, 20L, 21L, 22L, 23L))), - ImmutableMap.of("r_nationkey", "nationkey")))), - PlanMatchPattern.constrainedTableScan(view, ImmutableMap.of()))); + assertPlan( + Session.builder(getSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.name()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, FeaturesConfig.JoinDistributionType.PARTITIONED.name()) + .build(), + viewQuery, + anyTree( + join(INNER, ImmutableList.of(equiJoinClause("l_nationkey", "r_nationkey")), + anyTree(PlanMatchPattern.constrainedTableScan(table1, + ImmutableMap.of( + "regionkey", multipleValues(BIGINT, ImmutableList.of(0L, 2L, 3L, 4L)), + "nationkey", multipleValues(BIGINT, + ImmutableList.of(0L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 18L, 19L, 20L, 21L, 22L, 23L))), + ImmutableMap.of("l_nationkey", "nationkey"))), + anyTree(PlanMatchPattern.constrainedTableScan(table2, + ImmutableMap.of("nationkey", multipleValues(BIGINT, + ImmutableList.of(0L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 18L, 19L, 20L, 21L, 22L, 23L))), + ImmutableMap.of("r_nationkey", "nationkey")))), + PlanMatchPattern.constrainedTableScan(view, ImmutableMap.of()))); } finally { queryRunner.execute("DROP MATERIALIZED VIEW IF EXISTS " + view); diff --git a/presto-hive/src/test/java/com/facebook/presto/hive/TestStreamingAggregationPlan.java b/presto-hive/src/test/java/com/facebook/presto/hive/TestStreamingAggregationPlan.java new file mode 100644 index 0000000000000..5deeb894d5752 --- /dev/null +++ b/presto-hive/src/test/java/com/facebook/presto/hive/TestStreamingAggregationPlan.java @@ -0,0 +1,371 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.hive; + +import com.facebook.presto.Session; +import com.facebook.presto.spi.plan.ProjectNode; +import com.facebook.presto.sql.planner.assertions.PlanMatchPattern; +import com.facebook.presto.sql.planner.plan.ExchangeNode; +import com.facebook.presto.sql.planner.plan.OutputNode; +import com.facebook.presto.testing.QueryRunner; +import com.facebook.presto.tests.AbstractTestQueryFramework; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.testng.annotations.Test; + +import java.util.Optional; + +import static com.facebook.presto.hive.HiveQueryRunner.HIVE_CATALOG; +import static com.facebook.presto.hive.HiveSessionProperties.STREAMING_AGGREGATION_ENABLED; +import static com.facebook.presto.spi.plan.AggregationNode.Step.FINAL; +import static com.facebook.presto.spi.plan.AggregationNode.Step.PARTIAL; +import static com.facebook.presto.spi.plan.AggregationNode.Step.SINGLE; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.aggregation; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anySymbol; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anyTree; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.functionCall; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.node; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.singleGroupingSet; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.tableScan; +import static io.airlift.tpch.TpchTable.CUSTOMER; +import static io.airlift.tpch.TpchTable.LINE_ITEM; +import static io.airlift.tpch.TpchTable.NATION; +import static io.airlift.tpch.TpchTable.ORDERS; + +public class TestStreamingAggregationPlan + extends AbstractTestQueryFramework +{ + @Override + protected QueryRunner createQueryRunner() + throws Exception + { + return HiveQueryRunner.createQueryRunner( + ImmutableList.of(ORDERS, LINE_ITEM, CUSTOMER, NATION), + ImmutableMap.of("experimental.pushdown-subfields-enabled", "true"), + Optional.empty()); + } + + @Test + public void testUnsortedTable() + { + QueryRunner queryRunner = getQueryRunner(); + + try { + queryRunner.execute("CREATE TABLE test_customer WITH ( \n" + + " bucket_count = 4, bucketed_by = ARRAY['custkey'], \n" + + " partitioned_by=array['ds'], \n" + + " format = 'DWRF' ) AS \n" + + "SELECT *, '2021-07-11' as ds FROM customer LIMIT 1000\n"); + + // even with streaming aggregation enabled, non-ordered table that can't be applied streaming aggregation would use hash based aggregation + assertPlan( + streamingAggregationEnabled(), + "SELECT custkey, COUNT(*) FROM test_customer \n" + + "WHERE ds = '2021-07-11' GROUP BY 1", + aggregationPlanWithNoStreaming("test_customer", false, "custkey")); + } + finally { + queryRunner.execute("DROP TABLE IF EXISTS test_customer"); + } + } + + // bucket-keys and sorted keys + @Test + public void testBucketedAndSortedBySameKey() + { + QueryRunner queryRunner = getQueryRunner(); + + try { + queryRunner.execute("CREATE TABLE test_customer2 WITH ( \n" + + " bucket_count = 4, bucketed_by = ARRAY['custkey'], \n" + + " sorted_by = ARRAY['custkey'], partitioned_by=array['ds'], \n" + + " format = 'DWRF' ) AS \n" + + "SELECT *, '2021-07-11' as ds FROM customer LIMIT 1000\n"); + + queryRunner.execute("INSERT INTO test_customer2 \n" + + "SELECT *, '2021-07-12' as ds FROM tpch.sf1.customer LIMIT 1000"); + + // default: streaming aggregation is not turned on by default and hash based aggregation would be used + assertPlan("SELECT custkey, COUNT(*) FROM test_customer2 \n" + + "WHERE ds = '2021-07-11' GROUP BY 1", aggregationPlanWithNoStreaming("test_customer2", false, "custkey")); + + // streaming aggregation enabled + assertPlan( + streamingAggregationEnabled(), + "SELECT custkey, COUNT(*) FROM test_customer2 \n" + + "WHERE ds = '2021-07-11' GROUP BY 1", + node( + OutputNode.class, + node( + ExchangeNode.class, + aggregation( + singleGroupingSet("custkey"), + ImmutableMap.of(Optional.empty(), functionCall("count", ImmutableList.of())), + ImmutableList.of("custkey"), // streaming + ImmutableMap.of(), + Optional.empty(), + SINGLE, + tableScan("test_customer2", ImmutableMap.of("custkey", "custkey")))))); + } + finally { + queryRunner.execute("DROP TABLE IF EXISTS test_customer2"); + } + } + + @Test + public void testBucketedAndSortedByDifferentKeys() + { + QueryRunner queryRunner = getQueryRunner(); + + try { + queryRunner.execute("CREATE TABLE test_customer3 WITH ( \n" + + " bucket_count = 4, bucketed_by = ARRAY['custkey'], \n" + + " sorted_by = ARRAY['name'], partitioned_by=array['ds'], \n" + + " format = 'DWRF' ) AS \n" + + "SELECT *, '2021-07-11' as ds FROM customer LIMIT 1000\n"); + + // can't enable stream + assertPlan( + streamingAggregationEnabled(), + "SELECT custkey, COUNT(*) FROM test_customer3 \n" + + "WHERE ds = '2021-07-11' GROUP BY 1", + aggregationPlanWithNoStreaming("test_customer3", false, "custkey")); + + // can't enable stream + assertPlan( + streamingAggregationEnabled(), + "SELECT name, COUNT(*) FROM test_customer3 \n" + + "WHERE ds = '2021-07-11' GROUP BY 1", + aggregationPlanWithNoStreaming("test_customer3", true, "name")); + } + finally { + queryRunner.execute("DROP TABLE IF EXISTS test_customer3"); + } + } + + @Test + public void testBucketedByPrefixOfSortedKeys() + { + QueryRunner queryRunner = getQueryRunner(); + + try { + queryRunner.execute("CREATE TABLE test_customer4 WITH ( \n" + + " bucket_count = 4, bucketed_by = ARRAY['custkey'], \n" + + " sorted_by = ARRAY['custkey', 'name'], partitioned_by=array['ds'], \n" + + " format = 'DWRF' ) AS \n" + + "SELECT *, '2021-07-11' as ds FROM customer LIMIT 1000\n"); + + // streaming aggregation enabled + assertPlan( + streamingAggregationEnabled(), + "SELECT custkey, name, COUNT(*) FROM test_customer4 \n" + + "WHERE ds = '2021-07-11' GROUP BY 1, 2", + node( + OutputNode.class, + node( + ExchangeNode.class, + aggregation( + singleGroupingSet("custkey", "name"), + ImmutableMap.of(Optional.empty(), functionCall("count", ImmutableList.of())), + ImmutableList.of("custkey", "name"), // streaming + ImmutableMap.of(), + Optional.empty(), + SINGLE, + tableScan("test_customer4", ImmutableMap.of("custkey", "custkey", "name", "name")))))); + } + finally { + queryRunner.execute("DROP TABLE IF EXISTS test_customer4"); + } + } + + @Test + public void testSortedByPrefixOfBucketedKeys() + { + QueryRunner queryRunner = getQueryRunner(); + + try { + queryRunner.execute("CREATE TABLE test_customer5 WITH ( \n" + + " bucket_count = 4, bucketed_by = ARRAY['custkey', 'name'], \n" + + " sorted_by = ARRAY['custkey'], partitioned_by=array['ds'], \n" + + " format = 'DWRF' ) AS \n" + + "SELECT *, '2021-07-11' as ds FROM customer LIMIT 1000\n"); + + // can't enable stream + assertPlan(streamingAggregationEnabled(), + "SELECT custkey, COUNT(*) FROM test_customer5 \n" + + "WHERE ds = '2021-07-11' GROUP BY 1", aggregationPlanWithNoStreaming("test_customer5", false, "custkey")); + } + finally { + queryRunner.execute("DROP TABLE IF EXISTS test_customer5"); + } + } + + // Sorted keys and groupby keys + @Test + public void testGroupbySameKeysOfSortedbyKeys() + { + QueryRunner queryRunner = getQueryRunner(); + + try { + queryRunner.execute("CREATE TABLE test_customer6 WITH ( \n" + + " bucket_count = 4, bucketed_by = ARRAY['custkey', 'name'], \n" + + " sorted_by = ARRAY['custkey', 'name'], partitioned_by=array['ds'], \n" + + " format = 'DWRF' ) AS \n" + + "SELECT *, '2021-07-11' as ds FROM customer LIMIT 1000\n"); + + // can enable streaming aggregation + assertPlan(streamingAggregationEnabled(), + "SELECT custkey, name, COUNT(*) FROM test_customer6 \n" + + "WHERE ds = '2021-07-11' GROUP BY 1, 2", + node( + OutputNode.class, + node( + ExchangeNode.class, + aggregation( + singleGroupingSet("custkey", "name"), + ImmutableMap.of(Optional.empty(), functionCall("count", ImmutableList.of())), + ImmutableList.of("custkey", "name"), // streaming + ImmutableMap.of(), + Optional.empty(), + SINGLE, + tableScan("test_customer6", ImmutableMap.of("custkey", "custkey", "name", "name")))))); + } + finally { + queryRunner.execute("DROP TABLE IF EXISTS test_customer6"); + } + } + + @Test + public void testGroupbySupersetOfSortedKeys() + { + QueryRunner queryRunner = getQueryRunner(); + + try { + queryRunner.execute("CREATE TABLE test_customer7 WITH ( \n" + + " bucket_count = 4, bucketed_by = ARRAY['custkey'], \n" + + " sorted_by = ARRAY['custkey'], partitioned_by=array['ds'], \n" + + " format = 'DWRF' ) AS \n" + + "SELECT *, '2021-07-11' as ds FROM customer LIMIT 1000\n"); + + // can't enable streaming aggregation, but streaming aggregation session property would disable splittable + assertPlan( + streamingAggregationEnabled(), + "SELECT custkey, name, COUNT(*) FROM test_customer7 \n" + + "WHERE ds = '2021-07-11' GROUP BY 1, 2", + anyTree(aggregation( + singleGroupingSet("custkey", "name"), + // note: partial aggregation function has no parameter + ImmutableMap.of(Optional.empty(), functionCall("count", ImmutableList.of())), + ImmutableList.of(), // non-streaming + ImmutableMap.of(), + Optional.empty(), + SINGLE, + node(ProjectNode.class, tableScan("test_customer7", ImmutableMap.of("custkey", "custkey", "name", "name")))))); + } + finally { + queryRunner.execute("DROP TABLE IF EXISTS test_customer7"); + } + } + + @Test + public void testGroupbyKeysNotPrefixOfSortedKeys() + { + QueryRunner queryRunner = getQueryRunner(); + + try { + queryRunner.execute("CREATE TABLE test_customer8 WITH ( \n" + + " bucket_count = 4, bucketed_by = ARRAY['custkey', 'name'], \n" + + " sorted_by = ARRAY['custkey', 'name'], partitioned_by=array['ds'], \n" + + " format = 'DWRF' ) AS \n" + + "SELECT *, '2021-07-11' as ds FROM customer LIMIT 1000\n"); + + // can't enable streaming aggregation + assertPlan( + streamingAggregationEnabled(), + "SELECT name, COUNT(*) FROM test_customer8 \n" + + "WHERE ds = '2021-07-11' GROUP BY 1", + aggregationPlanWithNoStreaming("test_customer8", true, "name")); + } + finally { + queryRunner.execute("DROP TABLE IF EXISTS test_customer8"); + } + } + + //todo: add streaming aggregation support when grouping keys are prefix Of sorted keys + + // Partition keys + @Test + public void testQueryingMultiplePartitions() + { + QueryRunner queryRunner = getQueryRunner(); + + try { + queryRunner.execute("CREATE TABLE test_customer9 WITH ( \n" + + " bucket_count = 4, bucketed_by = ARRAY['custkey'], \n" + + " sorted_by = ARRAY['custkey'], partitioned_by=array['ds'], \n" + + " format = 'DWRF' ) AS \n" + + "SELECT *, '2021-07-11' as ds FROM customer LIMIT 1000\n"); + queryRunner.execute("INSERT INTO test_customer9 \n" + + "SELECT *, '2021-07-12' as ds FROM tpch.sf1.customer LIMIT 1000"); + + // can't enable streaming aggregation when querying multiple partitions without grouping by partition keys + assertPlan( + streamingAggregationEnabled(), + "SELECT custkey, COUNT(*) FROM test_customer9 \n" + + "WHERE ds = '2021-07-11' or ds = '2021-07-12' GROUP BY 1", + aggregationPlanWithNoStreaming("test_customer9", false, "custkey")); + + //todo: add streaming aggregation support when grouping keys contain all of the partition keys + } + finally { + queryRunner.execute("DROP TABLE IF EXISTS test_customer9"); + } + } + + private Session streamingAggregationEnabled() + { + return Session.builder(getQueryRunner().getDefaultSession()) + .setCatalogSessionProperty(HIVE_CATALOG, STREAMING_AGGREGATION_ENABLED, "true") + .build(); + } + + private PlanMatchPattern aggregationPlanWithNoStreaming(String tableName, boolean hasProject, String... groupingKeys) + { + ImmutableMap.Builder columnReferencesBuilder = ImmutableMap.builder(); + for (String groupingKey : groupingKeys) { + columnReferencesBuilder.put(groupingKey, groupingKey); + } + PlanMatchPattern tableScanPattern = tableScan(tableName, columnReferencesBuilder.build()); + + return anyTree(aggregation( + singleGroupingSet(groupingKeys), + // note: final aggregation function's parameter is of size one + ImmutableMap.of(Optional.empty(), functionCall("count", false, ImmutableList.of(anySymbol()))), + ImmutableList.of(), // non-streaming + ImmutableMap.of(), + Optional.empty(), + FINAL, + node( + ExchangeNode.class, + anyTree(aggregation( + singleGroupingSet(groupingKeys), + // note: partial aggregation function has no parameter + ImmutableMap.of(Optional.empty(), functionCall("count", ImmutableList.of())), + ImmutableList.of(), // non-streaming + ImmutableMap.of(), + Optional.empty(), + PARTIAL, + hasProject ? node(ProjectNode.class, tableScanPattern) : tableScanPattern))))); + } +} diff --git a/presto-hive/src/test/java/com/facebook/presto/hive/parquet/BenchmarkParquetPageSource.java b/presto-hive/src/test/java/com/facebook/presto/hive/parquet/BenchmarkParquetPageSource.java index 5680c65d299ef..bbff04916d096 100644 --- a/presto-hive/src/test/java/com/facebook/presto/hive/parquet/BenchmarkParquetPageSource.java +++ b/presto-hive/src/test/java/com/facebook/presto/hive/parquet/BenchmarkParquetPageSource.java @@ -290,8 +290,7 @@ ParquetPageSource createParquetPageSource() fields.add(ColumnIOConverter.constructField(getTypeFromTypeSignature(), messageColumnIO.getChild(i))); } - ParquetReader parquetReader = new ParquetReader(messageColumnIO, parquetMetadata.getBlocks(), dataSource, newSimpleAggregatedMemoryContext(), new DataSize(16, MEGABYTE), batchReadEnabled, enableVerification); - + ParquetReader parquetReader = new ParquetReader(messageColumnIO, parquetMetadata.getBlocks(), dataSource, newSimpleAggregatedMemoryContext(), new DataSize(16, MEGABYTE), batchReadEnabled, enableVerification, null, null, false); return new ParquetPageSource(parquetReader, Collections.nCopies(channelCount, type), fields, columnNames, new RuntimeStats()); } diff --git a/presto-i18n-functions/pom.xml b/presto-i18n-functions/pom.xml index 9c3c63be8b978..e4d960491095e 100644 --- a/presto-i18n-functions/pom.xml +++ b/presto-i18n-functions/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-i18n-functions diff --git a/presto-iceberg/pom.xml b/presto-iceberg/pom.xml index b7dc4c8fec93b..79c8e4fe987d1 100644 --- a/presto-iceberg/pom.xml +++ b/presto-iceberg/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-iceberg Presto - Iceberg Connector diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/HiveTableOperations.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/HiveTableOperations.java index 78bc184794095..5ddc7c8437a93 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/HiveTableOperations.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/HiveTableOperations.java @@ -29,6 +29,9 @@ import com.facebook.presto.spi.SchemaTableName; import com.facebook.presto.spi.TableNotFoundException; import com.facebook.presto.spi.security.PrestoPrincipal; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMultimap; import org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe; import org.apache.hadoop.mapred.FileInputFormat; @@ -53,7 +56,9 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.ReentrantLock; import static com.facebook.presto.hive.HiveMetadata.TABLE_COMMENT; import static com.facebook.presto.hive.metastore.HivePrivilegeInfo.HivePrivilege.DELETE; @@ -104,6 +109,8 @@ public class HiveTableOperations private boolean shouldRefresh = true; private int version = -1; + private static LoadingCache commitLockCache; + public HiveTableOperations( ExtendedHiveMetastore metastore, MetastoreContext metastoreContext, @@ -156,6 +163,24 @@ private HiveTableOperations( this.tableName = requireNonNull(table, "table is null"); this.owner = requireNonNull(owner, "owner is null"); this.location = requireNonNull(location, "location is null"); + //TODO: duration from config + initTableLevelLockCache(TimeUnit.MINUTES.toMillis(10)); + } + + private static synchronized void initTableLevelLockCache(long evictionTimeout) + { + if (commitLockCache == null) { + commitLockCache = CacheBuilder.newBuilder() + .expireAfterAccess(evictionTimeout, TimeUnit.MILLISECONDS) + .build( + new CacheLoader() { + @Override + public ReentrantLock load(String fullName) + { + return new ReentrantLock(); + } + }); + } } @Override @@ -208,72 +233,88 @@ public void commit(@Nullable TableMetadata base, TableMetadata metadata) String newMetadataLocation = writeNewMetadata(metadata, version + 1); - // TODO: use metastore locking - Table table; + // getting a process-level lock per table to avoid concurrent commit attempts to the same table from the same + // JVM process, which would result in unnecessary and costly HMS lock acquisition requests + Optional lockId = Optional.empty(); + ReentrantLock tableLevelMutex = commitLockCache.getUnchecked(database + "." + tableName); + tableLevelMutex.lock(); try { - if (base == null) { - String tableComment = metadata.properties().get(TABLE_COMMENT); - Map parameters = new HashMap<>(); - parameters.put("EXTERNAL", "TRUE"); - parameters.put(TABLE_TYPE_PROP, ICEBERG_TABLE_TYPE_VALUE); - parameters.put(METADATA_LOCATION, newMetadataLocation); - if (tableComment != null) { - parameters.put(TABLE_COMMENT, tableComment); + try { + lockId = Optional.of(metastore.lock(metastoreContext, database, tableName)); + if (base == null) { + String tableComment = metadata.properties().get(TABLE_COMMENT); + Map parameters = new HashMap<>(); + parameters.put("EXTERNAL", "TRUE"); + parameters.put(TABLE_TYPE_PROP, ICEBERG_TABLE_TYPE_VALUE); + parameters.put(METADATA_LOCATION, newMetadataLocation); + if (tableComment != null) { + parameters.put(TABLE_COMMENT, tableComment); + } + Table.Builder builder = Table.builder() + .setDatabaseName(database) + .setTableName(tableName) + .setOwner(owner.orElseThrow(() -> new IllegalStateException("Owner not set"))) + .setTableType(PrestoTableType.EXTERNAL_TABLE) + .setDataColumns(toHiveColumns(metadata.schema().columns())) + .withStorage(storage -> storage.setLocation(metadata.location())) + .withStorage(storage -> storage.setStorageFormat(STORAGE_FORMAT)) + .setParameters(parameters); + table = builder.build(); } - Table.Builder builder = Table.builder() - .setDatabaseName(database) - .setTableName(tableName) - .setOwner(owner.orElseThrow(() -> new IllegalStateException("Owner not set"))) - .setTableType(PrestoTableType.EXTERNAL_TABLE) - .setDataColumns(toHiveColumns(metadata.schema().columns())) - .withStorage(storage -> storage.setLocation(metadata.location())) - .withStorage(storage -> storage.setStorageFormat(STORAGE_FORMAT)) - .setParameters(parameters); - table = builder.build(); - } - else { - Table currentTable = getTable(); - checkState(currentMetadataLocation != null, "No current metadata location for existing table"); - String metadataLocation = currentTable.getParameters().get(METADATA_LOCATION); - if (!currentMetadataLocation.equals(metadataLocation)) { - throw new CommitFailedException("Metadata location [%s] is not same as table metadata location [%s] for %s", currentMetadataLocation, metadataLocation, getSchemaTableName()); + else { + Table currentTable = getTable(); + checkState(currentMetadataLocation != null, "No current metadata location for existing table"); + String metadataLocation = currentTable.getParameters().get(METADATA_LOCATION); + if (!currentMetadataLocation.equals(metadataLocation)) { + throw new CommitFailedException("Metadata location [%s] is not same as table metadata location [%s] for %s", currentMetadataLocation, metadataLocation, getSchemaTableName()); + } + table = Table.builder(currentTable) + .setDataColumns(toHiveColumns(metadata.schema().columns())) + .withStorage(storage -> storage.setLocation(metadata.location())) + .setParameter(METADATA_LOCATION, newMetadataLocation) + .setParameter(PREVIOUS_METADATA_LOCATION, currentMetadataLocation) + .build(); } - table = Table.builder(currentTable) - .setDataColumns(toHiveColumns(metadata.schema().columns())) - .withStorage(storage -> storage.setLocation(metadata.location())) - .setParameter(METADATA_LOCATION, newMetadataLocation) - .setParameter(PREVIOUS_METADATA_LOCATION, currentMetadataLocation) - .build(); - } - } - catch (RuntimeException e) { - try { - io().deleteFile(newMetadataLocation); } - catch (RuntimeException exception) { - e.addSuppressed(exception); + catch (RuntimeException e) { + try { + io().deleteFile(newMetadataLocation); + } + catch (RuntimeException exception) { + e.addSuppressed(exception); + } + throw e; } - throw e; - } - PrestoPrincipal owner = new PrestoPrincipal(USER, table.getOwner()); - PrincipalPrivileges privileges = new PrincipalPrivileges( - ImmutableMultimap.builder() + PrestoPrincipal owner = new PrestoPrincipal(USER, table.getOwner()); + PrincipalPrivileges privileges = new PrincipalPrivileges( + ImmutableMultimap.builder() .put(table.getOwner(), new HivePrivilegeInfo(SELECT, true, owner, owner)) .put(table.getOwner(), new HivePrivilegeInfo(INSERT, true, owner, owner)) .put(table.getOwner(), new HivePrivilegeInfo(UPDATE, true, owner, owner)) .put(table.getOwner(), new HivePrivilegeInfo(DELETE, true, owner, owner)) .build(), - ImmutableMultimap.of()); - if (base == null) { - metastore.createTable(metastoreContext, table, privileges); + ImmutableMultimap.of()); + if (base == null) { + metastore.createTable(metastoreContext, table, privileges); + } + else { + metastore.replaceTable(metastoreContext, database, tableName, table, privileges); + } } - else { - metastore.replaceTable(metastoreContext, database, tableName, table, privileges); + finally { + shouldRefresh = true; + try { + lockId.ifPresent(id -> metastore.unlock(metastoreContext, id)); + } + catch (Exception e) { + log.error(e, "Failed to unlock: %s", lockId.orElse(null)); + } + finally { + tableLevelMutex.unlock(); + } } - - shouldRefresh = true; } @Override diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java new file mode 100644 index 0000000000000..c11e7aa6cbfb7 --- /dev/null +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java @@ -0,0 +1,312 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.iceberg; + +import com.facebook.airlift.json.JsonCodec; +import com.facebook.airlift.log.Logger; +import com.facebook.presto.common.type.TypeManager; +import com.facebook.presto.hive.HiveWrittenPartitions; +import com.facebook.presto.spi.ColumnHandle; +import com.facebook.presto.spi.ColumnMetadata; +import com.facebook.presto.spi.ConnectorInsertTableHandle; +import com.facebook.presto.spi.ConnectorNewTableLayout; +import com.facebook.presto.spi.ConnectorOutputTableHandle; +import com.facebook.presto.spi.ConnectorSession; +import com.facebook.presto.spi.ConnectorTableHandle; +import com.facebook.presto.spi.ConnectorTableLayout; +import com.facebook.presto.spi.ConnectorTableLayoutHandle; +import com.facebook.presto.spi.ConnectorTableLayoutResult; +import com.facebook.presto.spi.ConnectorTableMetadata; +import com.facebook.presto.spi.Constraint; +import com.facebook.presto.spi.PrestoException; +import com.facebook.presto.spi.SchemaTableName; +import com.facebook.presto.spi.SchemaTablePrefix; +import com.facebook.presto.spi.SystemTable; +import com.facebook.presto.spi.TableNotFoundException; +import com.facebook.presto.spi.connector.ConnectorMetadata; +import com.facebook.presto.spi.connector.ConnectorOutputMetadata; +import com.facebook.presto.spi.statistics.ComputedStatistics; +import com.google.common.base.VerifyException; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import io.airlift.slice.Slice; +import org.apache.iceberg.AppendFiles; +import org.apache.iceberg.DataFiles; +import org.apache.iceberg.PartitionSpecParser; +import org.apache.iceberg.Schema; +import org.apache.iceberg.SchemaParser; +import org.apache.iceberg.Transaction; +import org.apache.iceberg.types.Type; +import org.apache.iceberg.types.TypeUtil; +import org.apache.iceberg.types.Types; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import static com.facebook.presto.common.type.BigintType.BIGINT; +import static com.facebook.presto.iceberg.IcebergTableProperties.FILE_FORMAT_PROPERTY; +import static com.facebook.presto.iceberg.IcebergTableProperties.PARTITIONING_PROPERTY; +import static com.facebook.presto.iceberg.IcebergUtil.getColumns; +import static com.facebook.presto.iceberg.IcebergUtil.getFileFormat; +import static com.facebook.presto.iceberg.IcebergUtil.resolveSnapshotIdByName; +import static com.facebook.presto.iceberg.PartitionFields.toPartitionFields; +import static com.facebook.presto.iceberg.TypeConverter.toIcebergType; +import static com.facebook.presto.iceberg.TypeConverter.toPrestoType; +import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static java.util.Collections.singletonList; +import static java.util.Objects.requireNonNull; + +public abstract class IcebergAbstractMetadata + implements ConnectorMetadata +{ + private static final Logger log = Logger.get(IcebergAbstractMetadata.class); + + protected final TypeManager typeManager; + protected final JsonCodec commitTaskCodec; + + protected final Map> snapshotIds = new ConcurrentHashMap<>(); + + protected Transaction transaction; + + public IcebergAbstractMetadata(TypeManager typeManager, JsonCodec commitTaskCodec) + { + this.typeManager = requireNonNull(typeManager, "typeManager is null"); + this.commitTaskCodec = requireNonNull(commitTaskCodec, "commitTaskCodec is null"); + } + + @Override + public List getTableLayouts(ConnectorSession session, ConnectorTableHandle table, Constraint constraint, Optional> desiredColumns) + { + IcebergTableHandle handle = (IcebergTableHandle) table; + ConnectorTableLayout layout = new ConnectorTableLayout(new IcebergTableLayoutHandle(handle, constraint.getSummary())); + return ImmutableList.of(new ConnectorTableLayoutResult(layout, constraint.getSummary())); + } + + @Override + public ConnectorTableLayout getTableLayout(ConnectorSession session, ConnectorTableLayoutHandle handle) + { + return new ConnectorTableLayout(handle); + } + + protected Optional getIcebergSystemTable(SchemaTableName tableName, org.apache.iceberg.Table table) + { + IcebergTableName name = IcebergTableName.from(tableName.getTableName()); + SchemaTableName systemTableName = new SchemaTableName(tableName.getSchemaName(), name.getTableNameWithType()); + Optional snapshotId = resolveSnapshotIdByName(table, name); + + switch (name.getTableType()) { + case DATA: + break; + case HISTORY: + if (name.getSnapshotId().isPresent()) { + throw new PrestoException(NOT_SUPPORTED, "Snapshot ID not supported for history table: " + systemTableName); + } + // make sure Hadoop FileSystem initialized in classloader-safe context + table.refresh(); + return Optional.of(new HistoryTable(systemTableName, table)); + case SNAPSHOTS: + if (name.getSnapshotId().isPresent()) { + throw new PrestoException(NOT_SUPPORTED, "Snapshot ID not supported for snapshots table: " + systemTableName); + } + table.refresh(); + return Optional.of(new SnapshotsTable(systemTableName, typeManager, table)); + case PARTITIONS: + return Optional.of(new PartitionTable(systemTableName, typeManager, table, snapshotId)); + case MANIFESTS: + return Optional.of(new ManifestsTable(systemTableName, table, snapshotId)); + case FILES: + return Optional.of(new FilesTable(systemTableName, table, snapshotId, typeManager)); + } + return Optional.empty(); + } + + @Override + public ConnectorTableMetadata getTableMetadata(ConnectorSession session, ConnectorTableHandle table) + { + return getTableMetadata(session, ((IcebergTableHandle) table).getSchemaTableName()); + } + + protected abstract ConnectorTableMetadata getTableMetadata(ConnectorSession session, SchemaTableName table); + + @Override + public Map> listTableColumns(ConnectorSession session, SchemaTablePrefix prefix) + { + List tables = prefix.getTableName() != null ? singletonList(prefix.toSchemaTableName()) : listTables(session, Optional.of(prefix.getSchemaName())); + + ImmutableMap.Builder> columns = ImmutableMap.builder(); + for (SchemaTableName table : tables) { + try { + columns.put(table, getTableMetadata(session, table).getColumns()); + } + catch (TableNotFoundException e) { + log.warn(String.format("table disappeared during listing operation: %s", e.getMessage())); + } + catch (UnknownTableTypeException e) { + log.warn(String.format("%s: Unknown table type of table %s", e.getMessage(), table.getTableName())); + } + } + return columns.build(); + } + + @Override + public ColumnMetadata getColumnMetadata(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnHandle columnHandle) + { + IcebergColumnHandle column = (IcebergColumnHandle) columnHandle; + return ColumnMetadata.builder() + .setName(column.getName()) + .setType(column.getType()) + .setComment(column.getComment()) + .setHidden(false) + .build(); + } + + @Override + public void createTable(ConnectorSession session, ConnectorTableMetadata tableMetadata, boolean ignoreExisting) + { + Optional layout = getNewTableLayout(session, tableMetadata); + finishCreateTable(session, beginCreateTable(session, tableMetadata, layout), ImmutableList.of(), ImmutableList.of()); + } + + @Override + public Optional finishCreateTable(ConnectorSession session, ConnectorOutputTableHandle tableHandle, Collection fragments, Collection computedStatistics) + { + return finishInsert(session, (IcebergWritableTableHandle) tableHandle, fragments, computedStatistics); + } + + protected ConnectorInsertTableHandle beginIcebergTableInsert(IcebergTableHandle table, org.apache.iceberg.Table icebergTable) + { + transaction = icebergTable.newTransaction(); + + return new IcebergWritableTableHandle( + table.getSchemaName(), + table.getTableName(), + SchemaParser.toJson(icebergTable.schema()), + PartitionSpecParser.toJson(icebergTable.spec()), + getColumns(icebergTable.schema(), typeManager), + icebergTable.location(), + getFileFormat(icebergTable), + icebergTable.properties()); + } + + @Override + public Optional finishInsert(ConnectorSession session, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics) + { + if (fragments.isEmpty()) { + transaction.commitTransaction(); + return Optional.empty(); + } + + IcebergWritableTableHandle table = (IcebergWritableTableHandle) insertHandle; + org.apache.iceberg.Table icebergTable = transaction.table(); + + List commitTasks = fragments.stream() + .map(slice -> commitTaskCodec.fromJson(slice.getBytes())) + .collect(toImmutableList()); + + Type[] partitionColumnTypes = icebergTable.spec().fields().stream() + .map(field -> field.transform().getResultType( + icebergTable.schema().findType(field.sourceId()))) + .toArray(Type[]::new); + + AppendFiles appendFiles = transaction.newFastAppend(); + for (CommitTaskData task : commitTasks) { + DataFiles.Builder builder = DataFiles.builder(icebergTable.spec()) + .withPath(task.getPath()) + .withFileSizeInBytes(task.getFileSizeInBytes()) + .withFormat(table.getFileFormat()) + .withMetrics(task.getMetrics().metrics()); + + if (!icebergTable.spec().fields().isEmpty()) { + String partitionDataJson = task.getPartitionDataJson() + .orElseThrow(() -> new VerifyException("No partition data for partitioned table")); + builder.withPartition(PartitionData.fromJson(partitionDataJson, partitionColumnTypes)); + } + + appendFiles.appendFile(builder.build()); + } + + appendFiles.commit(); + transaction.commitTransaction(); + + return Optional.of(new HiveWrittenPartitions(commitTasks.stream() + .map(CommitTaskData::getPath) + .collect(toImmutableList()))); + } + + @Override + public ColumnHandle getUpdateRowIdColumnHandle(ConnectorSession session, ConnectorTableHandle tableHandle) + { + return new IcebergColumnHandle(0, "$row_id", BIGINT, Optional.empty()); + } + + @Override + public ConnectorTableHandle beginDelete(ConnectorSession session, ConnectorTableHandle tableHandle) + { + throw new PrestoException(NOT_SUPPORTED, "This connector only supports delete where one or more partitions are deleted entirely"); + } + + protected List getColumnMetadatas(org.apache.iceberg.Table table) + { + return table.schema().columns().stream() + .map(column -> ColumnMetadata.builder() + .setName(column.name()) + .setType(toPrestoType(column.type(), typeManager)) + .setComment(Optional.ofNullable(column.doc())) + .setHidden(false) + .build()) + .collect(toImmutableList()); + } + + protected ImmutableMap createMetadataProperties(org.apache.iceberg.Table icebergTable) + { + ImmutableMap.Builder properties = ImmutableMap.builder(); + properties.put(FILE_FORMAT_PROPERTY, getFileFormat(icebergTable)); + if (!icebergTable.spec().fields().isEmpty()) { + properties.put(PARTITIONING_PROPERTY, toPartitionFields(icebergTable.spec())); + } + + return properties.build(); + } + + protected static Schema toIcebergSchema(List columns) + { + List icebergColumns = new ArrayList<>(); + for (ColumnMetadata column : columns) { + if (!column.isHidden()) { + int index = icebergColumns.size(); + Type type = toIcebergType(column.getType()); + Types.NestedField field = column.isNullable() + ? Types.NestedField.optional(index, column.getName(), type, column.getComment()) + : Types.NestedField.required(index, column.getName(), type, column.getComment()); + icebergColumns.add(field); + } + } + Type icebergSchema = Types.StructType.of(icebergColumns); + AtomicInteger nextFieldId = new AtomicInteger(1); + icebergSchema = TypeUtil.assignFreshIds(icebergSchema, nextFieldId::getAndIncrement); + return new Schema(icebergSchema.asStructType().fields()); + } + + public void rollback() + { + // TODO: cleanup open transaction + } +} diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergNativeMetadata.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergHadoopMetadata.java similarity index 53% rename from presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergNativeMetadata.java rename to presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergHadoopMetadata.java index f0b36d9c35a3d..5e6f06beee668 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergNativeMetadata.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergHadoopMetadata.java @@ -14,7 +14,6 @@ package com.facebook.presto.iceberg; import com.facebook.airlift.json.JsonCodec; -import com.facebook.airlift.log.Logger; import com.facebook.presto.common.predicate.TupleDomain; import com.facebook.presto.common.type.TypeManager; import com.facebook.presto.hive.TableAlreadyExistsException; @@ -26,76 +25,49 @@ import com.facebook.presto.spi.ConnectorOutputTableHandle; import com.facebook.presto.spi.ConnectorSession; import com.facebook.presto.spi.ConnectorTableHandle; -import com.facebook.presto.spi.ConnectorTableLayout; import com.facebook.presto.spi.ConnectorTableLayoutHandle; -import com.facebook.presto.spi.ConnectorTableLayoutResult; import com.facebook.presto.spi.ConnectorTableMetadata; import com.facebook.presto.spi.Constraint; import com.facebook.presto.spi.PrestoException; import com.facebook.presto.spi.SchemaTableName; -import com.facebook.presto.spi.SchemaTablePrefix; import com.facebook.presto.spi.SystemTable; import com.facebook.presto.spi.TableNotFoundException; -import com.facebook.presto.spi.connector.ConnectorMetadata; -import com.facebook.presto.spi.connector.ConnectorOutputMetadata; -import com.facebook.presto.spi.statistics.ComputedStatistics; import com.facebook.presto.spi.statistics.TableStatistics; -import com.google.common.base.VerifyException; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import io.airlift.slice.Slice; -import org.apache.iceberg.AppendFiles; -import org.apache.iceberg.DataFiles; import org.apache.iceberg.FileFormat; import org.apache.iceberg.PartitionSpec; import org.apache.iceberg.PartitionSpecParser; import org.apache.iceberg.Schema; import org.apache.iceberg.SchemaParser; -import org.apache.iceberg.Snapshot; import org.apache.iceberg.Table; -import org.apache.iceberg.Transaction; import org.apache.iceberg.catalog.SupportsNamespaces; import org.apache.iceberg.catalog.TableIdentifier; import org.apache.iceberg.exceptions.AlreadyExistsException; import org.apache.iceberg.exceptions.NamespaceNotEmptyException; import org.apache.iceberg.exceptions.NoSuchTableException; -import org.apache.iceberg.types.Type; -import org.apache.iceberg.types.TypeUtil; -import org.apache.iceberg.types.Types; -import org.apache.iceberg.types.Types.NestedField; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import static com.facebook.presto.common.type.BigintType.BIGINT; import static com.facebook.presto.iceberg.IcebergErrorCode.ICEBERG_INVALID_SNAPSHOT_ID; -import static com.facebook.presto.iceberg.IcebergTableProperties.FILE_FORMAT_PROPERTY; -import static com.facebook.presto.iceberg.IcebergTableProperties.PARTITIONING_PROPERTY; import static com.facebook.presto.iceberg.IcebergTableProperties.getFileFormat; import static com.facebook.presto.iceberg.IcebergTableProperties.getFormatVersion; import static com.facebook.presto.iceberg.IcebergTableProperties.getPartitioning; import static com.facebook.presto.iceberg.IcebergUtil.getColumns; -import static com.facebook.presto.iceberg.IcebergUtil.getFileFormat; +import static com.facebook.presto.iceberg.IcebergUtil.getHadoopIcebergTable; import static com.facebook.presto.iceberg.IcebergUtil.getTableComment; +import static com.facebook.presto.iceberg.IcebergUtil.resolveSnapshotIdByName; import static com.facebook.presto.iceberg.PartitionFields.parsePartitionFields; -import static com.facebook.presto.iceberg.PartitionFields.toPartitionFields; import static com.facebook.presto.iceberg.TableType.DATA; import static com.facebook.presto.iceberg.TypeConverter.toIcebergType; -import static com.facebook.presto.iceberg.TypeConverter.toPrestoType; import static com.facebook.presto.iceberg.util.IcebergPrestoModelConverters.toIcebergNamespace; import static com.facebook.presto.iceberg.util.IcebergPrestoModelConverters.toIcebergTableIdentifier; import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED; import static com.facebook.presto.spi.StandardErrorCode.SCHEMA_NOT_EMPTY; import static com.google.common.base.Verify.verify; -import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; import static java.lang.String.format; -import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; import static java.util.function.Function.identity; import static java.util.stream.Collectors.toList; @@ -103,28 +75,21 @@ import static org.apache.iceberg.TableProperties.DEFAULT_FILE_FORMAT; import static org.apache.iceberg.TableProperties.FORMAT_VERSION; -public class IcebergNativeMetadata - implements ConnectorMetadata +public class IcebergHadoopMetadata + extends IcebergAbstractMetadata { - private static final Logger log = Logger.get(IcebergNativeMetadata.class); - private static final String INFORMATION_SCHEMA = "information_schema"; private static final String TABLE_COMMENT = "comment"; private final IcebergResourceFactory resourceFactory; - private final TypeManager typeManager; - private final JsonCodec commitTaskCodec; - - private Transaction transaction; - public IcebergNativeMetadata( + public IcebergHadoopMetadata( IcebergResourceFactory resourceFactory, TypeManager typeManager, JsonCodec commitTaskCodec) { + super(typeManager, commitTaskCodec); this.resourceFactory = requireNonNull(resourceFactory, "resourceFactory is null"); - this.typeManager = requireNonNull(typeManager, "typeManager is null"); - this.commitTaskCodec = requireNonNull(commitTaskCodec, "commitTaskCodec is null"); } @Override @@ -157,35 +122,10 @@ public IcebergTableHandle getTableHandle(ConnectorSession session, SchemaTableNa tableName.getSchemaName(), name.getTableName(), name.getTableType(), - resolveSnapshotId(name, table), + resolveSnapshotIdByName(table, name), TupleDomain.all()); } - private Optional resolveSnapshotId(IcebergTableName name, Table table) - { - if (name.getSnapshotId().isPresent()) { - if (table.snapshot(name.getSnapshotId().get()) == null) { - throw new PrestoException(ICEBERG_INVALID_SNAPSHOT_ID, format("Invalid snapshot [%s] for table: %s", name.getSnapshotId().get(), table)); - } - return name.getSnapshotId(); - } - return Optional.ofNullable(table.currentSnapshot()).map(Snapshot::snapshotId); - } - - @Override - public List getTableLayouts(ConnectorSession session, ConnectorTableHandle table, Constraint constraint, Optional> desiredColumns) - { - IcebergTableHandle handle = (IcebergTableHandle) table; - ConnectorTableLayout layout = new ConnectorTableLayout(new IcebergTableLayoutHandle(handle, constraint.getSummary())); - return ImmutableList.of(new ConnectorTableLayoutResult(layout, constraint.getSummary())); - } - - @Override - public ConnectorTableLayout getTableLayout(ConnectorSession session, ConnectorTableLayoutHandle handle) - { - return new ConnectorTableLayout(handle); - } - @Override public Optional getSystemTable(ConnectorSession session, SchemaTableName tableName) { @@ -203,35 +143,7 @@ public Optional getSystemTable(ConnectorSession session, SchemaTabl throw new PrestoException(ICEBERG_INVALID_SNAPSHOT_ID, format("Invalid snapshot [%s] for table: %s", name.getSnapshotId().get(), table)); } - SchemaTableName systemTableName = new SchemaTableName(tableName.getSchemaName(), name.getTableNameWithType()); - Optional snapshotId = resolveSnapshotId(name, table); - switch (name.getTableType()) { - case HISTORY: - if (name.getSnapshotId().isPresent()) { - throw new PrestoException(NOT_SUPPORTED, "Snapshot ID not supported for history table: " + systemTableName); - } - return Optional.of(new HistoryTable(systemTableName, table)); - case SNAPSHOTS: - if (name.getSnapshotId().isPresent()) { - throw new PrestoException(NOT_SUPPORTED, "Snapshot ID not supported for snapshots table: " + systemTableName); - } - return Optional.of(new SnapshotsTable(systemTableName, typeManager, table)); - case PARTITIONS: - return Optional.of(new PartitionTable(systemTableName, typeManager, table, snapshotId)); - case MANIFESTS: - return Optional.of(new ManifestsTable(systemTableName, table, snapshotId)); - case FILES: - return Optional.of(new FilesTable(systemTableName, table, snapshotId, typeManager)); - case DATA: // data tables are not system tables - default: - return Optional.empty(); - } - } - - @Override - public ConnectorTableMetadata getTableMetadata(ConnectorSession session, ConnectorTableHandle table) - { - return getTableMetadata(session, ((IcebergTableHandle) table).getSchemaTableName()); + return getIcebergSystemTable(tableName, table); } @Override @@ -253,7 +165,7 @@ public List listTables(ConnectorSession session, Optional getColumnHandles(ConnectorSession session, ConnectorTableHandle tableHandle) { IcebergTableHandle table = (IcebergTableHandle) tableHandle; - Table icebergTable = resourceFactory.getCatalog(session).loadTable(toIcebergTableIdentifier(table.getSchemaTableName())); + Table icebergTable = getHadoopIcebergTable(resourceFactory, session, table.getSchemaTableName()); return getColumns(icebergTable.schema(), typeManager).stream() .collect(toImmutableMap(IcebergColumnHandle::getName, identity())); } @@ -270,26 +182,6 @@ public ColumnMetadata getColumnMetadata(ConnectorSession session, ConnectorTable .build(); } - @Override - public Map> listTableColumns(ConnectorSession session, SchemaTablePrefix prefix) - { - List tables = prefix.getTableName() != null ? singletonList(prefix.toSchemaTableName()) : listTables(session, Optional.of(prefix.getSchemaName())); - - ImmutableMap.Builder> columns = ImmutableMap.builder(); - for (SchemaTableName table : tables) { - try { - columns.put(table, getTableMetadata(session, table).getColumns()); - } - catch (TableNotFoundException e) { - log.warn(String.format("table disappeared during listing operation: %s", e.getMessage())); - } - catch (UnknownTableTypeException e) { - log.warn(String.format("%s: Unknown table type of table %s", e.getMessage(), table.getTableName())); - } - } - return columns.build(); - } - @Override public void createSchema(ConnectorSession session, String schemaName, Map properties) { @@ -312,14 +204,7 @@ public void dropSchema(ConnectorSession session, String schemaName) @Override public void renameSchema(ConnectorSession session, String source, String target) { - throw new PrestoException(NOT_SUPPORTED, "Iceberg native catalog does not support rename namespace"); - } - - @Override - public void createTable(ConnectorSession session, ConnectorTableMetadata tableMetadata, boolean ignoreExisting) - { - Optional layout = getNewTableLayout(session, tableMetadata); - finishCreateTable(session, beginCreateTable(session, tableMetadata, layout), ImmutableList.of(), ImmutableList.of()); + throw new PrestoException(NOT_SUPPORTED, "Iceberg hadoop catalog does not support rename namespace"); } @Override @@ -364,80 +249,13 @@ public ConnectorOutputTableHandle beginCreateTable(ConnectorSession session, Con icebergTable.properties()); } - @Override - public Optional finishCreateTable(ConnectorSession session, ConnectorOutputTableHandle tableHandle, Collection fragments, Collection computedStatistics) - { - return finishInsert(session, (IcebergWritableTableHandle) tableHandle, fragments, computedStatistics); - } - @Override public ConnectorInsertTableHandle beginInsert(ConnectorSession session, ConnectorTableHandle tableHandle) { IcebergTableHandle table = (IcebergTableHandle) tableHandle; - Table icebergTable = resourceFactory.getCatalog(session).loadTable(toIcebergTableIdentifier(table.getSchemaTableName())); + Table icebergTable = getHadoopIcebergTable(resourceFactory, session, table.getSchemaTableName()); - transaction = icebergTable.newTransaction(); - - return new IcebergWritableTableHandle( - table.getSchemaName(), - table.getTableName(), - SchemaParser.toJson(icebergTable.schema()), - PartitionSpecParser.toJson(icebergTable.spec()), - getColumns(icebergTable.schema(), typeManager), - icebergTable.location(), - getFileFormat(icebergTable), - icebergTable.properties()); - } - - @Override - public Optional finishInsert(ConnectorSession session, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics) - { - if (fragments.isEmpty()) { - transaction.commitTransaction(); - return Optional.empty(); - } - - IcebergWritableTableHandle table = (IcebergWritableTableHandle) insertHandle; - org.apache.iceberg.Table icebergTable = transaction.table(); - - List commitTasks = fragments.stream() - .map(slice -> commitTaskCodec.fromJson(slice.getBytes())) - .collect(toImmutableList()); - - Type[] partitionColumnTypes = icebergTable.spec().fields().stream() - .map(field -> field.transform().getResultType( - icebergTable.schema().findType(field.sourceId()))) - .toArray(Type[]::new); - - AppendFiles appendFiles = transaction.newFastAppend(); - for (CommitTaskData task : commitTasks) { - DataFiles.Builder builder = DataFiles.builder(icebergTable.spec()) - .withPath(task.getPath()) - .withFileSizeInBytes(task.getFileSizeInBytes()) - .withFormat(table.getFileFormat()) - .withMetrics(task.getMetrics().metrics()); - - if (!icebergTable.spec().fields().isEmpty()) { - String partitionDataJson = task.getPartitionDataJson() - .orElseThrow(() -> new VerifyException("No partition data for partitioned table")); - builder.withPartition(PartitionData.fromJson(partitionDataJson, partitionColumnTypes)); - } - - appendFiles.appendFile(builder.build()); - } - - appendFiles.commit(); - transaction.commitTransaction(); - - return Optional.of(new IcebergWrittenPartitions(commitTasks.stream() - .map(CommitTaskData::getPath) - .collect(toImmutableList()))); - } - - @Override - public ColumnHandle getUpdateRowIdColumnHandle(ConnectorSession session, ConnectorTableHandle tableHandle) - { - return new IcebergColumnHandle(0, "$row_id", BIGINT, Optional.empty()); + return beginIcebergTableInsert(table, icebergTable); } @Override @@ -481,11 +299,12 @@ public void renameColumn(ConnectorSession session, ConnectorTableHandle tableHan icebergTable.updateSchema().renameColumn(columnHandle.getName(), target).commit(); } - private ConnectorTableMetadata getTableMetadata(ConnectorSession session, SchemaTableName table) + @Override + protected ConnectorTableMetadata getTableMetadata(ConnectorSession session, SchemaTableName table) { Table icebergTable; try { - icebergTable = resourceFactory.getCatalog(session).loadTable(toIcebergTableIdentifier(table)); + icebergTable = getHadoopIcebergTable(resourceFactory, session, table); } catch (NoSuchTableException e) { throw new TableNotFoundException(table); @@ -493,57 +312,14 @@ private ConnectorTableMetadata getTableMetadata(ConnectorSession session, Schema List columns = getColumnMetadatas(icebergTable); - ImmutableMap.Builder properties = ImmutableMap.builder(); - properties.put(FILE_FORMAT_PROPERTY, getFileFormat(icebergTable)); - if (!icebergTable.spec().fields().isEmpty()) { - properties.put(PARTITIONING_PROPERTY, toPartitionFields(icebergTable.spec())); - } - - return new ConnectorTableMetadata(table, columns, properties.build(), getTableComment(icebergTable)); - } - - private List getColumnMetadatas(org.apache.iceberg.Table table) - { - return table.schema().columns().stream() - .map(column -> ColumnMetadata.builder() - .setName(column.name()) - .setType(toPrestoType(column.type(), typeManager)) - .setComment(Optional.ofNullable(column.doc())) - .setHidden(false) - .build()) - .collect(toImmutableList()); - } - - private static Schema toIcebergSchema(List columns) - { - List icebergColumns = new ArrayList<>(); - for (ColumnMetadata column : columns) { - if (!column.isHidden()) { - int index = icebergColumns.size(); - Type type = toIcebergType(column.getType()); - NestedField field = column.isNullable() - ? NestedField.optional(index, column.getName(), type, column.getComment()) - : NestedField.required(index, column.getName(), type, column.getComment()); - icebergColumns.add(field); - } - } - Type icebergSchema = Types.StructType.of(icebergColumns); - AtomicInteger nextFieldId = new AtomicInteger(1); - icebergSchema = TypeUtil.assignFreshIds(icebergSchema, nextFieldId::getAndIncrement); - return new Schema(icebergSchema.asStructType().fields()); - } - - @Override - public ConnectorTableHandle beginDelete(ConnectorSession session, ConnectorTableHandle tableHandle) - { - throw new PrestoException(NOT_SUPPORTED, "This connector only supports delete where one or more partitions are deleted entirely"); + return new ConnectorTableMetadata(table, columns, createMetadataProperties(icebergTable), getTableComment(icebergTable)); } @Override public TableStatistics getTableStatistics(ConnectorSession session, ConnectorTableHandle tableHandle, Optional tableLayoutHandle, List columnHandles, Constraint constraint) { IcebergTableHandle handle = (IcebergTableHandle) tableHandle; - Table icebergTable = resourceFactory.getCatalog(session).loadTable(toIcebergTableIdentifier(handle.getSchemaTableName())); + Table icebergTable = getHadoopIcebergTable(resourceFactory, session, handle.getSchemaTableName()); return TableStatisticsMaker.getTableStatistics(typeManager, constraint, handle, icebergTable); } } diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergMetadata.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergHiveMetadata.java similarity index 58% rename from presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergMetadata.java rename to presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergHiveMetadata.java index 71fbde632c853..a806d46c6a33c 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergMetadata.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergHiveMetadata.java @@ -14,13 +14,11 @@ package com.facebook.presto.iceberg; import com.facebook.airlift.json.JsonCodec; -import com.facebook.airlift.log.Logger; import com.facebook.presto.common.predicate.TupleDomain; import com.facebook.presto.common.type.TypeManager; import com.facebook.presto.hive.HdfsContext; import com.facebook.presto.hive.HdfsEnvironment; import com.facebook.presto.hive.HiveColumnConverterProvider; -import com.facebook.presto.hive.HiveWrittenPartitions; import com.facebook.presto.hive.TableAlreadyExistsException; import com.facebook.presto.hive.metastore.Database; import com.facebook.presto.hive.metastore.ExtendedHiveMetastore; @@ -33,28 +31,17 @@ import com.facebook.presto.spi.ConnectorOutputTableHandle; import com.facebook.presto.spi.ConnectorSession; import com.facebook.presto.spi.ConnectorTableHandle; -import com.facebook.presto.spi.ConnectorTableLayout; import com.facebook.presto.spi.ConnectorTableLayoutHandle; -import com.facebook.presto.spi.ConnectorTableLayoutResult; import com.facebook.presto.spi.ConnectorTableMetadata; import com.facebook.presto.spi.Constraint; import com.facebook.presto.spi.PrestoException; import com.facebook.presto.spi.SchemaNotFoundException; import com.facebook.presto.spi.SchemaTableName; -import com.facebook.presto.spi.SchemaTablePrefix; import com.facebook.presto.spi.SystemTable; import com.facebook.presto.spi.TableNotFoundException; -import com.facebook.presto.spi.connector.ConnectorMetadata; -import com.facebook.presto.spi.connector.ConnectorOutputMetadata; -import com.facebook.presto.spi.statistics.ComputedStatistics; import com.facebook.presto.spi.statistics.TableStatistics; -import com.google.common.base.VerifyException; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import io.airlift.slice.Slice; import org.apache.hadoop.fs.Path; -import org.apache.iceberg.AppendFiles; -import org.apache.iceberg.DataFiles; import org.apache.iceberg.FileFormat; import org.apache.iceberg.PartitionSpec; import org.apache.iceberg.PartitionSpecParser; @@ -63,48 +50,30 @@ import org.apache.iceberg.Snapshot; import org.apache.iceberg.TableMetadata; import org.apache.iceberg.TableOperations; -import org.apache.iceberg.Transaction; -import org.apache.iceberg.types.Type; -import org.apache.iceberg.types.TypeUtil; -import org.apache.iceberg.types.Types; -import org.apache.iceberg.types.Types.NestedField; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import static com.facebook.presto.common.type.BigintType.BIGINT; import static com.facebook.presto.hive.HiveMetadata.TABLE_COMMENT; import static com.facebook.presto.iceberg.IcebergSchemaProperties.getSchemaLocation; -import static com.facebook.presto.iceberg.IcebergTableProperties.FILE_FORMAT_PROPERTY; -import static com.facebook.presto.iceberg.IcebergTableProperties.PARTITIONING_PROPERTY; import static com.facebook.presto.iceberg.IcebergTableProperties.getFileFormat; import static com.facebook.presto.iceberg.IcebergTableProperties.getPartitioning; import static com.facebook.presto.iceberg.IcebergTableProperties.getTableLocation; import static com.facebook.presto.iceberg.IcebergUtil.getColumns; -import static com.facebook.presto.iceberg.IcebergUtil.getFileFormat; -import static com.facebook.presto.iceberg.IcebergUtil.getIcebergTable; +import static com.facebook.presto.iceberg.IcebergUtil.getHiveIcebergTable; import static com.facebook.presto.iceberg.IcebergUtil.getTableComment; import static com.facebook.presto.iceberg.IcebergUtil.isIcebergTable; import static com.facebook.presto.iceberg.PartitionFields.parsePartitionFields; -import static com.facebook.presto.iceberg.PartitionFields.toPartitionFields; import static com.facebook.presto.iceberg.TableType.DATA; import static com.facebook.presto.iceberg.TypeConverter.toIcebergType; -import static com.facebook.presto.iceberg.TypeConverter.toPrestoType; import static com.facebook.presto.spi.StandardErrorCode.INVALID_SCHEMA_PROPERTY; import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED; import static com.facebook.presto.spi.StandardErrorCode.SCHEMA_NOT_EMPTY; import static com.facebook.presto.spi.security.PrincipalType.USER; import static com.google.common.base.Verify.verify; -import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; -import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; import static java.util.function.Function.identity; import static java.util.stream.Collectors.toList; @@ -115,30 +84,21 @@ import static org.apache.iceberg.TableProperties.WRITE_NEW_DATA_LOCATION; import static org.apache.iceberg.Transactions.createTableTransaction; -public class IcebergMetadata - implements ConnectorMetadata +public class IcebergHiveMetadata + extends IcebergAbstractMetadata { - private static final Logger log = Logger.get(IcebergMetadata.class); - private final ExtendedHiveMetastore metastore; private final HdfsEnvironment hdfsEnvironment; - private final TypeManager typeManager; - private final JsonCodec commitTaskCodec; - - private final Map> snapshotIds = new ConcurrentHashMap<>(); - - private Transaction transaction; - public IcebergMetadata( + public IcebergHiveMetadata( ExtendedHiveMetastore metastore, HdfsEnvironment hdfsEnvironment, TypeManager typeManager, JsonCodec commitTaskCodec) { + super(typeManager, commitTaskCodec); this.metastore = requireNonNull(metastore, "metastore is null"); this.hdfsEnvironment = requireNonNull(hdfsEnvironment, "hdfsEnvironment is null"); - this.typeManager = requireNonNull(typeManager, "typeManager is null"); - this.commitTaskCodec = requireNonNull(commitTaskCodec, "commitTaskCodec is null"); } @Override @@ -163,7 +123,7 @@ public IcebergTableHandle getTableHandle(ConnectorSession session, SchemaTableNa throw new UnknownTableTypeException(tableName); } - org.apache.iceberg.Table table = getIcebergTable(metastore, hdfsEnvironment, session, tableName); + org.apache.iceberg.Table table = getHiveIcebergTable(metastore, hdfsEnvironment, session, tableName); Optional snapshotId = getSnapshotId(table, name.getSnapshotId()); return new IcebergTableHandle( @@ -174,20 +134,6 @@ public IcebergTableHandle getTableHandle(ConnectorSession session, SchemaTableNa TupleDomain.all()); } - @Override - public List getTableLayouts(ConnectorSession session, ConnectorTableHandle table, Constraint constraint, Optional> desiredColumns) - { - IcebergTableHandle handle = (IcebergTableHandle) table; - ConnectorTableLayout layout = new ConnectorTableLayout(new IcebergTableLayoutHandle(handle, constraint.getSummary())); - return ImmutableList.of(new ConnectorTableLayoutResult(layout, constraint.getSummary())); - } - - @Override - public ConnectorTableLayout getTableLayout(ConnectorSession session, ConnectorTableLayoutHandle handle) - { - return new ConnectorTableLayout(handle); - } - @Override public Optional getSystemTable(ConnectorSession session, SchemaTableName tableName) { @@ -204,39 +150,9 @@ private Optional getRawSystemTable(ConnectorSession session, Schema return Optional.empty(); } - org.apache.iceberg.Table table = getIcebergTable(metastore, hdfsEnvironment, session, new SchemaTableName(tableName.getSchemaName(), name.getTableName())); - - SchemaTableName systemTableName = new SchemaTableName(tableName.getSchemaName(), name.getTableNameWithType()); - switch (name.getTableType()) { - case DATA: - break; - case HISTORY: - if (name.getSnapshotId().isPresent()) { - throw new PrestoException(NOT_SUPPORTED, "Snapshot ID not supported for history table: " + systemTableName); - } - // make sure Hadoop FileSystem initialized in classloader-safe context - table.refresh(); - return Optional.of(new HistoryTable(systemTableName, table)); - case SNAPSHOTS: - if (name.getSnapshotId().isPresent()) { - throw new PrestoException(NOT_SUPPORTED, "Snapshot ID not supported for snapshots table: " + systemTableName); - } - table.refresh(); - return Optional.of(new SnapshotsTable(systemTableName, typeManager, table)); - case PARTITIONS: - return Optional.of(new PartitionTable(systemTableName, typeManager, table, getSnapshotId(table, name.getSnapshotId()))); - case MANIFESTS: - return Optional.of(new ManifestsTable(systemTableName, table, getSnapshotId(table, name.getSnapshotId()))); - case FILES: - return Optional.of(new FilesTable(systemTableName, table, getSnapshotId(table, name.getSnapshotId()), typeManager)); - } - return Optional.empty(); - } + org.apache.iceberg.Table table = getHiveIcebergTable(metastore, hdfsEnvironment, session, new SchemaTableName(tableName.getSchemaName(), name.getTableName())); - @Override - public ConnectorTableMetadata getTableMetadata(ConnectorSession session, ConnectorTableHandle table) - { - return getTableMetadata(session, ((IcebergTableHandle) table).getSchemaTableName()); + return getIcebergSystemTable(tableName, table); } @Override @@ -255,38 +171,11 @@ public List listTables(ConnectorSession session, Optional getColumnHandles(ConnectorSession session, ConnectorTableHandle tableHandle) { IcebergTableHandle table = (IcebergTableHandle) tableHandle; - org.apache.iceberg.Table icebergTable = getIcebergTable(metastore, hdfsEnvironment, session, table.getSchemaTableName()); + org.apache.iceberg.Table icebergTable = getHiveIcebergTable(metastore, hdfsEnvironment, session, table.getSchemaTableName()); return getColumns(icebergTable.schema(), typeManager).stream() .collect(toImmutableMap(IcebergColumnHandle::getName, identity())); } - @Override - public ColumnMetadata getColumnMetadata(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnHandle columnHandle) - { - IcebergColumnHandle column = (IcebergColumnHandle) columnHandle; - return new ColumnMetadata(column.getName(), column.getType(), column.getComment().orElse(""), false); - } - - @Override - public Map> listTableColumns(ConnectorSession session, SchemaTablePrefix prefix) - { - List tables = prefix.getTableName() != null ? singletonList(prefix.toSchemaTableName()) : listTables(session, Optional.of(prefix.getSchemaName())); - - ImmutableMap.Builder> columns = ImmutableMap.builder(); - for (SchemaTableName table : tables) { - try { - columns.put(table, getTableMetadata(session, table).getColumns()); - } - catch (TableNotFoundException e) { - log.warn(String.format("table disappeared during listing operation: %s", e.getMessage())); - } - catch (UnknownTableTypeException e) { - log.warn(String.format("%s: Unknown table type of table %s", e.getMessage(), table.getTableName())); - } - } - return columns.build(); - } - @Override public void createSchema(ConnectorSession session, String schemaName, Map properties) { @@ -330,13 +219,6 @@ public void renameSchema(ConnectorSession session, String source, String target) metastore.renameDatabase(metastoreContext, source, target); } - @Override - public void createTable(ConnectorSession session, ConnectorTableMetadata tableMetadata, boolean ignoreExisting) - { - Optional layout = getNewTableLayout(session, tableMetadata); - finishCreateTable(session, beginCreateTable(session, tableMetadata, layout), ImmutableList.of(), ImmutableList.of()); - } - @Override public ConnectorOutputTableHandle beginCreateTable(ConnectorSession session, ConnectorTableMetadata tableMetadata, Optional layout) { @@ -400,80 +282,13 @@ public ConnectorOutputTableHandle beginCreateTable(ConnectorSession session, Con metadata.properties()); } - @Override - public Optional finishCreateTable(ConnectorSession session, ConnectorOutputTableHandle tableHandle, Collection fragments, Collection computedStatistics) - { - return finishInsert(session, (IcebergWritableTableHandle) tableHandle, fragments, computedStatistics); - } - @Override public ConnectorInsertTableHandle beginInsert(ConnectorSession session, ConnectorTableHandle tableHandle) { IcebergTableHandle table = (IcebergTableHandle) tableHandle; - org.apache.iceberg.Table icebergTable = getIcebergTable(metastore, hdfsEnvironment, session, table.getSchemaTableName()); + org.apache.iceberg.Table icebergTable = getHiveIcebergTable(metastore, hdfsEnvironment, session, table.getSchemaTableName()); - transaction = icebergTable.newTransaction(); - - return new IcebergWritableTableHandle( - table.getSchemaName(), - table.getTableName(), - SchemaParser.toJson(icebergTable.schema()), - PartitionSpecParser.toJson(icebergTable.spec()), - getColumns(icebergTable.schema(), typeManager), - icebergTable.location(), - getFileFormat(icebergTable), - icebergTable.properties()); - } - - @Override - public Optional finishInsert(ConnectorSession session, ConnectorInsertTableHandle insertHandle, Collection fragments, Collection computedStatistics) - { - if (fragments.isEmpty()) { - transaction.commitTransaction(); - return Optional.empty(); - } - - IcebergWritableTableHandle table = (IcebergWritableTableHandle) insertHandle; - org.apache.iceberg.Table icebergTable = transaction.table(); - - List commitTasks = fragments.stream() - .map(slice -> commitTaskCodec.fromJson(slice.getBytes())) - .collect(toImmutableList()); - - Type[] partitionColumnTypes = icebergTable.spec().fields().stream() - .map(field -> field.transform().getResultType( - icebergTable.schema().findType(field.sourceId()))) - .toArray(Type[]::new); - - AppendFiles appendFiles = transaction.newFastAppend(); - for (CommitTaskData task : commitTasks) { - DataFiles.Builder builder = DataFiles.builder(icebergTable.spec()) - .withPath(task.getPath()) - .withFileSizeInBytes(task.getFileSizeInBytes()) - .withFormat(table.getFileFormat()) - .withMetrics(task.getMetrics().metrics()); - - if (!icebergTable.spec().fields().isEmpty()) { - String partitionDataJson = task.getPartitionDataJson() - .orElseThrow(() -> new VerifyException("No partition data for partitioned table")); - builder.withPartition(PartitionData.fromJson(partitionDataJson, partitionColumnTypes)); - } - - appendFiles.appendFile(builder.build()); - } - - appendFiles.commit(); - transaction.commitTransaction(); - - return Optional.of(new HiveWrittenPartitions(commitTasks.stream() - .map(CommitTaskData::getPath) - .collect(toImmutableList()))); - } - - @Override - public ColumnHandle getUpdateRowIdColumnHandle(ConnectorSession session, ConnectorTableHandle tableHandle) - { - return new IcebergColumnHandle(0, "$row_id", BIGINT, Optional.empty()); + return beginIcebergTableInsert(table, icebergTable); } @Override @@ -481,7 +296,7 @@ public void dropTable(ConnectorSession session, ConnectorTableHandle tableHandle { IcebergTableHandle handle = (IcebergTableHandle) tableHandle; // TODO: support path override in Iceberg table creation - org.apache.iceberg.Table table = getIcebergTable(metastore, hdfsEnvironment, session, handle.getSchemaTableName()); + org.apache.iceberg.Table table = getHiveIcebergTable(metastore, hdfsEnvironment, session, handle.getSchemaTableName()); if (table.properties().containsKey(OBJECT_STORE_PATH) || table.properties().containsKey(WRITE_NEW_DATA_LOCATION) || table.properties().containsKey(WRITE_METADATA_LOCATION)) { @@ -503,7 +318,7 @@ public void renameTable(ConnectorSession session, ConnectorTableHandle tableHand public void addColumn(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnMetadata column) { IcebergTableHandle handle = (IcebergTableHandle) tableHandle; - org.apache.iceberg.Table icebergTable = getIcebergTable(metastore, hdfsEnvironment, session, handle.getSchemaTableName()); + org.apache.iceberg.Table icebergTable = getHiveIcebergTable(metastore, hdfsEnvironment, session, handle.getSchemaTableName()); icebergTable.updateSchema().addColumn(column.getName(), toIcebergType(column.getType())).commit(); } @@ -512,7 +327,7 @@ public void dropColumn(ConnectorSession session, ConnectorTableHandle tableHandl { IcebergTableHandle icebergTableHandle = (IcebergTableHandle) tableHandle; IcebergColumnHandle handle = (IcebergColumnHandle) column; - org.apache.iceberg.Table icebergTable = getIcebergTable(metastore, hdfsEnvironment, session, icebergTableHandle.getSchemaTableName()); + org.apache.iceberg.Table icebergTable = getHiveIcebergTable(metastore, hdfsEnvironment, session, icebergTableHandle.getSchemaTableName()); icebergTable.updateSchema().deleteColumn(handle.getName()).commit(); } @@ -521,62 +336,22 @@ public void renameColumn(ConnectorSession session, ConnectorTableHandle tableHan { IcebergTableHandle icebergTableHandle = (IcebergTableHandle) tableHandle; IcebergColumnHandle columnHandle = (IcebergColumnHandle) source; - org.apache.iceberg.Table icebergTable = getIcebergTable(metastore, hdfsEnvironment, session, icebergTableHandle.getSchemaTableName()); + org.apache.iceberg.Table icebergTable = getHiveIcebergTable(metastore, hdfsEnvironment, session, icebergTableHandle.getSchemaTableName()); icebergTable.updateSchema().renameColumn(columnHandle.getName(), target).commit(); } - private ConnectorTableMetadata getTableMetadata(ConnectorSession session, SchemaTableName table) + @Override + protected ConnectorTableMetadata getTableMetadata(ConnectorSession session, SchemaTableName table) { MetastoreContext metastoreContext = new MetastoreContext(session.getIdentity(), session.getQueryId(), session.getClientInfo(), session.getSource(), Optional.empty(), false, HiveColumnConverterProvider.DEFAULT_COLUMN_CONVERTER_PROVIDER); if (!metastore.getTable(metastoreContext, table.getSchemaName(), table.getTableName()).isPresent()) { throw new TableNotFoundException(table); } - org.apache.iceberg.Table icebergTable = getIcebergTable(metastore, hdfsEnvironment, session, table); - + org.apache.iceberg.Table icebergTable = getHiveIcebergTable(metastore, hdfsEnvironment, session, table); List columns = getColumnMetadatas(icebergTable); - ImmutableMap.Builder properties = ImmutableMap.builder(); - properties.put(FILE_FORMAT_PROPERTY, getFileFormat(icebergTable)); - if (!icebergTable.spec().fields().isEmpty()) { - properties.put(PARTITIONING_PROPERTY, toPartitionFields(icebergTable.spec())); - } - - return new ConnectorTableMetadata(table, columns, properties.build(), getTableComment(icebergTable)); - } - - private List getColumnMetadatas(org.apache.iceberg.Table table) - { - return table.schema().columns().stream() - .map(column -> { - return new ColumnMetadata(column.name(), toPrestoType(column.type(), typeManager), column.doc(), false); - }) - .collect(toImmutableList()); - } - - private static Schema toIcebergSchema(List columns) - { - List icebergColumns = new ArrayList<>(); - for (ColumnMetadata column : columns) { - if (!column.isHidden()) { - int index = icebergColumns.size(); - Type type = toIcebergType(column.getType()); - NestedField field = column.isNullable() - ? NestedField.optional(index, column.getName(), type, column.getComment()) - : NestedField.required(index, column.getName(), type, column.getComment()); - icebergColumns.add(field); - } - } - Type icebergSchema = Types.StructType.of(icebergColumns); - AtomicInteger nextFieldId = new AtomicInteger(1); - icebergSchema = TypeUtil.assignFreshIds(icebergSchema, nextFieldId::getAndIncrement); - return new Schema(icebergSchema.asStructType().fields()); - } - - @Override - public ConnectorTableHandle beginDelete(ConnectorSession session, ConnectorTableHandle tableHandle) - { - throw new PrestoException(NOT_SUPPORTED, "This connector only supports delete where one or more partitions are deleted entirely"); + return new ConnectorTableMetadata(table, columns, createMetadataProperties(icebergTable), getTableComment(icebergTable)); } public ExtendedHiveMetastore getMetastore() @@ -584,16 +359,11 @@ public ExtendedHiveMetastore getMetastore() return metastore; } - public void rollback() - { - // TODO: cleanup open transaction - } - @Override public TableStatistics getTableStatistics(ConnectorSession session, ConnectorTableHandle tableHandle, Optional tableLayoutHandle, List columnHandles, Constraint constraint) { IcebergTableHandle handle = (IcebergTableHandle) tableHandle; - org.apache.iceberg.Table icebergTable = getIcebergTable(metastore, hdfsEnvironment, session, handle.getSchemaTableName()); + org.apache.iceberg.Table icebergTable = getHiveIcebergTable(metastore, hdfsEnvironment, session, handle.getSchemaTableName()); return TableStatisticsMaker.getTableStatistics(typeManager, constraint, handle, icebergTable); } diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergMetadataFactory.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergMetadataFactory.java index 6298b25af1153..b8cb57bcaac9f 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergMetadataFactory.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergMetadataFactory.java @@ -56,9 +56,9 @@ public ConnectorMetadata create() { switch (catalogType) { case HADOOP: - return new IcebergNativeMetadata(resourceFactory, typeManager, commitTaskCodec); + return new IcebergHadoopMetadata(resourceFactory, typeManager, commitTaskCodec); case HIVE: - return new IcebergMetadata(metastore, hdfsEnvironment, typeManager, commitTaskCodec); + return new IcebergHiveMetadata(metastore, hdfsEnvironment, typeManager, commitTaskCodec); } throw new PrestoException(NOT_SUPPORTED, "Unsupported Presto Iceberg catalog type " + catalogType); } diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergPageSourceProvider.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergPageSourceProvider.java index aab7c411753ba..a06580012cee0 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergPageSourceProvider.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergPageSourceProvider.java @@ -54,6 +54,7 @@ import com.facebook.presto.parquet.RichColumnDescriptor; import com.facebook.presto.parquet.cache.MetadataReader; import com.facebook.presto.parquet.predicate.Predicate; +import com.facebook.presto.parquet.reader.ColumnIndexFilterUtils; import com.facebook.presto.parquet.reader.ParquetReader; import com.facebook.presto.spi.ColumnHandle; import com.facebook.presto.spi.ConnectorPageSource; @@ -78,6 +79,7 @@ import org.apache.parquet.hadoop.metadata.BlockMetaData; import org.apache.parquet.hadoop.metadata.FileMetaData; import org.apache.parquet.hadoop.metadata.ParquetMetadata; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; import org.apache.parquet.io.MessageColumnIO; import org.apache.parquet.schema.MessageType; @@ -231,7 +233,8 @@ private ConnectorPageSource createDataPageSource( isParquetBatchReadsEnabled(session), isParquetBatchReaderVerificationEnabled(session), predicate, - fileFormatDataSourceStats); + fileFormatDataSourceStats, + false); case ORC: OrcReaderOptions readerOptions = new OrcReaderOptions( getOrcMaxMergeDistance(session), @@ -281,7 +284,8 @@ private static ConnectorPageSource createParquetPageSource( boolean batchReaderEnabled, boolean verificationEnabled, TupleDomain effectivePredicate, - FileFormatDataSourceStats fileFormatDataSourceStats) + FileFormatDataSourceStats fileFormatDataSourceStats, + boolean columnIndexFilterEnabled) { AggregatedMemoryContext systemMemoryContext = newSimpleAggregatedMemoryContext(); @@ -319,13 +323,16 @@ private static ConnectorPageSource createParquetPageSource( Map, RichColumnDescriptor> descriptorsByPath = getDescriptors(fileSchema, requestedSchema); TupleDomain parquetTupleDomain = getParquetTupleDomain(descriptorsByPath, effectivePredicate); Predicate parquetPredicate = buildPredicate(requestedSchema, parquetTupleDomain, descriptorsByPath); - + final ParquetDataSource finalDataSource = dataSource; List blocks = new ArrayList<>(); + List blockIndexStores = new ArrayList<>(); for (BlockMetaData block : parquetMetadata.getBlocks()) { long firstDataPage = block.getColumns().get(0).getFirstDataPageOffset(); + Optional columnIndexStore = ColumnIndexFilterUtils.getColumnIndexStore(parquetPredicate, finalDataSource, block, descriptorsByPath, columnIndexFilterEnabled); if ((firstDataPage >= start) && (firstDataPage < (start + length)) && - predicateMatches(parquetPredicate, block, dataSource, descriptorsByPath, parquetTupleDomain)) { + predicateMatches(parquetPredicate, block, dataSource, descriptorsByPath, parquetTupleDomain, columnIndexStore, columnIndexFilterEnabled)) { blocks.add(block); + blockIndexStores.add(columnIndexStore.orElse(null)); } } @@ -337,7 +344,10 @@ private static ConnectorPageSource createParquetPageSource( systemMemoryContext, maxReadBlockSize, batchReaderEnabled, - verificationEnabled); + verificationEnabled, + parquetPredicate, + blockIndexStores, + columnIndexFilterEnabled); ImmutableList.Builder namesBuilder = ImmutableList.builder(); ImmutableList.Builder prestoTypes = ImmutableList.builder(); diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergSplitManager.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergSplitManager.java index 081bd19f26324..b79740690ea46 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergSplitManager.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergSplitManager.java @@ -29,8 +29,8 @@ import static com.facebook.presto.iceberg.CatalogType.HADOOP; import static com.facebook.presto.iceberg.ExpressionConverter.toIcebergExpression; -import static com.facebook.presto.iceberg.IcebergUtil.getIcebergTable; -import static com.facebook.presto.iceberg.IcebergUtil.getNativeIcebergTable; +import static com.facebook.presto.iceberg.IcebergUtil.getHadoopIcebergTable; +import static com.facebook.presto.iceberg.IcebergUtil.getHiveIcebergTable; import static java.util.Objects.requireNonNull; public class IcebergSplitManager @@ -71,11 +71,11 @@ public ConnectorSplitSource getSplits( Table icebergTable; if (catalogType == HADOOP) { - icebergTable = getNativeIcebergTable(resourceFactory, session, table.getSchemaTableName()); + icebergTable = getHadoopIcebergTable(resourceFactory, session, table.getSchemaTableName()); } else { - ExtendedHiveMetastore metastore = ((IcebergMetadata) transactionManager.get(transaction)).getMetastore(); - icebergTable = getIcebergTable(metastore, hdfsEnvironment, session, table.getSchemaTableName()); + ExtendedHiveMetastore metastore = ((IcebergHiveMetadata) transactionManager.get(transaction)).getMetastore(); + icebergTable = getHiveIcebergTable(metastore, hdfsEnvironment, session, table.getSchemaTableName()); } TableScan tableScan = icebergTable.newScan() diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergUtil.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergUtil.java index e76188d380be0..7f4a5b6976f89 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergUtil.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergUtil.java @@ -30,6 +30,7 @@ import org.apache.iceberg.PartitionField; import org.apache.iceberg.PartitionSpec; import org.apache.iceberg.Schema; +import org.apache.iceberg.Snapshot; import org.apache.iceberg.Table; import org.apache.iceberg.TableOperations; import org.apache.iceberg.TableScan; @@ -69,7 +70,7 @@ public static boolean isIcebergTable(com.facebook.presto.hive.metastore.Table ta return ICEBERG_TABLE_TYPE_VALUE.equalsIgnoreCase(table.getParameters().get(TABLE_TYPE_PROP)); } - public static Table getIcebergTable(ExtendedHiveMetastore metastore, HdfsEnvironment hdfsEnvironment, ConnectorSession session, SchemaTableName table) + public static Table getHiveIcebergTable(ExtendedHiveMetastore metastore, HdfsEnvironment hdfsEnvironment, ConnectorSession session, SchemaTableName table) { HdfsContext hdfsContext = new HdfsContext(session, table.getSchemaName(), table.getTableName()); TableOperations operations = new HiveTableOperations( @@ -82,7 +83,7 @@ public static Table getIcebergTable(ExtendedHiveMetastore metastore, HdfsEnviron return new BaseTable(operations, quotedTableName(table)); } - public static Table getNativeIcebergTable(IcebergResourceFactory resourceFactory, ConnectorSession session, SchemaTableName table) + public static Table getHadoopIcebergTable(IcebergResourceFactory resourceFactory, ConnectorSession session, SchemaTableName table) { return resourceFactory.getCatalog(session).loadTable(toIcebergTableIdentifier(table)); } @@ -100,6 +101,17 @@ public static long resolveSnapshotId(Table table, long snapshotId) .orElseThrow(() -> new PrestoException(ICEBERG_INVALID_SNAPSHOT_ID, format("Invalid snapshot [%s] for table: %s", snapshotId, table))); } + public static Optional resolveSnapshotIdByName(Table table, IcebergTableName name) + { + if (name.getSnapshotId().isPresent()) { + if (table.snapshot(name.getSnapshotId().get()) == null) { + throw new PrestoException(ICEBERG_INVALID_SNAPSHOT_ID, format("Invalid snapshot [%s] for table: %s", name.getSnapshotId().get(), table)); + } + return name.getSnapshotId(); + } + return Optional.ofNullable(table.currentSnapshot()).map(Snapshot::snapshotId); + } + public static List getColumns(Schema schema, TypeManager typeManager) { return schema.columns().stream() diff --git a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/RollbackToSnapshotProcedure.java b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/RollbackToSnapshotProcedure.java index 8d562a172b43b..1a4ce8f32794d 100644 --- a/presto-iceberg/src/main/java/com/facebook/presto/iceberg/RollbackToSnapshotProcedure.java +++ b/presto-iceberg/src/main/java/com/facebook/presto/iceberg/RollbackToSnapshotProcedure.java @@ -31,7 +31,7 @@ import static com.facebook.presto.common.type.StandardTypes.BIGINT; import static com.facebook.presto.common.type.StandardTypes.VARCHAR; import static com.facebook.presto.iceberg.CatalogType.HADOOP; -import static com.facebook.presto.iceberg.IcebergUtil.getIcebergTable; +import static com.facebook.presto.iceberg.IcebergUtil.getHiveIcebergTable; import static com.facebook.presto.iceberg.util.IcebergPrestoModelConverters.toIcebergTableIdentifier; import static java.util.Objects.requireNonNull; @@ -87,8 +87,8 @@ public void rollbackToSnapshot(ConnectorSession clientSession, String schema, St icebergTable = resourceFactory.getCatalog(clientSession).loadTable(toIcebergTableIdentifier(schema, table)); } else { - ExtendedHiveMetastore metastore = ((IcebergMetadata) metadata).getMetastore(); - icebergTable = getIcebergTable(metastore, hdfsEnvironment, clientSession, schemaTableName); + ExtendedHiveMetastore metastore = ((IcebergHiveMetadata) metadata).getMetastore(); + icebergTable = getHiveIcebergTable(metastore, hdfsEnvironment, clientSession, schemaTableName); } icebergTable.rollback().toSnapshotId(snapshotId).commit(); } diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/IcebergQueryRunner.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/IcebergQueryRunner.java index 35faea5fecacd..1ff17819ed752 100644 --- a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/IcebergQueryRunner.java +++ b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/IcebergQueryRunner.java @@ -43,7 +43,7 @@ public static DistributedQueryRunner createIcebergQueryRunner(Map extraProperties, CatalogType catalogType) + public static DistributedQueryRunner createIcebergQueryRunner(Map extraProperties, CatalogType catalogType) throws Exception { return createIcebergQueryRunner(extraProperties, ImmutableMap.of("iceberg.catalog.type", catalogType.name())); diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributed.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestAbstractIcebergDistributed.java similarity index 88% rename from presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributed.java rename to presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestAbstractIcebergDistributed.java index 12282bc83c547..c69146a76e295 100644 --- a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributed.java +++ b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestAbstractIcebergDistributed.java @@ -22,16 +22,24 @@ import static com.facebook.presto.common.type.VarcharType.VARCHAR; import static com.facebook.presto.testing.MaterializedResult.resultBuilder; import static com.facebook.presto.testing.assertions.Assert.assertEquals; +import static java.util.Objects.requireNonNull; @Test -public class TestIcebergDistributed +public class TestAbstractIcebergDistributed extends AbstractTestDistributedQueries { + private final CatalogType catalogType; + + protected TestAbstractIcebergDistributed(CatalogType catalogType) + { + this.catalogType = requireNonNull(catalogType, "catalogType is null"); + } + @Override protected QueryRunner createQueryRunner() throws Exception { - return IcebergQueryRunner.createIcebergQueryRunner(ImmutableMap.of()); + return IcebergQueryRunner.createIcebergQueryRunner(ImmutableMap.of(), catalogType); } @Override diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributedHadoop.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributedHadoop.java new file mode 100644 index 0000000000000..7bddf15f4846d --- /dev/null +++ b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributedHadoop.java @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.iceberg; + +import org.testng.annotations.Test; + +import static com.facebook.presto.iceberg.CatalogType.HADOOP; + +@Test +public class TestIcebergDistributedHadoop + extends TestAbstractIcebergDistributed +{ + public TestIcebergDistributedHadoop() + { + super(HADOOP); + } +} diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributedHive.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributedHive.java new file mode 100644 index 0000000000000..9722852aae9b7 --- /dev/null +++ b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributedHive.java @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.iceberg; + +import org.testng.annotations.Test; + +import static com.facebook.presto.iceberg.CatalogType.HIVE; + +@Test +public class TestIcebergDistributedHive + extends TestAbstractIcebergDistributed +{ + public TestIcebergDistributedHive() + { + super(HIVE); + } +} diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributedNative.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributedNative.java deleted file mode 100644 index 636a524cdce41..0000000000000 --- a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergDistributedNative.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.facebook.presto.iceberg; - -import com.facebook.presto.testing.MaterializedResult; -import com.facebook.presto.testing.QueryRunner; -import com.facebook.presto.tests.AbstractTestDistributedQueries; -import com.google.common.collect.ImmutableMap; -import org.testng.annotations.Test; - -import static com.facebook.presto.common.type.VarcharType.VARCHAR; -import static com.facebook.presto.iceberg.CatalogType.HADOOP; -import static com.facebook.presto.testing.MaterializedResult.resultBuilder; -import static com.facebook.presto.testing.assertions.Assert.assertEquals; - -@Test -public class TestIcebergDistributedNative - extends AbstractTestDistributedQueries -{ - @Override - protected QueryRunner createQueryRunner() - throws Exception - { - return IcebergQueryRunner.createNativeIcebergQueryRunner(ImmutableMap.of(), HADOOP); - } - - @Override - protected boolean supportsViews() - { - return false; - } - - @Override - protected boolean supportsNotNullColumns() - { - return false; - } - - public void testJoinWithLessThanOnDatesInJoinClause() - { - } - - @Override - public void testRenameTable() - { - } - - @Override - public void testAddColumn() - { - } - - @Override - public void testRenameColumn() - { - } - - @Override - public void testDropColumn() - { - } - - @Override - public void testInsert() - { - } - - @Override - public void testCreateTable() - { - } - - @Override - public void testDelete() - { - } - - @Override - public void testShowColumns() - { - MaterializedResult actual = computeActual("SHOW COLUMNS FROM orders"); - - MaterializedResult expectedParametrizedVarchar = resultBuilder(getSession(), VARCHAR, VARCHAR, VARCHAR, VARCHAR) - .row("orderkey", "bigint", "", "") - .row("custkey", "bigint", "", "") - .row("orderstatus", "varchar", "", "") - .row("totalprice", "double", "", "") - .row("orderdate", "date", "", "") - .row("orderpriority", "varchar", "", "") - .row("clerk", "varchar", "", "") - .row("shippriority", "integer", "", "") - .row("comment", "varchar", "", "") - .build(); - - assertEquals(actual, expectedParametrizedVarchar); - } - - @Override - public void testDescribeOutput() - { - } - - @Override - public void testDescribeOutputNamedAndUnnamed() - { - } - - @Override - public void testWrittenStats() - { - } -} diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmoke.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmoke.java index 88a26b476e9f2..ac4f971f57318 100644 --- a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmoke.java +++ b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmoke.java @@ -23,9 +23,17 @@ import org.intellij.lang.annotations.Language; import org.testng.annotations.Test; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.facebook.presto.common.type.VarcharType.VARCHAR; import static com.facebook.presto.iceberg.IcebergQueryRunner.createIcebergQueryRunner; @@ -37,6 +45,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; public class TestIcebergSmoke extends AbstractTestIntegrationSmokeTest @@ -424,6 +433,51 @@ public void testInsertIntoNotNullColumn() // TODO: To support non-null column. (NOT_NULL_COLUMN_CONSTRAINT) } + @Test + public void testConcurrentInsert() + { + final Session session = getSession(); + assertUpdate(session, "CREATE TABLE test_concurrent_insert (col0 INTEGER, col1 VARCHAR) WITH (format = 'ORC')"); + + int concurrency = 5; + final String[] strings = {"one", "two", "three", "four", "five"}; + final CountDownLatch countDownLatch = new CountDownLatch(concurrency); + AtomicInteger value = new AtomicInteger(0); + Set errors = new CopyOnWriteArraySet<>(); + List threads = Stream.generate(() -> new Thread(() -> { + int i = value.getAndIncrement(); + try { + getQueryRunner().execute(session, format("INSERT INTO test_concurrent_insert VALUES(%s, '%s')", i + 1, strings[i])); + } + catch (Throwable throwable) { + errors.add(throwable); + } + finally { + countDownLatch.countDown(); + } + })).limit(concurrency).collect(Collectors.toList()); + + threads.forEach(Thread::start); + + try { + final int seconds = 10; + if (!countDownLatch.await(seconds, TimeUnit.SECONDS)) { + fail(format("Failed to insert in %s seconds", seconds)); + } + if (!errors.isEmpty()) { + fail(format("Failed to insert concurrently: %s", errors.stream().map(Throwable::getMessage).collect(Collectors.joining(" & ")))); + } + assertQuery(session, "SELECT count(*) FROM test_concurrent_insert", "SELECT " + concurrency); + assertQuery(session, "SELECT * FROM test_concurrent_insert", "VALUES(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'five')"); + } + catch (InterruptedException e) { + fail("Interrupted when await insertion", e); + } + finally { + dropTable(session, "test_concurrent_insert"); + } + } + @Test public void testSchemaEvolution() { diff --git a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmokeNative.java b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmokeHadoop.java similarity index 99% rename from presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmokeNative.java rename to presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmokeHadoop.java index c642c52134066..0ddea5be567d3 100644 --- a/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmokeNative.java +++ b/presto-iceberg/src/test/java/com/facebook/presto/iceberg/TestIcebergSmokeHadoop.java @@ -29,7 +29,7 @@ import static com.facebook.presto.common.type.VarcharType.VARCHAR; import static com.facebook.presto.iceberg.CatalogType.HADOOP; -import static com.facebook.presto.iceberg.IcebergQueryRunner.createNativeIcebergQueryRunner; +import static com.facebook.presto.iceberg.IcebergQueryRunner.createIcebergQueryRunner; import static com.facebook.presto.testing.MaterializedResult.resultBuilder; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.Iterables.getOnlyElement; @@ -39,7 +39,7 @@ import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; -public class TestIcebergSmokeNative +public class TestIcebergSmokeHadoop extends AbstractTestIntegrationSmokeTest { private static final Pattern WITH_CLAUSE_EXTRACTER = Pattern.compile(".*(WITH\\s*\\([^)]*\\))\\s*$", Pattern.DOTALL); @@ -48,7 +48,7 @@ public class TestIcebergSmokeNative protected QueryRunner createQueryRunner() throws Exception { - return createNativeIcebergQueryRunner(ImmutableMap.of(), HADOOP); + return createIcebergQueryRunner(ImmutableMap.of(), HADOOP); } @Test diff --git a/presto-jdbc/pom.xml b/presto-jdbc/pom.xml index cc23f85909ad6..d233b79a86406 100644 --- a/presto-jdbc/pom.xml +++ b/presto-jdbc/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-jdbc diff --git a/presto-jdbc/src/main/java/com/facebook/presto/jdbc/ConnectionProperties.java b/presto-jdbc/src/main/java/com/facebook/presto/jdbc/ConnectionProperties.java index 929d546b7a753..07717eac9c165 100644 --- a/presto-jdbc/src/main/java/com/facebook/presto/jdbc/ConnectionProperties.java +++ b/presto-jdbc/src/main/java/com/facebook/presto/jdbc/ConnectionProperties.java @@ -54,6 +54,7 @@ final class ConnectionProperties public static final ConnectionProperty KERBEROS_KEYTAB_PATH = new KerberosKeytabPath(); public static final ConnectionProperty KERBEROS_CREDENTIAL_CACHE_PATH = new KerberosCredentialCachePath(); public static final ConnectionProperty ACCESS_TOKEN = new AccessToken(); + public static final ConnectionProperty TIMEZONE_ID = new TimeZoneId(); public static final ConnectionProperty> EXTRA_CREDENTIALS = new ExtraCredentials(); public static final ConnectionProperty> CUSTOM_HEADERS = new CustomHeaders(); public static final ConnectionProperty> SESSION_PROPERTIES = new SessionProperties(); @@ -79,6 +80,7 @@ final class ConnectionProperties .add(KERBEROS_KEYTAB_PATH) .add(KERBEROS_CREDENTIAL_CACHE_PATH) .add(ACCESS_TOKEN) + .add(TIMEZONE_ID) .add(EXTRA_CREDENTIALS) .add(CUSTOM_HEADERS) .add(SESSION_PROPERTIES) @@ -301,6 +303,15 @@ public AccessToken() } } + private static class TimeZoneId + extends AbstractConnectionProperty + { + public TimeZoneId() + { + super("timeZoneId", NOT_REQUIRED, ALLOWED, STRING_CONVERTER); + } + } + private static class ExtraCredentials extends AbstractConnectionProperty> { diff --git a/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoConnection.java b/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoConnection.java index 233f19651b5e5..d89ef658c5de8 100644 --- a/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoConnection.java +++ b/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoConnection.java @@ -50,7 +50,6 @@ import java.util.Map; import java.util.Optional; import java.util.Properties; -import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; @@ -118,7 +117,7 @@ public class PrestoConnection this.connectionProperties = uri.getProperties(); this.queryExecutor = requireNonNull(queryExecutor, "queryExecutor is null"); - timeZoneId.set(TimeZone.getDefault().getID()); + timeZoneId.set(uri.getTimeZoneId()); locale.set(Locale.getDefault()); this.queryInterceptorInstances = ImmutableList.copyOf(uri.getQueryInterceptors()); diff --git a/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoDriverUri.java b/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoDriverUri.java index 4bfe62405aa14..5f34ccf50b90f 100644 --- a/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoDriverUri.java +++ b/presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoDriverUri.java @@ -27,12 +27,14 @@ import java.net.URI; import java.net.URISyntaxException; import java.sql.SQLException; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.Properties; +import java.util.TimeZone; import static com.facebook.presto.client.GCSOAuthInterceptor.GCS_CREDENTIALS_PATH_KEY; import static com.facebook.presto.client.GCSOAuthInterceptor.GCS_OAUTH_SCOPES_KEY; @@ -66,6 +68,7 @@ import static com.facebook.presto.jdbc.ConnectionProperties.SSL_KEY_STORE_PATH; import static com.facebook.presto.jdbc.ConnectionProperties.SSL_TRUST_STORE_PASSWORD; import static com.facebook.presto.jdbc.ConnectionProperties.SSL_TRUST_STORE_PATH; +import static com.facebook.presto.jdbc.ConnectionProperties.TIMEZONE_ID; import static com.facebook.presto.jdbc.ConnectionProperties.USER; import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; @@ -149,6 +152,21 @@ public Properties getProperties() return properties; } + public String getTimeZoneId() + throws SQLException + { + Optional timezone = TIMEZONE_ID.getValue(properties); + + if (timezone.isPresent()) { + List timeZoneIds = Arrays.asList(TimeZone.getAvailableIDs()); + if (!timeZoneIds.contains(timezone.get())) { + throw new SQLException("Specified timeZoneId is not supported: " + timezone.get()); + } + return timezone.get(); + } + return TimeZone.getDefault().getID(); + } + public Map getExtraCredentials() throws SQLException { diff --git a/presto-jdbc/src/test/java/com/facebook/presto/jdbc/TestJdbcConnection.java b/presto-jdbc/src/test/java/com/facebook/presto/jdbc/TestJdbcConnection.java index c3bb10d837614..4e611c4bb8c9e 100644 --- a/presto-jdbc/src/test/java/com/facebook/presto/jdbc/TestJdbcConnection.java +++ b/presto-jdbc/src/test/java/com/facebook/presto/jdbc/TestJdbcConnection.java @@ -182,7 +182,7 @@ public void testSession() { try (Connection connection = createConnection("sessionProperties=query_max_run_time:2d;max_failed_task_percentage:0.6")) { assertThat(listSession(connection)) - .contains("join_distribution_type|PARTITIONED|PARTITIONED") + .contains("join_distribution_type|AUTOMATIC|AUTOMATIC") .contains("exchange_compression|false|false") .contains("query_max_run_time|2d|100.00d") .contains("max_failed_task_percentage|0.6|0.3"); @@ -192,7 +192,7 @@ public void testSession() } assertThat(listSession(connection)) - .contains("join_distribution_type|BROADCAST|PARTITIONED") + .contains("join_distribution_type|BROADCAST|AUTOMATIC") .contains("exchange_compression|false|false"); try (Statement statement = connection.createStatement()) { @@ -200,7 +200,7 @@ public void testSession() } assertThat(listSession(connection)) - .contains("join_distribution_type|BROADCAST|PARTITIONED") + .contains("join_distribution_type|BROADCAST|AUTOMATIC") .contains("exchange_compression|true|false"); } } diff --git a/presto-jdbc/src/test/java/com/facebook/presto/jdbc/TestPrestoDriver.java b/presto-jdbc/src/test/java/com/facebook/presto/jdbc/TestPrestoDriver.java index 76879f89dfb91..1d91cc3bf05d7 100644 --- a/presto-jdbc/src/test/java/com/facebook/presto/jdbc/TestPrestoDriver.java +++ b/presto-jdbc/src/test/java/com/facebook/presto/jdbc/TestPrestoDriver.java @@ -1680,6 +1680,22 @@ public void testEncodeDecodeSessionValue() assertTrue(isValidSessionValue); } + @Test + public void testTimeZoneIdParameter() + throws Exception + { + String sql = "SELECT current_timezone() zone, TIMESTAMP '2001-02-03 3:04:05' ts"; + + try (Connection connection = createConnectionWithParameter("timeZoneId=UTC")) { + try (Statement statement = connection.createStatement(); + ResultSet rs = statement.executeQuery(sql)) { + assertTrue(rs.next()); + assertEquals(rs.getString("zone"), "UTC"); + assertEquals(rs.getTimestamp("ts"), new Timestamp(new DateTime(2001, 2, 3, 3, 4, 5, DateTimeZone.UTC).getMillis())); + } + } + } + private QueryState getQueryState(String queryId) throws SQLException { @@ -1729,6 +1745,13 @@ private Connection createConnection(String catalog, String schema) return DriverManager.getConnection(url, "test", null); } + private Connection createConnectionWithParameter(String parameter) + throws SQLException + { + String url = format("jdbc:presto://%s?%s", server.getAddress(), parameter); + return DriverManager.getConnection(url, "test", null); + } + private static List> readRows(ResultSet rs) throws SQLException { diff --git a/presto-jmx/pom.xml b/presto-jmx/pom.xml index 9a8e51af4e532..77f829febd4d7 100644 --- a/presto-jmx/pom.xml +++ b/presto-jmx/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-jmx diff --git a/presto-kafka/pom.xml b/presto-kafka/pom.xml index d4479dfe68d98..61f0e2930b555 100644 --- a/presto-kafka/pom.xml +++ b/presto-kafka/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-kafka diff --git a/presto-kudu/pom.xml b/presto-kudu/pom.xml index c5a850eb21e8b..29e97296da65a 100644 --- a/presto-kudu/pom.xml +++ b/presto-kudu/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-kudu diff --git a/presto-local-file/pom.xml b/presto-local-file/pom.xml index 61b6abd4abb15..5e984ad3006f9 100644 --- a/presto-local-file/pom.xml +++ b/presto-local-file/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-local-file diff --git a/presto-main/pom.xml b/presto-main/pom.xml index cedbd019b87ab..1e58a3be7bef7 100644 --- a/presto-main/pom.xml +++ b/presto-main/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-main diff --git a/presto-main/src/main/java/com/facebook/presto/SystemSessionProperties.java b/presto-main/src/main/java/com/facebook/presto/SystemSessionProperties.java index 9e57d9ea9a877..683eab46defe1 100644 --- a/presto-main/src/main/java/com/facebook/presto/SystemSessionProperties.java +++ b/presto-main/src/main/java/com/facebook/presto/SystemSessionProperties.java @@ -217,6 +217,7 @@ public final class SystemSessionProperties public static final String EXCEEDED_MEMORY_LIMIT_HEAP_DUMP_FILE_DIRECTORY = "exceeded_memory_limit_heap_dump_file_directory"; public static final String DISTRIBUTED_TRACING_MODE = "distributed_tracing_mode"; public static final String VERBOSE_RUNTIME_STATS_ENABLED = "verbose_runtime_stats_enabled"; + public static final String STREAMING_FOR_PARTIAL_AGGREGATION_ENABLED = "streaming_for_partial_aggregation_enabled"; //TODO: Prestissimo related session properties that are temporarily put here. They will be relocated in the future public static final String PRESTISSIMO_SIMPLIFIED_EXPRESSION_EVALUATION_ENABLED = "simplified_expression_evaluation_enabled"; @@ -1158,6 +1159,11 @@ public SystemSessionProperties( "Enable logging all runtime stats", featuresConfig.isVerboseRuntimeStatsEnabled(), false), + booleanProperty( + STREAMING_FOR_PARTIAL_AGGREGATION_ENABLED, + "Enable streaming for partial aggregation", + featuresConfig.isStreamingForPartialAggregationEnabled(), + false), new PropertyMetadata<>( AGGREGATION_IF_TO_FILTER_REWRITE_STRATEGY, format("Set the strategy used to rewrite AGG IF to AGG FILTER. Options are %s", @@ -2034,6 +2040,11 @@ public static boolean isVerboseRuntimeStatsEnabled(Session session) return session.getSystemProperty(VERBOSE_RUNTIME_STATS_ENABLED, Boolean.class); } + public static boolean isStreamingForPartialAggregationEnabled(Session session) + { + return session.getSystemProperty(STREAMING_FOR_PARTIAL_AGGREGATION_ENABLED, Boolean.class); + } + public static AggregationIfToFilterRewriteStrategy getAggregationIfToFilterRewriteStrategy(Session session) { return session.getSystemProperty(AGGREGATION_IF_TO_FILTER_REWRITE_STRATEGY, AggregationIfToFilterRewriteStrategy.class); diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/MetadataUtil.java b/presto-main/src/main/java/com/facebook/presto/metadata/MetadataUtil.java index 41126d6df466d..091442f8aee6a 100644 --- a/presto-main/src/main/java/com/facebook/presto/metadata/MetadataUtil.java +++ b/presto-main/src/main/java/com/facebook/presto/metadata/MetadataUtil.java @@ -152,11 +152,6 @@ public static QualifiedObjectName createQualifiedObjectName(Session session, Nod return new QualifiedObjectName(catalogName, schemaName, objectName); } - public static QualifiedName createQualifiedName(QualifiedObjectName name) - { - return QualifiedName.of(name.getCatalogName(), name.getSchemaName(), name.getObjectName()); - } - public static PrestoPrincipal createPrincipal(Session session, GrantorSpecification specification) { GrantorSpecification.Type type = specification.getType(); diff --git a/presto-main/src/main/java/com/facebook/presto/server/ThreadResource.java b/presto-main/src/main/java/com/facebook/presto/server/ThreadResource.java index ddab14cf63f8f..38dd30ff0ff6e 100644 --- a/presto-main/src/main/java/com/facebook/presto/server/ThreadResource.java +++ b/presto-main/src/main/java/com/facebook/presto/server/ThreadResource.java @@ -13,6 +13,9 @@ */ package com.facebook.presto.server; +import com.facebook.drift.annotations.ThriftConstructor; +import com.facebook.drift.annotations.ThriftField; +import com.facebook.drift.annotations.ThriftStruct; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableList; @@ -74,6 +77,7 @@ private static List toStackTrace(StackTraceElement[] stackTrace) return builder.build(); } + @ThriftStruct public static class Info { private final long id; @@ -82,6 +86,7 @@ public static class Info private final Long lockOwnerId; private final List stackTrace; + @ThriftConstructor @JsonCreator public Info( @JsonProperty("id") long id, @@ -97,30 +102,35 @@ public Info( this.stackTrace = stackTrace; } + @ThriftField(1) @JsonProperty public long getId() { return id; } + @ThriftField(2) @JsonProperty public String getName() { return name; } + @ThriftField(3) @JsonProperty public String getState() { return state; } + @ThriftField(4) @JsonProperty public Long getLockOwnerId() { return lockOwnerId; } + @ThriftField(5) @JsonProperty public List getStackTrace() { @@ -140,6 +150,7 @@ public int compare(Info info, Info info2) } } + @ThriftStruct public static class StackLine { private final String file; @@ -147,6 +158,7 @@ public static class StackLine private final String className; private final String method; + @ThriftConstructor @JsonCreator public StackLine( @JsonProperty("file") String file, @@ -160,24 +172,28 @@ public StackLine( this.method = method; } + @ThriftField(1) @JsonProperty public String getFile() { return file; } + @ThriftField(2) @JsonProperty public int getLine() { return line; } + @ThriftField(3) @JsonProperty public String getClassName() { return className; } + @ThriftField(4) @JsonProperty public String getMethod() { diff --git a/presto-main/src/main/java/com/facebook/presto/sql/analyzer/FeaturesConfig.java b/presto-main/src/main/java/com/facebook/presto/sql/analyzer/FeaturesConfig.java index 92449aaf93a13..a30cc692225e6 100644 --- a/presto-main/src/main/java/com/facebook/presto/sql/analyzer/FeaturesConfig.java +++ b/presto-main/src/main/java/com/facebook/presto/sql/analyzer/FeaturesConfig.java @@ -37,8 +37,6 @@ import java.util.List; import static com.facebook.presto.sql.analyzer.FeaturesConfig.AggregationPartitioningMergingStrategy.LEGACY; -import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.PARTITIONED; -import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static com.facebook.presto.sql.analyzer.FeaturesConfig.TaskSpillingStrategy.ORDER_BY_CREATE_TIME; import static com.facebook.presto.sql.analyzer.RegexLibrary.JONI; import static com.google.common.collect.ImmutableList.toImmutableList; @@ -70,7 +68,7 @@ public class FeaturesConfig private double memoryCostWeight = 10; private double networkCostWeight = 15; private boolean distributedIndexJoinsEnabled; - private JoinDistributionType joinDistributionType = PARTITIONED; + private JoinDistributionType joinDistributionType = JoinDistributionType.AUTOMATIC; private DataSize joinMaxBroadcastTableSize = new DataSize(100, MEGABYTE); private boolean colocatedJoinsEnabled = true; private boolean groupedExecutionEnabled = true; @@ -85,7 +83,7 @@ public class FeaturesConfig private SingleStreamSpillerChoice singleStreamSpillerChoice = SingleStreamSpillerChoice.LOCAL_FILE; private String spillerTempStorage = "local"; private DataSize maxRevocableMemoryPerTask = new DataSize(500, MEGABYTE); - private JoinReorderingStrategy joinReorderingStrategy = ELIMINATE_CROSS_JOINS; + private JoinReorderingStrategy joinReorderingStrategy = JoinReorderingStrategy.AUTOMATIC; private PartialMergePushdownStrategy partialMergePushdownStrategy = PartialMergePushdownStrategy.NONE; private int maxReorderedJoins = 9; private boolean redistributeWrites = true; @@ -216,6 +214,8 @@ public class FeaturesConfig private boolean hashBasedDistinctLimitEnabled; private int hashBasedDistinctLimitThreshold = 10000; + private boolean streamingForPartialAggregationEnabled; + public enum PartitioningPrecisionStrategy { // Let Presto decide when to repartition @@ -1957,4 +1957,16 @@ public int getHashBasedDistinctLimitThreshold() { return hashBasedDistinctLimitThreshold; } + + public boolean isStreamingForPartialAggregationEnabled() + { + return streamingForPartialAggregationEnabled; + } + + @Config("streaming-for-partial-aggregation-enabled") + public FeaturesConfig setStreamingForPartialAggregationEnabled(boolean streamingForPartialAggregationEnabled) + { + this.streamingForPartialAggregationEnabled = streamingForPartialAggregationEnabled; + return this; + } } diff --git a/presto-main/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java b/presto-main/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java index eac9bdedb6c76..b3f76a6c63413 100644 --- a/presto-main/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java +++ b/presto-main/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java @@ -2281,7 +2281,7 @@ else if (expression instanceof DereferenceExpression) { if (!field.isPresent()) { if (name != null) { - field = Optional.of(new Identifier(getLast(name.getOriginalParts()))); + field = Optional.of(getLast(name.getOriginalParts())); } } diff --git a/presto-main/src/main/java/com/facebook/presto/sql/planner/iterative/rule/PushPartialAggregationThroughExchange.java b/presto-main/src/main/java/com/facebook/presto/sql/planner/iterative/rule/PushPartialAggregationThroughExchange.java index 6bc04b1cf6892..d37b3a2e0109c 100644 --- a/presto-main/src/main/java/com/facebook/presto/sql/planner/iterative/rule/PushPartialAggregationThroughExchange.java +++ b/presto-main/src/main/java/com/facebook/presto/sql/planner/iterative/rule/PushPartialAggregationThroughExchange.java @@ -46,6 +46,7 @@ import static com.facebook.presto.SystemSessionProperties.getPartialAggregationByteReductionThreshold; import static com.facebook.presto.SystemSessionProperties.getPartialAggregationStrategy; +import static com.facebook.presto.SystemSessionProperties.isStreamingForPartialAggregationEnabled; import static com.facebook.presto.operator.aggregation.AggregationUtils.isDecomposable; import static com.facebook.presto.spi.plan.AggregationNode.Step.FINAL; import static com.facebook.presto.spi.plan.AggregationNode.Step.PARTIAL; @@ -254,6 +255,14 @@ private PlanNode split(AggregationNode node, Context context) Optional.empty())); } + // We can always enable streaming aggregation for partial aggregations. But if the table is not pre-group by the groupby columns, it may have regressions. + // This session property is just a solution to force enabling when we know the execution would benefit from partial streaming aggregation. + // We can work on determining it based on the input table properties later. + List preGroupedSymbols = ImmutableList.of(); + if (isStreamingForPartialAggregationEnabled(context.getSession())) { + preGroupedSymbols = ImmutableList.copyOf(node.getGroupingSets().getGroupingKeys()); + } + PlanNode partial = new AggregationNode( node.getSourceLocation(), context.getIdAllocator().getNextId(), @@ -262,7 +271,7 @@ private PlanNode split(AggregationNode node, Context context) node.getGroupingSets(), // preGroupedSymbols reflect properties of the input. Splitting the aggregation and pushing partial aggregation // through the exchange may or may not preserve these properties. Hence, it is safest to drop preGroupedSymbols here. - ImmutableList.of(), + preGroupedSymbols, PARTIAL, node.getHashVariable(), node.getGroupIdVariable()); diff --git a/presto-main/src/main/java/com/facebook/presto/sql/planner/optimizations/SymbolMapper.java b/presto-main/src/main/java/com/facebook/presto/sql/planner/optimizations/SymbolMapper.java index 58118ac45c4d0..9cb8152b16e24 100644 --- a/presto-main/src/main/java/com/facebook/presto/sql/planner/optimizations/SymbolMapper.java +++ b/presto-main/src/main/java/com/facebook/presto/sql/planner/optimizations/SymbolMapper.java @@ -187,7 +187,7 @@ private AggregationNode map(AggregationNode node, PlanNode source, PlanNodeId ne mapAndDistinctVariable(node.getGroupingKeys()), node.getGroupingSetCount(), node.getGlobalGroupingSets()), - ImmutableList.of(), + mapAndDistinctVariable(node.getPreGroupedVariables()), node.getStep(), node.getHashVariable().map(this::map), node.getGroupIdVariable().map(this::map)); diff --git a/presto-main/src/main/java/com/facebook/presto/sql/rewrite/ShowQueriesRewrite.java b/presto-main/src/main/java/com/facebook/presto/sql/rewrite/ShowQueriesRewrite.java index def2e5896d124..ad95d287070ea 100644 --- a/presto-main/src/main/java/com/facebook/presto/sql/rewrite/ShowQueriesRewrite.java +++ b/presto-main/src/main/java/com/facebook/presto/sql/rewrite/ShowQueriesRewrite.java @@ -105,7 +105,6 @@ import static com.facebook.presto.metadata.MetadataListing.listCatalogs; import static com.facebook.presto.metadata.MetadataListing.listSchemas; import static com.facebook.presto.metadata.MetadataUtil.createCatalogSchemaName; -import static com.facebook.presto.metadata.MetadataUtil.createQualifiedName; import static com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName; import static com.facebook.presto.metadata.SessionFunctionHandle.SESSION_NAMESPACE; import static com.facebook.presto.spi.StandardErrorCode.FUNCTION_NOT_FOUND; @@ -459,7 +458,7 @@ protected Node visitShowCreate(ShowCreate node, Void context) } Query query = parseView(viewDefinition.get().getOriginalSql(), objectName, node); - String sql = formatSql(new CreateView(createQualifiedName(objectName), query, false, Optional.empty()), Optional.of(parameters)).trim(); + String sql = formatSql(new CreateView(getQualifiedName(node, objectName), query, false, Optional.empty()), Optional.of(parameters)).trim(); return singleValueQuery("Create View", sql); } @@ -485,7 +484,7 @@ protected Node visitShowCreate(ShowCreate node, Void context) CreateMaterializedView createMaterializedView = new CreateMaterializedView( Optional.empty(), - createQualifiedName(objectName), + getQualifiedName(node, objectName), query, false, propertyNodes, @@ -593,6 +592,16 @@ protected Node visitShowCreateFunction(ShowCreateFunction node, Void context) ordering(ascending("argument_types"))); } + private QualifiedName getQualifiedName(ShowCreate node, QualifiedObjectName objectName) + { + List parts = node.getName().getOriginalParts(); + Identifier tableName = parts.get(0); + Identifier schemaName = (parts.size() > 1) ? parts.get(1) : new Identifier(objectName.getSchemaName()); + Identifier catalogName = (parts.size() > 2) ? parts.get(2) : new Identifier(objectName.getCatalogName()); + + return QualifiedName.of(ImmutableList.of(catalogName, schemaName, tableName)); + } + private List buildProperties( Object objectName, Optional columnName, diff --git a/presto-main/src/main/resources/webapp/dist/query.js b/presto-main/src/main/resources/webapp/dist/query.js index 68919c71530ed..276251d50a623 100644 --- a/presto-main/src/main/resources/webapp/dist/query.js +++ b/presto-main/src/main/resources/webapp/dist/query.js @@ -58,4 +58,4 @@ t.exports={graphlib:e(46),dagre:e(28),intersect:e(85),render:e(87),util:e(4),ver * Released under MIT license * Based on Underscore.js 1.8.3 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */(function(){var o,u=200,a="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",c="Expected a function",l="__lodash_hash_undefined__",f=500,s="__lodash_placeholder__",h=1,d=2,p=4,v=1,g=2,y=1,m=2,_=4,b=8,w=16,x=32,E=64,M=128,k=256,N=512,S=30,T="...",C=800,A=16,P=1,O=2,I=1/0,R=9007199254740991,D=1.7976931348623157e308,L=NaN,U=4294967295,z=U-1,j=U>>>1,F=[["ary",M],["bind",y],["bindKey",m],["curry",b],["curryRight",w],["flip",N],["partial",x],["partialRight",E],["rearg",k]],q="[object Arguments]",B="[object Array]",H="[object AsyncFunction]",Y="[object Boolean]",$="[object Date]",V="[object DOMException]",W="[object Error]",X="[object Function]",G="[object GeneratorFunction]",Q="[object Map]",Z="[object Number]",K="[object Null]",J="[object Object]",tt="[object Proxy]",nt="[object RegExp]",et="[object Set]",rt="[object String]",it="[object Symbol]",ot="[object Undefined]",ut="[object WeakMap]",at="[object WeakSet]",ct="[object ArrayBuffer]",lt="[object DataView]",ft="[object Float32Array]",st="[object Float64Array]",ht="[object Int8Array]",dt="[object Int16Array]",pt="[object Int32Array]",vt="[object Uint8Array]",gt="[object Uint8ClampedArray]",yt="[object Uint16Array]",mt="[object Uint32Array]",_t=/\b__p \+= '';/g,bt=/\b(__p \+=) '' \+/g,wt=/(__e\(.*?\)|\b__t\)) \+\n'';/g,xt=/&(?:amp|lt|gt|quot|#39);/g,Et=/[&<>"']/g,Mt=RegExp(xt.source),kt=RegExp(Et.source),Nt=/<%-([\s\S]+?)%>/g,St=/<%([\s\S]+?)%>/g,Tt=/<%=([\s\S]+?)%>/g,Ct=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,At=/^\w*$/,Pt=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Ot=/[\\^$.*+?()[\]{}|]/g,It=RegExp(Ot.source),Rt=/^\s+|\s+$/g,Dt=/^\s+/,Lt=/\s+$/,Ut=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,zt=/\{\n\/\* \[wrapped with (.+)\] \*/,jt=/,? & /,Ft=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,qt=/\\(\\)?/g,Bt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,Ht=/\w*$/,Yt=/^[-+]0x[0-9a-f]+$/i,$t=/^0b[01]+$/i,Vt=/^\[object .+?Constructor\]$/,Wt=/^0o[0-7]+$/i,Xt=/^(?:0|[1-9]\d*)$/,Gt=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,Qt=/($^)/,Zt=/['\n\r\u2028\u2029\\]/g,Kt="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",Jt="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",tn="[\\ud800-\\udfff]",nn="["+Jt+"]",en="["+Kt+"]",rn="\\d+",on="[\\u2700-\\u27bf]",un="[a-z\\xdf-\\xf6\\xf8-\\xff]",an="[^\\ud800-\\udfff"+Jt+rn+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",cn="\\ud83c[\\udffb-\\udfff]",ln="[^\\ud800-\\udfff]",fn="(?:\\ud83c[\\udde6-\\uddff]){2}",sn="[\\ud800-\\udbff][\\udc00-\\udfff]",hn="[A-Z\\xc0-\\xd6\\xd8-\\xde]",dn="(?:"+un+"|"+an+")",pn="(?:"+hn+"|"+an+")",vn="(?:"+en+"|"+cn+")"+"?",gn="[\\ufe0e\\ufe0f]?"+vn+("(?:\\u200d(?:"+[ln,fn,sn].join("|")+")[\\ufe0e\\ufe0f]?"+vn+")*"),yn="(?:"+[on,fn,sn].join("|")+")"+gn,mn="(?:"+[ln+en+"?",en,fn,sn,tn].join("|")+")",_n=RegExp("['’]","g"),bn=RegExp(en,"g"),wn=RegExp(cn+"(?="+cn+")|"+mn+gn,"g"),xn=RegExp([hn+"?"+un+"+(?:['’](?:d|ll|m|re|s|t|ve))?(?="+[nn,hn,"$"].join("|")+")",pn+"+(?:['’](?:D|LL|M|RE|S|T|VE))?(?="+[nn,hn+dn,"$"].join("|")+")",hn+"?"+dn+"+(?:['’](?:d|ll|m|re|s|t|ve))?",hn+"+(?:['’](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",rn,yn].join("|"),"g"),En=RegExp("[\\u200d\\ud800-\\udfff"+Kt+"\\ufe0e\\ufe0f]"),Mn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,kn=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Nn=-1,Sn={};Sn[ft]=Sn[st]=Sn[ht]=Sn[dt]=Sn[pt]=Sn[vt]=Sn[gt]=Sn[yt]=Sn[mt]=!0,Sn[q]=Sn[B]=Sn[ct]=Sn[Y]=Sn[lt]=Sn[$]=Sn[W]=Sn[X]=Sn[Q]=Sn[Z]=Sn[J]=Sn[nt]=Sn[et]=Sn[rt]=Sn[ut]=!1;var Tn={};Tn[q]=Tn[B]=Tn[ct]=Tn[lt]=Tn[Y]=Tn[$]=Tn[ft]=Tn[st]=Tn[ht]=Tn[dt]=Tn[pt]=Tn[Q]=Tn[Z]=Tn[J]=Tn[nt]=Tn[et]=Tn[rt]=Tn[it]=Tn[vt]=Tn[gt]=Tn[yt]=Tn[mt]=!0,Tn[W]=Tn[X]=Tn[ut]=!1;var Cn={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},An=parseFloat,Pn=parseInt,On="object"==typeof t&&t&&t.Object===Object&&t,In="object"==typeof self&&self&&self.Object===Object&&self,Rn=On||In||Function("return this")(),Dn="object"==typeof n&&n&&!n.nodeType&&n,Ln=Dn&&"object"==typeof r&&r&&!r.nodeType&&r,Un=Ln&&Ln.exports===Dn,zn=Un&&On.process,jn=function(){try{var t=Ln&&Ln.require&&Ln.require("util").types;return t||zn&&zn.binding&&zn.binding("util")}catch(t){}}(),Fn=jn&&jn.isArrayBuffer,qn=jn&&jn.isDate,Bn=jn&&jn.isMap,Hn=jn&&jn.isRegExp,Yn=jn&&jn.isSet,$n=jn&&jn.isTypedArray;function Vn(t,n,e){switch(e.length){case 0:return t.call(n);case 1:return t.call(n,e[0]);case 2:return t.call(n,e[0],e[1]);case 3:return t.call(n,e[0],e[1],e[2])}return t.apply(n,e)}function Wn(t,n,e,r){for(var i=-1,o=null==t?0:t.length;++i-1}function Jn(t,n,e){for(var r=-1,i=null==t?0:t.length;++r-1;);return e}function we(t,n){for(var e=t.length;e--&&ce(n,t[e],0)>-1;);return e}var xe=de({"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss","Ā":"A","Ă":"A","Ą":"A","ā":"a","ă":"a","ą":"a","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","ć":"c","ĉ":"c","ċ":"c","č":"c","Ď":"D","Đ":"D","ď":"d","đ":"d","Ē":"E","Ĕ":"E","Ė":"E","Ę":"E","Ě":"E","ē":"e","ĕ":"e","ė":"e","ę":"e","ě":"e","Ĝ":"G","Ğ":"G","Ġ":"G","Ģ":"G","ĝ":"g","ğ":"g","ġ":"g","ģ":"g","Ĥ":"H","Ħ":"H","ĥ":"h","ħ":"h","Ĩ":"I","Ī":"I","Ĭ":"I","Į":"I","İ":"I","ĩ":"i","ī":"i","ĭ":"i","į":"i","ı":"i","Ĵ":"J","ĵ":"j","Ķ":"K","ķ":"k","ĸ":"k","Ĺ":"L","Ļ":"L","Ľ":"L","Ŀ":"L","Ł":"L","ĺ":"l","ļ":"l","ľ":"l","ŀ":"l","ł":"l","Ń":"N","Ņ":"N","Ň":"N","Ŋ":"N","ń":"n","ņ":"n","ň":"n","ŋ":"n","Ō":"O","Ŏ":"O","Ő":"O","ō":"o","ŏ":"o","ő":"o","Ŕ":"R","Ŗ":"R","Ř":"R","ŕ":"r","ŗ":"r","ř":"r","Ś":"S","Ŝ":"S","Ş":"S","Š":"S","ś":"s","ŝ":"s","ş":"s","š":"s","Ţ":"T","Ť":"T","Ŧ":"T","ţ":"t","ť":"t","ŧ":"t","Ũ":"U","Ū":"U","Ŭ":"U","Ů":"U","Ű":"U","Ų":"U","ũ":"u","ū":"u","ŭ":"u","ů":"u","ű":"u","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","Ż":"Z","Ž":"Z","ź":"z","ż":"z","ž":"z","IJ":"IJ","ij":"ij","Œ":"Oe","œ":"oe","ʼn":"'n","ſ":"s"}),Ee=de({"&":"&","<":"<",">":">",'"':""","'":"'"});function Me(t){return"\\"+Cn[t]}function ke(t){return En.test(t)}function Ne(t){var n=-1,e=Array(t.size);return t.forEach(function(t,r){e[++n]=[r,t]}),e}function Se(t,n){return function(e){return t(n(e))}}function Te(t,n){for(var e=-1,r=t.length,i=0,o=[];++e",""":'"',"'":"'"});var Re=function t(n){var e=(n=null==n?Rn:Re.defaults(Rn.Object(),n,Re.pick(Rn,kn))).Array,r=n.Date,i=n.Error,Kt=n.Function,Jt=n.Math,tn=n.Object,nn=n.RegExp,en=n.String,rn=n.TypeError,on=e.prototype,un=Kt.prototype,an=tn.prototype,cn=n["__core-js_shared__"],ln=un.toString,fn=an.hasOwnProperty,sn=0,hn=function(){var t=/[^.]+$/.exec(cn&&cn.keys&&cn.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""}(),dn=an.toString,pn=ln.call(tn),vn=Rn._,gn=nn("^"+ln.call(fn).replace(Ot,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),yn=Un?n.Buffer:o,mn=n.Symbol,wn=n.Uint8Array,En=yn?yn.allocUnsafe:o,Cn=Se(tn.getPrototypeOf,tn),On=tn.create,In=an.propertyIsEnumerable,Dn=on.splice,Ln=mn?mn.isConcatSpreadable:o,zn=mn?mn.iterator:o,jn=mn?mn.toStringTag:o,oe=function(){try{var t=zo(tn,"defineProperty");return t({},"",{}),t}catch(t){}}(),de=n.clearTimeout!==Rn.clearTimeout&&n.clearTimeout,De=r&&r.now!==Rn.Date.now&&r.now,Le=n.setTimeout!==Rn.setTimeout&&n.setTimeout,Ue=Jt.ceil,ze=Jt.floor,je=tn.getOwnPropertySymbols,Fe=yn?yn.isBuffer:o,qe=n.isFinite,Be=on.join,He=Se(tn.keys,tn),Ye=Jt.max,$e=Jt.min,Ve=r.now,We=n.parseInt,Xe=Jt.random,Ge=on.reverse,Qe=zo(n,"DataView"),Ze=zo(n,"Map"),Ke=zo(n,"Promise"),Je=zo(n,"Set"),tr=zo(n,"WeakMap"),nr=zo(tn,"create"),er=tr&&new tr,rr={},ir=fu(Qe),or=fu(Ze),ur=fu(Ke),ar=fu(Je),cr=fu(tr),lr=mn?mn.prototype:o,fr=lr?lr.valueOf:o,sr=lr?lr.toString:o;function hr(t){if(Sa(t)&&!ga(t)&&!(t instanceof gr)){if(t instanceof vr)return t;if(fn.call(t,"__wrapped__"))return su(t)}return new vr(t)}var dr=function(){function t(){}return function(n){if(!Na(n))return{};if(On)return On(n);t.prototype=n;var e=new t;return t.prototype=o,e}}();function pr(){}function vr(t,n){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!n,this.__index__=0,this.__values__=o}function gr(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=U,this.__views__=[]}function yr(t){var n=-1,e=null==t?0:t.length;for(this.clear();++n=n?t:n)),t}function Rr(t,n,e,r,i,u){var a,c=n&h,l=n&d,f=n&p;if(e&&(a=i?e(t,r,i,u):e(t)),a!==o)return a;if(!Na(t))return t;var s=ga(t);if(s){if(a=function(t){var n=t.length,e=new t.constructor(n);return n&&"string"==typeof t[0]&&fn.call(t,"index")&&(e.index=t.index,e.input=t.input),e}(t),!c)return no(t,a)}else{var v=qo(t),g=v==X||v==G;if(ba(t))return Gi(t,c);if(v==J||v==q||g&&!i){if(a=l||g?{}:Ho(t),!c)return l?function(t,n){return eo(t,Fo(t),n)}(t,function(t,n){return t&&eo(n,ic(n),t)}(a,t)):function(t,n){return eo(t,jo(t),n)}(t,Ar(a,t))}else{if(!Tn[v])return i?t:{};a=function(t,n,e){var r=t.constructor;switch(n){case ct:return Qi(t);case Y:case $:return new r(+t);case lt:return function(t,n){var e=n?Qi(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.byteLength)}(t,e);case ft:case st:case ht:case dt:case pt:case vt:case gt:case yt:case mt:return Zi(t,e);case Q:return new r;case Z:case rt:return new r(t);case nt:return function(t){var n=new t.constructor(t.source,Ht.exec(t));return n.lastIndex=t.lastIndex,n}(t);case et:return new r;case it:return function(t){return fr?tn(fr.call(t)):{}}(t)}}(t,v,c)}}u||(u=new wr);var y=u.get(t);if(y)return y;if(u.set(t,a),Oa(t))return t.forEach(function(r){a.add(Rr(r,n,e,r,t,u))}),a;if(Ta(t))return t.forEach(function(r,i){a.set(i,Rr(r,n,e,i,t,u))}),a;var m=s?o:(f?l?Po:Ao:l?ic:rc)(t);return Xn(m||t,function(r,i){m&&(r=t[i=r]),Sr(a,i,Rr(r,n,e,i,t,u))}),a}function Dr(t,n,e){var r=e.length;if(null==t)return!r;for(t=tn(t);r--;){var i=e[r],u=n[i],a=t[i];if(a===o&&!(i in t)||!u(a))return!1}return!0}function Lr(t,n,e){if("function"!=typeof t)throw new rn(c);return ru(function(){t.apply(o,e)},n)}function Ur(t,n,e,r){var i=-1,o=Kn,a=!0,c=t.length,l=[],f=n.length;if(!c)return l;e&&(n=te(n,ye(e))),r?(o=Jn,a=!1):n.length>=u&&(o=_e,a=!1,n=new br(n));t:for(;++i-1},mr.prototype.set=function(t,n){var e=this.__data__,r=Tr(e,t);return r<0?(++this.size,e.push([t,n])):e[r][1]=n,this},_r.prototype.clear=function(){this.size=0,this.__data__={hash:new yr,map:new(Ze||mr),string:new yr}},_r.prototype.delete=function(t){var n=Lo(this,t).delete(t);return this.size-=n?1:0,n},_r.prototype.get=function(t){return Lo(this,t).get(t)},_r.prototype.has=function(t){return Lo(this,t).has(t)},_r.prototype.set=function(t,n){var e=Lo(this,t),r=e.size;return e.set(t,n),this.size+=e.size==r?0:1,this},br.prototype.add=br.prototype.push=function(t){return this.__data__.set(t,l),this},br.prototype.has=function(t){return this.__data__.has(t)},wr.prototype.clear=function(){this.__data__=new mr,this.size=0},wr.prototype.delete=function(t){var n=this.__data__,e=n.delete(t);return this.size=n.size,e},wr.prototype.get=function(t){return this.__data__.get(t)},wr.prototype.has=function(t){return this.__data__.has(t)},wr.prototype.set=function(t,n){var e=this.__data__;if(e instanceof mr){var r=e.__data__;if(!Ze||r.length0&&e(a)?n>1?Hr(a,n-1,e,r,i):ne(i,a):r||(i[i.length]=a)}return i}var Yr=uo(),$r=uo(!0);function Vr(t,n){return t&&Yr(t,n,rc)}function Wr(t,n){return t&&$r(t,n,rc)}function Xr(t,n){return Zn(n,function(n){return Ea(t[n])})}function Gr(t,n){for(var e=0,r=(n=$i(n,t)).length;null!=t&&en}function Jr(t,n){return null!=t&&fn.call(t,n)}function ti(t,n){return null!=t&&n in tn(t)}function ni(t,n,r){for(var i=r?Jn:Kn,u=t[0].length,a=t.length,c=a,l=e(a),f=1/0,s=[];c--;){var h=t[c];c&&n&&(h=te(h,ye(n))),f=$e(h.length,f),l[c]=!r&&(n||u>=120&&h.length>=120)?new br(c&&h):o}h=t[0];var d=-1,p=l[0];t:for(;++d=a)return c;var l=e[r];return c*("desc"==l?-1:1)}}return t.index-n.index}(t,n,e)})}function yi(t,n,e){for(var r=-1,i=n.length,o={};++r-1;)a!==t&&Dn.call(a,c,1),Dn.call(t,c,1);return t}function _i(t,n){for(var e=t?n.length:0,r=e-1;e--;){var i=n[e];if(e==r||i!==o){var o=i;$o(i)?Dn.call(t,i,1):Ui(t,i)}}return t}function bi(t,n){return t+ze(Xe()*(n-t+1))}function wi(t,n){var e="";if(!t||n<1||n>R)return e;do{n%2&&(e+=t),(n=ze(n/2))&&(t+=t)}while(n);return e}function xi(t,n){return iu(Jo(t,n,Cc),t+"")}function Ei(t){return Er(hc(t))}function Mi(t,n){var e=hc(t);return au(e,Ir(n,0,e.length))}function ki(t,n,e,r){if(!Na(t))return t;for(var i=-1,u=(n=$i(n,t)).length,a=u-1,c=t;null!=c&&++io?0:o+n),(r=r>o?o:r)<0&&(r+=o),o=n>r?0:r-n>>>0,n>>>=0;for(var u=e(o);++i>>1,u=t[o];null!==u&&!Ra(u)&&(e?u<=n:u=u){var f=n?null:xo(t);if(f)return Ce(f);a=!1,i=_e,l=new br}else l=n?[]:c;t:for(;++r=r?t:Ci(t,n,e)}var Xi=de||function(t){return Rn.clearTimeout(t)};function Gi(t,n){if(n)return t.slice();var e=t.length,r=En?En(e):new t.constructor(e);return t.copy(r),r}function Qi(t){var n=new t.constructor(t.byteLength);return new wn(n).set(new wn(t)),n}function Zi(t,n){var e=n?Qi(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.length)}function Ki(t,n){if(t!==n){var e=t!==o,r=null===t,i=t==t,u=Ra(t),a=n!==o,c=null===n,l=n==n,f=Ra(n);if(!c&&!f&&!u&&t>n||u&&a&&l&&!c&&!f||r&&a&&l||!e&&l||!i)return 1;if(!r&&!u&&!f&&t1?e[i-1]:o,a=i>2?e[2]:o;for(u=t.length>3&&"function"==typeof u?(i--,u):o,a&&Vo(e[0],e[1],a)&&(u=i<3?o:u,i=1),n=tn(n);++r-1?i[u?n[a]:a]:o}}function so(t){return Co(function(n){var e=n.length,r=e,i=vr.prototype.thru;for(t&&n.reverse();r--;){var u=n[r];if("function"!=typeof u)throw new rn(c);if(i&&!a&&"wrapper"==Io(u))var a=new vr([],!0)}for(r=a?r:e;++r1&&b.reverse(),h&&fc))return!1;var f=u.get(t);if(f&&u.get(n))return f==n;var s=-1,h=!0,d=e&g?new br:o;for(u.set(t,n),u.set(n,t);++s-1&&t%1==0&&t1?"& ":"")+n[r],n=n.join(e>2?", ":" "),t.replace(Ut,"{\n/* [wrapped with "+n+"] */\n")}(r,function(t,n){return Xn(F,function(e){var r="_."+e[0];n&e[1]&&!Kn(t,r)&&t.push(r)}),t.sort()}(function(t){var n=t.match(zt);return n?n[1].split(jt):[]}(r),e)))}function uu(t){var n=0,e=0;return function(){var r=Ve(),i=A-(r-e);if(e=r,i>0){if(++n>=C)return arguments[0]}else n=0;return t.apply(o,arguments)}}function au(t,n){var e=-1,r=t.length,i=r-1;for(n=n===o?r:n;++e1?t[n-1]:o;return Pu(t,e="function"==typeof e?(t.pop(),e):o)});function zu(t){var n=hr(t);return n.__chain__=!0,n}function ju(t,n){return n(t)}var Fu=Co(function(t){var n=t.length,e=n?t[0]:0,r=this.__wrapped__,i=function(n){return Or(n,t)};return!(n>1||this.__actions__.length)&&r instanceof gr&&$o(e)?((r=r.slice(e,+e+(n?1:0))).__actions__.push({func:ju,args:[i],thisArg:o}),new vr(r,this.__chain__).thru(function(t){return n&&!t.length&&t.push(o),t})):this.thru(i)});var qu=ro(function(t,n,e){fn.call(t,e)?++t[e]:Pr(t,e,1)});var Bu=fo(vu),Hu=fo(gu);function Yu(t,n){return(ga(t)?Xn:zr)(t,Do(n,3))}function $u(t,n){return(ga(t)?Gn:jr)(t,Do(n,3))}var Vu=ro(function(t,n,e){fn.call(t,e)?t[e].push(n):Pr(t,e,[n])});var Wu=xi(function(t,n,r){var i=-1,o="function"==typeof n,u=ma(t)?e(t.length):[];return zr(t,function(t){u[++i]=o?Vn(n,t,r):ei(t,n,r)}),u}),Xu=ro(function(t,n,e){Pr(t,e,n)});function Gu(t,n){return(ga(t)?te:si)(t,Do(n,3))}var Qu=ro(function(t,n,e){t[e?0:1].push(n)},function(){return[[],[]]});var Zu=xi(function(t,n){if(null==t)return[];var e=n.length;return e>1&&Vo(t,n[0],n[1])?n=[]:e>2&&Vo(n[0],n[1],n[2])&&(n=[n[0]]),gi(t,Hr(n,1),[])}),Ku=De||function(){return Rn.Date.now()};function Ju(t,n,e){return n=e?o:n,n=t&&null==n?t.length:n,Mo(t,M,o,o,o,o,n)}function ta(t,n){var e;if("function"!=typeof n)throw new rn(c);return t=Fa(t),function(){return--t>0&&(e=n.apply(this,arguments)),t<=1&&(n=o),e}}var na=xi(function(t,n,e){var r=y;if(e.length){var i=Te(e,Ro(na));r|=x}return Mo(t,r,n,e,i)}),ea=xi(function(t,n,e){var r=y|m;if(e.length){var i=Te(e,Ro(ea));r|=x}return Mo(n,r,t,e,i)});function ra(t,n,e){var r,i,u,a,l,f,s=0,h=!1,d=!1,p=!0;if("function"!=typeof t)throw new rn(c);function v(n){var e=r,u=i;return r=i=o,s=n,a=t.apply(u,e)}function g(t){var e=t-f;return f===o||e>=n||e<0||d&&t-s>=u}function y(){var t=Ku();if(g(t))return m(t);l=ru(y,function(t){var e=n-(t-f);return d?$e(e,u-(t-s)):e}(t))}function m(t){return l=o,p&&r?v(t):(r=i=o,a)}function _(){var t=Ku(),e=g(t);if(r=arguments,i=this,f=t,e){if(l===o)return function(t){return s=t,l=ru(y,n),h?v(t):a}(f);if(d)return l=ru(y,n),v(f)}return l===o&&(l=ru(y,n)),a}return n=Ba(n)||0,Na(e)&&(h=!!e.leading,u=(d="maxWait"in e)?Ye(Ba(e.maxWait)||0,n):u,p="trailing"in e?!!e.trailing:p),_.cancel=function(){l!==o&&Xi(l),s=0,r=f=i=l=o},_.flush=function(){return l===o?a:m(Ku())},_}var ia=xi(function(t,n){return Lr(t,1,n)}),oa=xi(function(t,n,e){return Lr(t,Ba(n)||0,e)});function ua(t,n){if("function"!=typeof t||null!=n&&"function"!=typeof n)throw new rn(c);var e=function(){var r=arguments,i=n?n.apply(this,r):r[0],o=e.cache;if(o.has(i))return o.get(i);var u=t.apply(this,r);return e.cache=o.set(i,u)||o,u};return e.cache=new(ua.Cache||_r),e}function aa(t){if("function"!=typeof t)throw new rn(c);return function(){var n=arguments;switch(n.length){case 0:return!t.call(this);case 1:return!t.call(this,n[0]);case 2:return!t.call(this,n[0],n[1]);case 3:return!t.call(this,n[0],n[1],n[2])}return!t.apply(this,n)}}ua.Cache=_r;var ca=Vi(function(t,n){var e=(n=1==n.length&&ga(n[0])?te(n[0],ye(Do())):te(Hr(n,1),ye(Do()))).length;return xi(function(r){for(var i=-1,o=$e(r.length,e);++i=n}),va=ri(function(){return arguments}())?ri:function(t){return Sa(t)&&fn.call(t,"callee")&&!In.call(t,"callee")},ga=e.isArray,ya=Fn?ye(Fn):function(t){return Sa(t)&&Zr(t)==ct};function ma(t){return null!=t&&ka(t.length)&&!Ea(t)}function _a(t){return Sa(t)&&ma(t)}var ba=Fe||Bc,wa=qn?ye(qn):function(t){return Sa(t)&&Zr(t)==$};function xa(t){if(!Sa(t))return!1;var n=Zr(t);return n==W||n==V||"string"==typeof t.message&&"string"==typeof t.name&&!Aa(t)}function Ea(t){if(!Na(t))return!1;var n=Zr(t);return n==X||n==G||n==H||n==tt}function Ma(t){return"number"==typeof t&&t==Fa(t)}function ka(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=R}function Na(t){var n=typeof t;return null!=t&&("object"==n||"function"==n)}function Sa(t){return null!=t&&"object"==typeof t}var Ta=Bn?ye(Bn):function(t){return Sa(t)&&qo(t)==Q};function Ca(t){return"number"==typeof t||Sa(t)&&Zr(t)==Z}function Aa(t){if(!Sa(t)||Zr(t)!=J)return!1;var n=Cn(t);if(null===n)return!0;var e=fn.call(n,"constructor")&&n.constructor;return"function"==typeof e&&e instanceof e&&ln.call(e)==pn}var Pa=Hn?ye(Hn):function(t){return Sa(t)&&Zr(t)==nt};var Oa=Yn?ye(Yn):function(t){return Sa(t)&&qo(t)==et};function Ia(t){return"string"==typeof t||!ga(t)&&Sa(t)&&Zr(t)==rt}function Ra(t){return"symbol"==typeof t||Sa(t)&&Zr(t)==it}var Da=$n?ye($n):function(t){return Sa(t)&&ka(t.length)&&!!Sn[Zr(t)]};var La=_o(fi),Ua=_o(function(t,n){return t<=n});function za(t){if(!t)return[];if(ma(t))return Ia(t)?Oe(t):no(t);if(zn&&t[zn])return function(t){for(var n,e=[];!(n=t.next()).done;)e.push(n.value);return e}(t[zn]());var n=qo(t);return(n==Q?Ne:n==et?Ce:hc)(t)}function ja(t){return t?(t=Ba(t))===I||t===-I?(t<0?-1:1)*D:t==t?t:0:0===t?t:0}function Fa(t){var n=ja(t),e=n%1;return n==n?e?n-e:n:0}function qa(t){return t?Ir(Fa(t),0,U):0}function Ba(t){if("number"==typeof t)return t;if(Ra(t))return L;if(Na(t)){var n="function"==typeof t.valueOf?t.valueOf():t;t=Na(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(Rt,"");var e=$t.test(t);return e||Wt.test(t)?Pn(t.slice(2),e?2:8):Yt.test(t)?L:+t}function Ha(t){return eo(t,ic(t))}function Ya(t){return null==t?"":Di(t)}var $a=io(function(t,n){if(Qo(n)||ma(n))eo(n,rc(n),t);else for(var e in n)fn.call(n,e)&&Sr(t,e,n[e])}),Va=io(function(t,n){eo(n,ic(n),t)}),Wa=io(function(t,n,e,r){eo(n,ic(n),t,r)}),Xa=io(function(t,n,e,r){eo(n,rc(n),t,r)}),Ga=Co(Or);var Qa=xi(function(t,n){t=tn(t);var e=-1,r=n.length,i=r>2?n[2]:o;for(i&&Vo(n[0],n[1],i)&&(r=1);++e1),n}),eo(t,Po(t),e),r&&(e=Rr(e,h|d|p,So));for(var i=n.length;i--;)Ui(e,n[i]);return e});var cc=Co(function(t,n){return null==t?{}:function(t,n){return yi(t,n,function(n,e){return Ja(t,e)})}(t,n)});function lc(t,n){if(null==t)return{};var e=te(Po(t),function(t){return[t]});return n=Do(n),yi(t,e,function(t,e){return n(t,e[0])})}var fc=Eo(rc),sc=Eo(ic);function hc(t){return null==t?[]:me(t,rc(t))}var dc=co(function(t,n,e){return n=n.toLowerCase(),t+(e?pc(n):n)});function pc(t){return xc(Ya(t).toLowerCase())}function vc(t){return(t=Ya(t))&&t.replace(Gt,xe).replace(bn,"")}var gc=co(function(t,n,e){return t+(e?"-":"")+n.toLowerCase()}),yc=co(function(t,n,e){return t+(e?" ":"")+n.toLowerCase()}),mc=ao("toLowerCase");var _c=co(function(t,n,e){return t+(e?"_":"")+n.toLowerCase()});var bc=co(function(t,n,e){return t+(e?" ":"")+xc(n)});var wc=co(function(t,n,e){return t+(e?" ":"")+n.toUpperCase()}),xc=ao("toUpperCase");function Ec(t,n,e){return t=Ya(t),(n=e?o:n)===o?function(t){return Mn.test(t)}(t)?function(t){return t.match(xn)||[]}(t):function(t){return t.match(Ft)||[]}(t):t.match(n)||[]}var Mc=xi(function(t,n){try{return Vn(t,o,n)}catch(t){return xa(t)?t:new i(t)}}),kc=Co(function(t,n){return Xn(n,function(n){n=lu(n),Pr(t,n,na(t[n],t))}),t});function Nc(t){return function(){return t}}var Sc=so(),Tc=so(!0);function Cc(t){return t}function Ac(t){return ai("function"==typeof t?t:Rr(t,h))}var Pc=xi(function(t,n){return function(e){return ei(e,t,n)}}),Oc=xi(function(t,n){return function(e){return ei(t,e,n)}});function Ic(t,n,e){var r=rc(n),i=Xr(n,r);null!=e||Na(n)&&(i.length||!r.length)||(e=n,n=t,t=this,i=Xr(n,rc(n)));var o=!(Na(e)&&"chain"in e&&!e.chain),u=Ea(t);return Xn(i,function(e){var r=n[e];t[e]=r,u&&(t.prototype[e]=function(){var n=this.__chain__;if(o||n){var e=t(this.__wrapped__);return(e.__actions__=no(this.__actions__)).push({func:r,args:arguments,thisArg:t}),e.__chain__=n,e}return r.apply(t,ne([this.value()],arguments))})}),t}function Rc(){}var Dc=go(te),Lc=go(Qn),Uc=go(ie);function zc(t){return Wo(t)?he(lu(t)):function(t){return function(n){return Gr(n,t)}}(t)}var jc=mo(),Fc=mo(!0);function qc(){return[]}function Bc(){return!1}var Hc=vo(function(t,n){return t+n},0),Yc=wo("ceil"),$c=vo(function(t,n){return t/n},1),Vc=wo("floor");var Wc=vo(function(t,n){return t*n},1),Xc=wo("round"),Gc=vo(function(t,n){return t-n},0);return hr.after=function(t,n){if("function"!=typeof n)throw new rn(c);return t=Fa(t),function(){if(--t<1)return n.apply(this,arguments)}},hr.ary=Ju,hr.assign=$a,hr.assignIn=Va,hr.assignInWith=Wa,hr.assignWith=Xa,hr.at=Ga,hr.before=ta,hr.bind=na,hr.bindAll=kc,hr.bindKey=ea,hr.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return ga(t)?t:[t]},hr.chain=zu,hr.chunk=function(t,n,r){n=(r?Vo(t,n,r):n===o)?1:Ye(Fa(n),0);var i=null==t?0:t.length;if(!i||n<1)return[];for(var u=0,a=0,c=e(Ue(i/n));ui?0:i+e),(r=r===o||r>i?i:Fa(r))<0&&(r+=i),r=e>r?0:qa(r);e>>0)?(t=Ya(t))&&("string"==typeof n||null!=n&&!Pa(n))&&!(n=Di(n))&&ke(t)?Wi(Oe(t),0,e):t.split(n,e):[]},hr.spread=function(t,n){if("function"!=typeof t)throw new rn(c);return n=null==n?0:Ye(Fa(n),0),xi(function(e){var r=e[n],i=Wi(e,0,n);return r&&ne(i,r),Vn(t,this,i)})},hr.tail=function(t){var n=null==t?0:t.length;return n?Ci(t,1,n):[]},hr.take=function(t,n,e){return t&&t.length?Ci(t,0,(n=e||n===o?1:Fa(n))<0?0:n):[]},hr.takeRight=function(t,n,e){var r=null==t?0:t.length;return r?Ci(t,(n=r-(n=e||n===o?1:Fa(n)))<0?0:n,r):[]},hr.takeRightWhile=function(t,n){return t&&t.length?ji(t,Do(n,3),!1,!0):[]},hr.takeWhile=function(t,n){return t&&t.length?ji(t,Do(n,3)):[]},hr.tap=function(t,n){return n(t),t},hr.throttle=function(t,n,e){var r=!0,i=!0;if("function"!=typeof t)throw new rn(c);return Na(e)&&(r="leading"in e?!!e.leading:r,i="trailing"in e?!!e.trailing:i),ra(t,n,{leading:r,maxWait:n,trailing:i})},hr.thru=ju,hr.toArray=za,hr.toPairs=fc,hr.toPairsIn=sc,hr.toPath=function(t){return ga(t)?te(t,lu):Ra(t)?[t]:no(cu(Ya(t)))},hr.toPlainObject=Ha,hr.transform=function(t,n,e){var r=ga(t),i=r||ba(t)||Da(t);if(n=Do(n,4),null==e){var o=t&&t.constructor;e=i?r?new o:[]:Na(t)&&Ea(o)?dr(Cn(t)):{}}return(i?Xn:Vr)(t,function(t,r,i){return n(e,t,r,i)}),e},hr.unary=function(t){return Ju(t,1)},hr.union=Su,hr.unionBy=Tu,hr.unionWith=Cu,hr.uniq=function(t){return t&&t.length?Li(t):[]},hr.uniqBy=function(t,n){return t&&t.length?Li(t,Do(n,2)):[]},hr.uniqWith=function(t,n){return n="function"==typeof n?n:o,t&&t.length?Li(t,o,n):[]},hr.unset=function(t,n){return null==t||Ui(t,n)},hr.unzip=Au,hr.unzipWith=Pu,hr.update=function(t,n,e){return null==t?t:zi(t,n,Yi(e))},hr.updateWith=function(t,n,e,r){return r="function"==typeof r?r:o,null==t?t:zi(t,n,Yi(e),r)},hr.values=hc,hr.valuesIn=function(t){return null==t?[]:me(t,ic(t))},hr.without=Ou,hr.words=Ec,hr.wrap=function(t,n){return la(Yi(n),t)},hr.xor=Iu,hr.xorBy=Ru,hr.xorWith=Du,hr.zip=Lu,hr.zipObject=function(t,n){return Bi(t||[],n||[],Sr)},hr.zipObjectDeep=function(t,n){return Bi(t||[],n||[],ki)},hr.zipWith=Uu,hr.entries=fc,hr.entriesIn=sc,hr.extend=Va,hr.extendWith=Wa,Ic(hr,hr),hr.add=Hc,hr.attempt=Mc,hr.camelCase=dc,hr.capitalize=pc,hr.ceil=Yc,hr.clamp=function(t,n,e){return e===o&&(e=n,n=o),e!==o&&(e=(e=Ba(e))==e?e:0),n!==o&&(n=(n=Ba(n))==n?n:0),Ir(Ba(t),n,e)},hr.clone=function(t){return Rr(t,p)},hr.cloneDeep=function(t){return Rr(t,h|p)},hr.cloneDeepWith=function(t,n){return Rr(t,h|p,n="function"==typeof n?n:o)},hr.cloneWith=function(t,n){return Rr(t,p,n="function"==typeof n?n:o)},hr.conformsTo=function(t,n){return null==n||Dr(t,n,rc(n))},hr.deburr=vc,hr.defaultTo=function(t,n){return null==t||t!=t?n:t},hr.divide=$c,hr.endsWith=function(t,n,e){t=Ya(t),n=Di(n);var r=t.length,i=e=e===o?r:Ir(Fa(e),0,r);return(e-=n.length)>=0&&t.slice(e,i)==n},hr.eq=ha,hr.escape=function(t){return(t=Ya(t))&&kt.test(t)?t.replace(Et,Ee):t},hr.escapeRegExp=function(t){return(t=Ya(t))&&It.test(t)?t.replace(Ot,"\\$&"):t},hr.every=function(t,n,e){var r=ga(t)?Qn:Fr;return e&&Vo(t,n,e)&&(n=o),r(t,Do(n,3))},hr.find=Bu,hr.findIndex=vu,hr.findKey=function(t,n){return ue(t,Do(n,3),Vr)},hr.findLast=Hu,hr.findLastIndex=gu,hr.findLastKey=function(t,n){return ue(t,Do(n,3),Wr)},hr.floor=Vc,hr.forEach=Yu,hr.forEachRight=$u,hr.forIn=function(t,n){return null==t?t:Yr(t,Do(n,3),ic)},hr.forInRight=function(t,n){return null==t?t:$r(t,Do(n,3),ic)},hr.forOwn=function(t,n){return t&&Vr(t,Do(n,3))},hr.forOwnRight=function(t,n){return t&&Wr(t,Do(n,3))},hr.get=Ka,hr.gt=da,hr.gte=pa,hr.has=function(t,n){return null!=t&&Bo(t,n,Jr)},hr.hasIn=Ja,hr.head=mu,hr.identity=Cc,hr.includes=function(t,n,e,r){t=ma(t)?t:hc(t),e=e&&!r?Fa(e):0;var i=t.length;return e<0&&(e=Ye(i+e,0)),Ia(t)?e<=i&&t.indexOf(n,e)>-1:!!i&&ce(t,n,e)>-1},hr.indexOf=function(t,n,e){var r=null==t?0:t.length;if(!r)return-1;var i=null==e?0:Fa(e);return i<0&&(i=Ye(r+i,0)),ce(t,n,i)},hr.inRange=function(t,n,e){return n=ja(n),e===o?(e=n,n=0):e=ja(e),function(t,n,e){return t>=$e(n,e)&&t=-R&&t<=R},hr.isSet=Oa,hr.isString=Ia,hr.isSymbol=Ra,hr.isTypedArray=Da,hr.isUndefined=function(t){return t===o},hr.isWeakMap=function(t){return Sa(t)&&qo(t)==ut},hr.isWeakSet=function(t){return Sa(t)&&Zr(t)==at},hr.join=function(t,n){return null==t?"":Be.call(t,n)},hr.kebabCase=gc,hr.last=xu,hr.lastIndexOf=function(t,n,e){var r=null==t?0:t.length;if(!r)return-1;var i=r;return e!==o&&(i=(i=Fa(e))<0?Ye(r+i,0):$e(i,r-1)),n==n?function(t,n,e){for(var r=e+1;r--;)if(t[r]===n)return r;return r}(t,n,i):ae(t,fe,i,!0)},hr.lowerCase=yc,hr.lowerFirst=mc,hr.lt=La,hr.lte=Ua,hr.max=function(t){return t&&t.length?qr(t,Cc,Kr):o},hr.maxBy=function(t,n){return t&&t.length?qr(t,Do(n,2),Kr):o},hr.mean=function(t){return se(t,Cc)},hr.meanBy=function(t,n){return se(t,Do(n,2))},hr.min=function(t){return t&&t.length?qr(t,Cc,fi):o},hr.minBy=function(t,n){return t&&t.length?qr(t,Do(n,2),fi):o},hr.stubArray=qc,hr.stubFalse=Bc,hr.stubObject=function(){return{}},hr.stubString=function(){return""},hr.stubTrue=function(){return!0},hr.multiply=Wc,hr.nth=function(t,n){return t&&t.length?vi(t,Fa(n)):o},hr.noConflict=function(){return Rn._===this&&(Rn._=vn),this},hr.noop=Rc,hr.now=Ku,hr.pad=function(t,n,e){t=Ya(t);var r=(n=Fa(n))?Pe(t):0;if(!n||r>=n)return t;var i=(n-r)/2;return yo(ze(i),e)+t+yo(Ue(i),e)},hr.padEnd=function(t,n,e){t=Ya(t);var r=(n=Fa(n))?Pe(t):0;return n&&rn){var r=t;t=n,n=r}if(e||t%1||n%1){var i=Xe();return $e(t+i*(n-t+An("1e-"+((i+"").length-1))),n)}return bi(t,n)},hr.reduce=function(t,n,e){var r=ga(t)?ee:pe,i=arguments.length<3;return r(t,Do(n,4),e,i,zr)},hr.reduceRight=function(t,n,e){var r=ga(t)?re:pe,i=arguments.length<3;return r(t,Do(n,4),e,i,jr)},hr.repeat=function(t,n,e){return n=(e?Vo(t,n,e):n===o)?1:Fa(n),wi(Ya(t),n)},hr.replace=function(){var t=arguments,n=Ya(t[0]);return t.length<3?n:n.replace(t[1],t[2])},hr.result=function(t,n,e){var r=-1,i=(n=$i(n,t)).length;for(i||(i=1,t=o);++rR)return[];var e=U,r=$e(t,U);n=Do(n),t-=U;for(var i=ge(r,n);++e=u)return t;var c=e-Pe(r);if(c<1)return r;var l=a?Wi(a,0,c).join(""):t.slice(0,c);if(i===o)return l+r;if(a&&(c+=l.length-c),Pa(i)){if(t.slice(c).search(i)){var f,s=l;for(i.global||(i=nn(i.source,Ya(Ht.exec(i))+"g")),i.lastIndex=0;f=i.exec(s);)var h=f.index;l=l.slice(0,h===o?c:h)}}else if(t.indexOf(Di(i),c)!=c){var d=l.lastIndexOf(i);d>-1&&(l=l.slice(0,d))}return l+r},hr.unescape=function(t){return(t=Ya(t))&&Mt.test(t)?t.replace(xt,Ie):t},hr.uniqueId=function(t){var n=++sn;return Ya(t)+n},hr.upperCase=wc,hr.upperFirst=xc,hr.each=Yu,hr.eachRight=$u,hr.first=mu,Ic(hr,function(){var t={};return Vr(hr,function(n,e){fn.call(hr.prototype,e)||(t[e]=n)}),t}(),{chain:!1}),hr.VERSION="4.17.11",Xn(["bind","bindKey","curry","curryRight","partial","partialRight"],function(t){hr[t].placeholder=hr}),Xn(["drop","take"],function(t,n){gr.prototype[t]=function(e){e=e===o?1:Ye(Fa(e),0);var r=this.__filtered__&&!n?new gr(this):this.clone();return r.__filtered__?r.__takeCount__=$e(e,r.__takeCount__):r.__views__.push({size:$e(e,U),type:t+(r.__dir__<0?"Right":"")}),r},gr.prototype[t+"Right"]=function(n){return this.reverse()[t](n).reverse()}}),Xn(["filter","map","takeWhile"],function(t,n){var e=n+1,r=e==P||3==e;gr.prototype[t]=function(t){var n=this.clone();return n.__iteratees__.push({iteratee:Do(t,3),type:e}),n.__filtered__=n.__filtered__||r,n}}),Xn(["head","last"],function(t,n){var e="take"+(n?"Right":"");gr.prototype[t]=function(){return this[e](1).value()[0]}}),Xn(["initial","tail"],function(t,n){var e="drop"+(n?"":"Right");gr.prototype[t]=function(){return this.__filtered__?new gr(this):this[e](1)}}),gr.prototype.compact=function(){return this.filter(Cc)},gr.prototype.find=function(t){return this.filter(t).head()},gr.prototype.findLast=function(t){return this.reverse().find(t)},gr.prototype.invokeMap=xi(function(t,n){return"function"==typeof t?new gr(this):this.map(function(e){return ei(e,t,n)})}),gr.prototype.reject=function(t){return this.filter(aa(Do(t)))},gr.prototype.slice=function(t,n){t=Fa(t);var e=this;return e.__filtered__&&(t>0||n<0)?new gr(e):(t<0?e=e.takeRight(-t):t&&(e=e.drop(t)),n!==o&&(e=(n=Fa(n))<0?e.dropRight(-n):e.take(n-t)),e)},gr.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},gr.prototype.toArray=function(){return this.take(U)},Vr(gr.prototype,function(t,n){var e=/^(?:filter|find|map|reject)|While$/.test(n),r=/^(?:head|last)$/.test(n),i=hr[r?"take"+("last"==n?"Right":""):n],u=r||/^find/.test(n);i&&(hr.prototype[n]=function(){var n=this.__wrapped__,a=r?[1]:arguments,c=n instanceof gr,l=a[0],f=c||ga(n),s=function(t){var n=i.apply(hr,ne([t],a));return r&&h?n[0]:n};f&&e&&"function"==typeof l&&1!=l.length&&(c=f=!1);var h=this.__chain__,d=!!this.__actions__.length,p=u&&!h,v=c&&!d;if(!u&&f){n=v?n:new gr(this);var g=t.apply(n,a);return g.__actions__.push({func:ju,args:[s],thisArg:o}),new vr(g,h)}return p&&v?t.apply(this,a):(g=this.thru(s),p?r?g.value()[0]:g.value():g)})}),Xn(["pop","push","shift","sort","splice","unshift"],function(t){var n=on[t],e=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",r=/^(?:pop|shift)$/.test(t);hr.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var i=this.value();return n.apply(ga(i)?i:[],t)}return this[e](function(e){return n.apply(ga(e)?e:[],t)})}}),Vr(gr.prototype,function(t,n){var e=hr[n];if(e){var r=e.name+"";(rr[r]||(rr[r]=[])).push({name:n,func:e})}}),rr[ho(o,m).name]=[{name:"wrapper",func:o}],gr.prototype.clone=function(){var t=new gr(this.__wrapped__);return t.__actions__=no(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=no(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=no(this.__views__),t},gr.prototype.reverse=function(){if(this.__filtered__){var t=new gr(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},gr.prototype.value=function(){var t=this.__wrapped__.value(),n=this.__dir__,e=ga(t),r=n<0,i=e?t.length:0,o=function(t,n,e){for(var r=-1,i=e.length;++r=this.__values__.length;return{done:t,value:t?o:this.__values__[this.__index__++]}},hr.prototype.plant=function(t){for(var n,e=this;e instanceof pr;){var r=su(e);r.__index__=0,r.__values__=o,n?i.__wrapped__=r:n=r;var i=r;e=e.__wrapped__}return i.__wrapped__=t,n},hr.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof gr){var n=t;return this.__actions__.length&&(n=new gr(this)),(n=n.reverse()).__actions__.push({func:ju,args:[Nu],thisArg:o}),new vr(n,this.__chain__)}return this.thru(Nu)},hr.prototype.toJSON=hr.prototype.valueOf=hr.prototype.value=function(){return Fi(this.__wrapped__,this.__actions__)},hr.prototype.first=hr.prototype.head,zn&&(hr.prototype[zn]=function(){return this}),hr}();Rn._=Re,(i=function(){return Re}.call(n,e,n,r))===o||(r.exports=i)}).call(this)}).call(this,e(21),e(22)(t))},function(t,n){t.exports="2.1.5"},function(t,n,e){var r=e(3),i=e(12);t.exports={write:function(t){var n={options:{directed:t.isDirected(),multigraph:t.isMultigraph(),compound:t.isCompound()},nodes:function(t){return r.map(t.nodes(),function(n){var e=t.node(n),i=t.parent(n),o={v:n};return r.isUndefined(e)||(o.value=e),r.isUndefined(i)||(o.parent=i),o})}(t),edges:function(t){return r.map(t.edges(),function(n){var e=t.edge(n),i={v:n.v,w:n.w};return r.isUndefined(n.name)||(i.name=n.name),r.isUndefined(e)||(i.value=e),i})}(t)};r.isUndefined(t.graph())||(n.value=r.clone(t.graph()));return n},read:function(t){var n=new i(t.options).setGraph(t.value);return r.each(t.nodes,function(t){n.setNode(t.v,t.value),t.parent&&n.setParent(t.v,t.parent)}),r.each(t.edges,function(t){n.setEdge({v:t.v,w:t.w,name:t.name},t.value)}),n}}},function(t,n,e){t.exports={components:e(52),dijkstra:e(23),dijkstraAll:e(53),findCycles:e(54),floydWarshall:e(55),isAcyclic:e(56),postorder:e(57),preorder:e(58),prim:e(59),tarjan:e(25),topsort:e(26)}},function(t,n,e){var r=e(3);t.exports=function(t){var n,e={},i=[];function o(i){r.has(e,i)||(e[i]=!0,n.push(i),r.each(t.successors(i),o),r.each(t.predecessors(i),o))}return r.each(t.nodes(),function(t){n=[],o(t),n.length&&i.push(n)}),i}},function(t,n,e){var r=e(23),i=e(3);t.exports=function(t,n,e){return i.transform(t.nodes(),function(i,o){i[o]=r(t,o,n,e)},{})}},function(t,n,e){var r=e(3),i=e(25);t.exports=function(t){return r.filter(i(t),function(n){return n.length>1||1===n.length&&t.hasEdge(n[0],n[0])})}},function(t,n,e){var r=e(3);t.exports=function(t,n,e){return function(t,n,e){var r={},i=t.nodes();return i.forEach(function(t){r[t]={},r[t][t]={distance:0},i.forEach(function(n){t!==n&&(r[t][n]={distance:Number.POSITIVE_INFINITY})}),e(t).forEach(function(e){var i=e.v===t?e.w:e.v,o=n(e);r[t][i]={distance:o,predecessor:t}})}),i.forEach(function(t){var n=r[t];i.forEach(function(e){var o=r[e];i.forEach(function(e){var r=o[t],i=n[e],u=o[e],a=r.distance+i.distance;a0;){if(e=c.removeMin(),r.has(a,e))u.setEdge(e,a[e]);else{if(f)throw new Error("Input graph is not connected: "+t);f=!0}t.nodeEdges(e).forEach(l)}return u}},function(t,n,e){t.exports={graphlib:e(5),layout:e(61),debug:e(83),util:{time:e(1).time,notime:e(1).notime},version:e(84)}},function(t,n,e){"use strict";var r=e(0),i=e(62),o=e(65),u=e(66),a=e(1).normalizeRanks,c=e(68),l=e(1).removeEmptyRanks,f=e(69),s=e(70),h=e(71),d=e(72),p=e(81),v=e(1),g=e(5).Graph;t.exports=function(t,n){var e=n&&n.debugTiming?v.time:v.notime;e("layout",function(){var n=e(" buildLayoutGraph",function(){return function(t){var n=new g({multigraph:!0,compound:!0}),e=N(t.graph());return n.setGraph(r.merge({},m,k(e,y),r.pick(e,_))),r.forEach(t.nodes(),function(e){var i=N(t.node(e));n.setNode(e,r.defaults(k(i,b),w)),n.setParent(e,t.parent(e))}),r.forEach(t.edges(),function(e){var i=N(t.edge(e));n.setEdge(e,r.merge({},E,k(i,x),r.pick(i,M)))}),n}(t)});e(" runLayout",function(){!function(t,n){n(" makeSpaceForEdgeLabels",function(){!function(t){var n=t.graph();n.ranksep/=2,r.forEach(t.edges(),function(e){var r=t.edge(e);r.minlen*=2,"c"!==r.labelpos.toLowerCase()&&("TB"===n.rankdir||"BT"===n.rankdir?r.width+=r.labeloffset:r.height+=r.labeloffset)})}(t)}),n(" removeSelfEdges",function(){!function(t){r.forEach(t.edges(),function(n){if(n.v===n.w){var e=t.node(n.v);e.selfEdges||(e.selfEdges=[]),e.selfEdges.push({e:n,label:t.edge(n)}),t.removeEdge(n)}})}(t)}),n(" acyclic",function(){i.run(t)}),n(" nestingGraph.run",function(){f.run(t)}),n(" rank",function(){u(v.asNonCompoundGraph(t))}),n(" injectEdgeLabelProxies",function(){!function(t){r.forEach(t.edges(),function(n){var e=t.edge(n);if(e.width&&e.height){var r=t.node(n.v),i=t.node(n.w),o={rank:(i.rank-r.rank)/2+r.rank,e:n};v.addDummyNode(t,"edge-proxy",o,"_ep")}})}(t)}),n(" removeEmptyRanks",function(){l(t)}),n(" nestingGraph.cleanup",function(){f.cleanup(t)}),n(" normalizeRanks",function(){a(t)}),n(" assignRankMinMax",function(){!function(t){var n=0;r.forEach(t.nodes(),function(e){var i=t.node(e);i.borderTop&&(i.minRank=t.node(i.borderTop).rank,i.maxRank=t.node(i.borderBottom).rank,n=r.max(n,i.maxRank))}),t.graph().maxRank=n}(t)}),n(" removeEdgeLabelProxies",function(){!function(t){r.forEach(t.nodes(),function(n){var e=t.node(n);"edge-proxy"===e.dummy&&(t.edge(e.e).labelRank=e.rank,t.removeNode(n))})}(t)}),n(" normalize.run",function(){o.run(t)}),n(" parentDummyChains",function(){c(t)}),n(" addBorderSegments",function(){s(t)}),n(" order",function(){d(t)}),n(" insertSelfEdges",function(){!function(t){var n=v.buildLayerMatrix(t);r.forEach(n,function(n){var e=0;r.forEach(n,function(n,i){var o=t.node(n);o.order=i+e,r.forEach(o.selfEdges,function(n){v.addDummyNode(t,"selfedge",{width:n.label.width,height:n.label.height,rank:o.rank,order:i+ ++e,e:n.e,label:n.label},"_se")}),delete o.selfEdges})})}(t)}),n(" adjustCoordinateSystem",function(){h.adjust(t)}),n(" position",function(){p(t)}),n(" positionSelfEdges",function(){!function(t){r.forEach(t.nodes(),function(n){var e=t.node(n);if("selfedge"===e.dummy){var r=t.node(e.e.v),i=r.x+r.width/2,o=r.y,u=e.x-i,a=r.height/2;t.setEdge(e.e,e.label),t.removeNode(n),e.label.points=[{x:i+2*u/3,y:o-a},{x:i+5*u/6,y:o-a},{x:i+u,y:o},{x:i+5*u/6,y:o+a},{x:i+2*u/3,y:o+a}],e.label.x=e.x,e.label.y=e.y}})}(t)}),n(" removeBorderNodes",function(){!function(t){r.forEach(t.nodes(),function(n){if(t.children(n).length){var e=t.node(n),i=t.node(e.borderTop),o=t.node(e.borderBottom),u=t.node(r.last(e.borderLeft)),a=t.node(r.last(e.borderRight));e.width=Math.abs(a.x-u.x),e.height=Math.abs(o.y-i.y),e.x=u.x+e.width/2,e.y=i.y+e.height/2}}),r.forEach(t.nodes(),function(n){"border"===t.node(n).dummy&&t.removeNode(n)})}(t)}),n(" normalize.undo",function(){o.undo(t)}),n(" fixupEdgeLabelCoords",function(){!function(t){r.forEach(t.edges(),function(n){var e=t.edge(n);if(r.has(e,"x"))switch("l"!==e.labelpos&&"r"!==e.labelpos||(e.width-=e.labeloffset),e.labelpos){case"l":e.x-=e.width/2+e.labeloffset;break;case"r":e.x+=e.width/2+e.labeloffset}})}(t)}),n(" undoCoordinateSystem",function(){h.undo(t)}),n(" translateGraph",function(){!function(t){var n=Number.POSITIVE_INFINITY,e=0,i=Number.POSITIVE_INFINITY,o=0,u=t.graph(),a=u.marginx||0,c=u.marginy||0;function l(t){var r=t.x,u=t.y,a=t.width,c=t.height;n=Math.min(n,r-a/2),e=Math.max(e,r+a/2),i=Math.min(i,u-c/2),o=Math.max(o,u+c/2)}r.forEach(t.nodes(),function(n){l(t.node(n))}),r.forEach(t.edges(),function(n){var e=t.edge(n);r.has(e,"x")&&l(e)}),n-=a,i-=c,r.forEach(t.nodes(),function(e){var r=t.node(e);r.x-=n,r.y-=i}),r.forEach(t.edges(),function(e){var o=t.edge(e);r.forEach(o.points,function(t){t.x-=n,t.y-=i}),r.has(o,"x")&&(o.x-=n),r.has(o,"y")&&(o.y-=i)}),u.width=e-n+a,u.height=o-i+c}(t)}),n(" assignNodeIntersects",function(){!function(t){r.forEach(t.edges(),function(n){var e,r,i=t.edge(n),o=t.node(n.v),u=t.node(n.w);i.points?(e=i.points[0],r=i.points[i.points.length-1]):(i.points=[],e=u,r=o),i.points.unshift(v.intersectRect(o,e)),i.points.push(v.intersectRect(u,r))})}(t)}),n(" reversePoints",function(){!function(t){r.forEach(t.edges(),function(n){var e=t.edge(n);e.reversed&&e.points.reverse()})}(t)}),n(" acyclic.undo",function(){i.undo(t)})}(n,e)}),e(" updateInputGraph",function(){!function(t,n){r.forEach(t.nodes(),function(e){var r=t.node(e),i=n.node(e);r&&(r.x=i.x,r.y=i.y,n.children(e).length&&(r.width=i.width,r.height=i.height))}),r.forEach(t.edges(),function(e){var i=t.edge(e),o=n.edge(e);i.points=o.points,r.has(o,"x")&&(i.x=o.x,i.y=o.y)}),t.graph().width=n.graph().width,t.graph().height=n.graph().height}(t,n)})})};var y=["nodesep","edgesep","ranksep","marginx","marginy"],m={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},_=["acyclicer","ranker","rankdir","align"],b=["width","height"],w={width:0,height:0},x=["minlen","weight","width","height","labeloffset"],E={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},M=["labelpos"];function k(t,n){return r.mapValues(r.pick(t,n),Number)}function N(t){var n={};return r.forEach(t,function(t,e){n[e.toLowerCase()]=t}),n}},function(t,n,e){"use strict";var r=e(0),i=e(63);t.exports={run:function(t){var n="greedy"===t.graph().acyclicer?i(t,function(t){return function(n){return t.edge(n).weight}}(t)):function(t){var n=[],e={},i={};return r.forEach(t.nodes(),function o(u){r.has(i,u)||(i[u]=!0,e[u]=!0,r.forEach(t.outEdges(u),function(t){r.has(e,t.w)?n.push(t):o(t.w)}),delete e[u])}),n}(t);r.forEach(n,function(n){var e=t.edge(n);t.removeEdge(n),e.forwardName=n.name,e.reversed=!0,t.setEdge(n.w,n.v,e,r.uniqueId("rev"))})},undo:function(t){r.forEach(t.edges(),function(n){var e=t.edge(n);if(e.reversed){t.removeEdge(n);var r=e.forwardName;delete e.reversed,delete e.forwardName,t.setEdge(n.w,n.v,e,r)}})}}},function(t,n,e){var r=e(0),i=e(5).Graph,o=e(64);t.exports=function(t,n){if(t.nodeCount()<=1)return[];var e=function(t,n){var e=new i,u=0,a=0;r.forEach(t.nodes(),function(t){e.setNode(t,{v:t,in:0,out:0})}),r.forEach(t.edges(),function(t){var r=e.edge(t.v,t.w)||0,i=n(t),o=r+i;e.setEdge(t.v,t.w,o),a=Math.max(a,e.node(t.v).out+=i),u=Math.max(u,e.node(t.w).in+=i)});var l=r.range(a+u+3).map(function(){return new o}),f=u+1;return r.forEach(e.nodes(),function(t){c(l,f,e.node(t))}),{graph:e,buckets:l,zeroIdx:f}}(t,n||u),l=function(t,n,e){var r,i=[],o=n[n.length-1],u=n[0];for(;t.nodeCount();){for(;r=u.dequeue();)a(t,n,e,r);for(;r=o.dequeue();)a(t,n,e,r);if(t.nodeCount())for(var c=n.length-2;c>0;--c)if(r=n[c].dequeue()){i=i.concat(a(t,n,e,r,!0));break}}return i}(e.graph,e.buckets,e.zeroIdx);return r.flatten(r.map(l,function(n){return t.outEdges(n.v,n.w)}),!0)};var u=r.constant(1);function a(t,n,e,i,o){var u=o?[]:void 0;return r.forEach(t.inEdges(i.v),function(r){var i=t.edge(r),a=t.node(r.v);o&&u.push({v:r.v,w:r.w}),a.out-=i,c(n,e,a)}),r.forEach(t.outEdges(i.v),function(r){var i=t.edge(r),o=r.w,u=t.node(o);u.in-=i,c(n,e,u)}),t.removeNode(i.v),u}function c(t,n,e){e.out?e.in?t[e.out-e.in+n].enqueue(e):t[t.length-1].enqueue(e):t[0].enqueue(e)}},function(t,n){function e(){var t={};t._next=t._prev=t,this._sentinel=t}function r(t){t._prev._next=t._next,t._next._prev=t._prev,delete t._next,delete t._prev}function i(t,n){if("_next"!==t&&"_prev"!==t)return n}t.exports=e,e.prototype.dequeue=function(){var t=this._sentinel,n=t._prev;if(n!==t)return r(n),n},e.prototype.enqueue=function(t){var n=this._sentinel;t._prev&&t._next&&r(t),t._next=n._next,n._next._prev=t,n._next=t,t._prev=n},e.prototype.toString=function(){for(var t=[],n=this._sentinel,e=n._prev;e!==n;)t.push(JSON.stringify(e,i)),e=e._prev;return"["+t.join(", ")+"]"}},function(t,n,e){"use strict";var r=e(0),i=e(1);t.exports={run:function(t){t.graph().dummyChains=[],r.forEach(t.edges(),function(n){!function(t,n){var e,r,o,u=n.v,a=t.node(u).rank,c=n.w,l=t.node(c).rank,f=n.name,s=t.edge(n),h=s.labelRank;if(l===a+1)return;for(t.removeEdge(n),o=0,++a;ac.lim&&(l=c,f=!0);var s=r.filter(n.edges(),function(n){return f===y(t,t.node(n.v),l)&&f!==y(t,t.node(n.w),l)});return r.minBy(s,function(t){return o(n,t)})}function g(t,n,e,i){var o=e.v,u=e.w;t.removeEdge(o,u),t.setEdge(i.v,i.w,{}),d(t),s(t,n),function(t,n){var e=r.find(t.nodes(),function(t){return!n.node(t).parent}),i=a(t,e);i=i.slice(1),r.forEach(i,function(e){var r=t.node(e).parent,i=n.edge(e,r),o=!1;i||(i=n.edge(r,e),o=!0),n.node(e).rank=n.node(r).rank+(o?i.minlen:-i.minlen)})}(t,n)}function y(t,n,e){return e.low<=n.lim&&n.lim<=e.lim}t.exports=f,f.initLowLimValues=d,f.initCutValues=s,f.calcCutValue=h,f.leaveEdge=p,f.enterEdge=v,f.exchangeEdges=g},function(t,n,e){var r=e(0);t.exports=function(t){var n=function(t){var n={},e=0;return r.forEach(t.children(),function i(o){var u=e;r.forEach(t.children(o),i),n[o]={low:u,lim:e++}}),n}(t);r.forEach(t.graph().dummyChains,function(e){for(var r=t.node(e),i=r.edgeObj,o=function(t,n,e,r){var i,o,u=[],a=[],c=Math.min(n[e].low,n[r].low),l=Math.max(n[e].lim,n[r].lim);i=e;do{i=t.parent(i),u.push(i)}while(i&&(n[i].low>c||l>n[i].lim));o=i,i=r;for(;(i=t.parent(i))!==o;)a.push(i);return{path:u.concat(a.reverse()),lca:o}}(t,n,i.v,i.w),u=o.path,a=o.lca,c=0,l=u[c],f=!0;e!==i.w;){if(r=t.node(e),f){for(;(l=u[c])!==a&&t.node(l).maxRank=2),a=f.buildLayerMatrix(t);var g=o(t,a);g0;)n%2&&(e+=c[n+1]),c[n=n-1>>1]+=t.weight;l+=t.weight*e})),l}t.exports=function(t,n){for(var e=0,r=1;r=t.barycenter)&&function(t,n){var e=0,r=0;t.weight&&(e+=t.barycenter*t.weight,r+=t.weight),n.weight&&(e+=n.barycenter*n.weight,r+=n.weight),t.vs=n.vs.concat(t.vs),t.barycenter=e/r,t.weight=r,t.i=Math.min(n.i,t.i),n.merged=!0}(t,n)}}function i(n){return function(e){e.in.push(n),0==--e.indegree&&t.push(e)}}for(;t.length;){var o=t.pop();n.push(o),r.forEach(o.in.reverse(),e(o)),r.forEach(o.out,i(o))}return r.chain(n).filter(function(t){return!t.merged}).map(function(t){return r.pick(t,["vs","i","barycenter","weight"])}).value()}(r.filter(e,function(t){return!t.indegree}))}},function(t,n,e){var r=e(0),i=e(1);function o(t,n,e){for(var i;n.length&&(i=r.last(n)).i<=e;)n.pop(),t.push(i.vs),e++;return e}t.exports=function(t,n){var e=i.partition(t,function(t){return r.has(t,"barycenter")}),u=e.lhs,a=r.sortBy(e.rhs,function(t){return-t.i}),c=[],l=0,f=0,s=0;u.sort(function(t){return function(n,e){return n.barycentere.barycenter?1:t?e.i-n.i:n.i-e.i}}(!!n)),s=o(c,a,s),r.forEach(u,function(t){s+=t.vs.length,c.push(t.vs),l+=t.barycenter*t.weight,f+=t.weight,s=o(c,a,s)});var h={vs:r.flatten(c,!0)};f&&(h.barycenter=l/f,h.weight=f);return h}},function(t,n,e){var r=e(0),i=e(5).Graph;t.exports=function(t,n,e){var o=function(t){var n;for(;t.hasNode(n=r.uniqueId("_root")););return n}(t),u=new i({compound:!0}).setGraph({root:o}).setDefaultNodeLabel(function(n){return t.node(n)});return r.forEach(t.nodes(),function(i){var a=t.node(i),c=t.parent(i);(a.rank===n||a.minRank<=n&&n<=a.maxRank)&&(u.setNode(i),u.setParent(i,c||o),r.forEach(t[e](i),function(n){var e=n.v===i?n.w:n.v,o=u.edge(e,i),a=r.isUndefined(o)?0:o.weight;u.setEdge(e,i,{weight:t.edge(n).weight+a})}),r.has(a,"minRank")&&u.setNode(i,{borderLeft:a.borderLeft[n],borderRight:a.borderRight[n]}))}),u}},function(t,n,e){var r=e(0);t.exports=function(t,n,e){var i,o={};r.forEach(e,function(e){for(var r,u,a=t.parent(e);a;){if((r=t.parent(a))?(u=o[r],o[r]=a):(u=i,i=a),u&&u!==a)return void n.setEdge(u,a);a=r}})}},function(t,n,e){"use strict";var r=e(0),i=e(1),o=e(82).positionX;t.exports=function(t){(function(t){var n=i.buildLayerMatrix(t),e=t.graph().ranksep,o=0;r.forEach(n,function(n){var i=r.max(r.map(n,function(n){return t.node(n).height}));r.forEach(n,function(n){t.node(n).y=o+i/2}),o+=i+e})})(t=i.asNonCompoundGraph(t)),r.forEach(o(t),function(n,e){t.node(e).x=n})}},function(t,n,e){"use strict";var r=e(0),i=e(5).Graph,o=e(1);function u(t,n){var e={};return r.reduce(n,function(n,i){var o=0,u=0,a=n.length,l=r.last(i);return r.forEach(i,function(n,f){var s=function(t,n){if(t.node(n).dummy)return r.find(t.predecessors(n),function(n){return t.node(n).dummy})}(t,n),h=s?t.node(s).order:a;(s||n===l)&&(r.forEach(i.slice(u,f+1),function(n){r.forEach(t.predecessors(n),function(r){var i=t.node(r),u=i.order;!(ua)&&c(e,n,l)})})}return r.reduce(n,function(n,e){var o,u=-1,a=0;return r.forEach(e,function(r,c){if("border"===t.node(r).dummy){var l=t.predecessors(r);l.length&&(o=t.node(l[0]).order,i(e,a,c,u,o),a=c,u=o)}i(e,a,e.length,o,n.length)}),e}),e}function c(t,n,e){if(n>e){var r=n;n=e,e=r}var i=t[n];i||(t[n]=i={}),i[e]=!0}function l(t,n,e){if(n>e){var i=n;n=e,e=i}return r.has(t[n],e)}function f(t,n,e,i){var o={},u={},a={};return r.forEach(n,function(t){r.forEach(t,function(t,n){o[t]=t,u[t]=t,a[t]=n})}),r.forEach(n,function(t){var n=-1;r.forEach(t,function(t){var c=i(t);if(c.length)for(var f=((c=r.sortBy(c,function(t){return a[t]})).length-1)/2,s=Math.floor(f),h=Math.ceil(f);s<=h;++s){var d=c[s];u[t]===t&&n0}t.exports=function(t,n,r,i){var o,u,a,c,l,f,s,h,d,p,v,g,y;if(o=n.y-t.y,a=t.x-n.x,l=n.x*t.y-t.x*n.y,d=o*r.x+a*r.y+l,p=o*i.x+a*i.y+l,0!==d&&0!==p&&e(d,p))return;if(u=i.y-r.y,c=r.x-i.x,f=i.x*r.y-r.x*i.y,s=u*t.x+c*t.y+f,h=u*n.x+c*n.y+f,0!==s&&0!==h&&e(s,h))return;if(0==(v=o*c-u*a))return;return g=Math.abs(v/2),{x:(y=a*f-c*l)<0?(y-g)/v:(y+g)/v,y:(y=u*l-o*f)<0?(y-g)/v:(y+g)/v}}},function(t,n,e){var r=e(10),i=e(8),o=e(28).layout;t.exports=function(){var t=e(88),n=e(92),i=e(93),l=e(94),f=e(95),s=e(96),h=e(97),d=e(98),p=e(99),v=function(e,v){!function(t){t.nodes().forEach(function(n){var e=t.node(n);r.has(e,"label")||t.children(n).length||(e.label=n),r.has(e,"paddingX")&&r.defaults(e,{paddingLeft:e.paddingX,paddingRight:e.paddingX}),r.has(e,"paddingY")&&r.defaults(e,{paddingTop:e.paddingY,paddingBottom:e.paddingY}),r.has(e,"padding")&&r.defaults(e,{paddingLeft:e.padding,paddingRight:e.padding,paddingTop:e.padding,paddingBottom:e.padding}),r.defaults(e,u),r.each(["paddingLeft","paddingRight","paddingTop","paddingBottom"],function(t){e[t]=Number(e[t])}),r.has(e,"width")&&(e._prevWidth=e.width),r.has(e,"height")&&(e._prevHeight=e.height)}),t.edges().forEach(function(n){var e=t.edge(n);r.has(e,"label")||(e.label=""),r.defaults(e,a)})}(v),e.selectAll("*").remove();var g=c(e,"output"),y=c(g,"clusters"),m=c(g,"edgePaths"),_=i(c(g,"edgeLabels"),v),b=t(c(g,"nodes"),v,d);o(v),f(b,v),s(_,v),l(m,v,p);var w=n(y,v);h(w,v),function(t){r.each(t.nodes(),function(n){var e=t.node(n);r.has(e,"_prevWidth")?e.width=e._prevWidth:delete e.width,r.has(e,"_prevHeight")?e.height=e._prevHeight:delete e.height,delete e._prevWidth,delete e._prevHeight})}(v)};return v.createNodes=function(n){return arguments.length?(t=n,v):t},v.createClusters=function(t){return arguments.length?(n=t,v):n},v.createEdgeLabels=function(t){return arguments.length?(i=t,v):i},v.createEdgePaths=function(t){return arguments.length?(l=t,v):l},v.shapes=function(t){return arguments.length?(d=t,v):d},v.arrows=function(t){return arguments.length?(p=t,v):p},v};var u={paddingLeft:10,paddingRight:10,paddingTop:10,paddingBottom:10,rx:0,ry:0,shape:"rect"},a={arrowhead:"normal",curve:i.curveLinear};function c(t,n){var e=t.select("g."+n);return e.empty()&&(e=t.append("g").attr("class",n)),e}},function(t,n,e){"use strict";var r=e(10),i=e(14),o=e(4),u=e(8);t.exports=function(t,n,e){var a=n.nodes().filter(function(t){return!o.isSubgraph(n,t)}),c=t.selectAll("g.node").data(a,function(t){return t}).classed("update",!0);return c.selectAll("*").remove(),c.enter().append("g").attr("class","node").style("opacity",0),(c=t.selectAll("g.node")).each(function(t){var a=n.node(t),c=u.select(this);o.applyClass(c,a.class,(c.classed("update")?"update ":"")+"node");var l=c.append("g").attr("class","label"),f=i(l,a),s=e[a.shape],h=r.pick(f.node().getBBox(),"width","height");a.elem=this,a.id&&c.attr("id",a.id),a.labelId&&l.attr("id",a.labelId),r.has(a,"width")&&(h.width=a.width),r.has(a,"height")&&(h.height=a.height),h.width+=a.paddingLeft+a.paddingRight,h.height+=a.paddingTop+a.paddingBottom,l.attr("transform","translate("+(a.paddingLeft-a.paddingRight)/2+","+(a.paddingTop-a.paddingBottom)/2+")");var d=s(u.select(this),h,a);o.applyStyle(d,a.style);var p=d.node().getBBox();a.width=p.width,a.height=p.height}),o.applyTransition(c.exit(),n).style("opacity",0).remove(),c}},function(t,n,e){var r=e(4);t.exports=function(t,n){for(var e=t.append("text"),i=function(t){for(var n,e="",r=!1,i=0;in?1:t>=n?0:NaN},i=function(t){return 1===t.length&&(t=function(t){return function(n,e){return r(t(n),e)}}(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)>0?i=o:r=o+1}return r}}};var o=i(r),u=o.right,a=o.left,c=u,l=function(t,n){null==n&&(n=f);for(var e=0,r=t.length-1,i=t[0],o=new Array(r<0?0:r);et?1:n>=t?0:NaN},d=function(t){return null===t?NaN:+t},p=function(t,n){var e,r,i=t.length,o=0,u=-1,a=0,c=0;if(null==n)for(;++u1)return c/(o-1)},v=function(t,n){var e=p(t,n);return e?Math.sqrt(e):e},g=function(t,n){var e,r,i,o=t.length,u=-1;if(null==n){for(;++u=e)for(r=i=e;++ue&&(r=e),i=e)for(r=i=e;++ue&&(r=e),i0)return[t];if((r=n0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++a=0?(o>=E?10:o>=M?5:o>=k?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=E?10:o>=M?5:o>=k?2:1)}function T(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=E?i*=10:o>=M?i*=5:o>=k&&(i*=2),ns;)h.pop(),--d;var p,v=new Array(d+1);for(i=0;i<=d;++i)(p=v[i]=[]).x0=i>0?h[i-1]:f,p.x1=i=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}},O=function(t,n,e){return t=_.call(t,d).sort(r),Math.ceil((e-n)/(2*(P(t,.75)-P(t,.25))*Math.pow(t.length,-1/3)))},I=function(t,n,e){return Math.ceil((e-n)/(3.5*v(t)*Math.pow(t.length,-1/3)))},R=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o=e)for(r=e;++or&&(r=e)}else for(;++o=e)for(r=e;++or&&(r=e);return r},D=function(t,n){var e,r=t.length,i=r,o=-1,u=0;if(null==n)for(;++o=0;)for(n=(r=t[i]).length;--n>=0;)e[--u]=r[n];return e},z=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o=e)for(r=e;++oe&&(r=e)}else for(;++o=e)for(r=e;++oe&&(r=e);return r},j=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},F=function(t,n){if(e=t.length){var e,i,o=0,u=0,a=t[u];for(null==n&&(n=r);++o=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),pt.hasOwnProperty(n)?{space:pt[n],local:t}:t};var gt=function(t){var n=vt(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===dt&&n.documentElement.namespaceURI===dt?n.createElement(t):n.createElementNS(e,t)}})(n)};function yt(){}var mt=function(t){return null==t?yt:function(){return this.querySelector(t)}};function _t(){return[]}var bt=function(t){return null==t?_t:function(){return this.querySelectorAll(t)}},wt=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var xt=document.documentElement;if(!xt.matches){var Et=xt.webkitMatchesSelector||xt.msMatchesSelector||xt.mozMatchesSelector||xt.oMatchesSelector;wt=function(t){return function(){return Et.call(this,t)}}}}var Mt=wt,kt=function(t){return new Array(t.length)};function Nt(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}Nt.prototype={constructor:Nt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var St="$";function Tt(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var Pt=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function Ot(t,n){return t.style.getPropertyValue(n)||Pt(t).getComputedStyle(t,null).getPropertyValue(n)}function It(t){return t.trim().split(/^|\s+/)}function Rt(t){return t.classList||new Dt(t)}function Dt(t){this._node=t,this._names=It(t.getAttribute("class")||"")}function Lt(t,n){for(var e=Rt(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function zt(){this.textContent=""}function jt(){this.innerHTML=""}function Ft(){this.nextSibling&&this.parentNode.appendChild(this)}function qt(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function Bt(){return null}function Ht(){var t=this.parentNode;t&&t.removeChild(this)}function Yt(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function $t(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var Vt={},Wt=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(Vt={mouseenter:"mouseover",mouseleave:"mouseout"}));function Xt(t,n,e){return t=Gt(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function Gt(t,n,e){return function(r){var i=Wt;Wt=r;try{t.call(this,this.__data__,n,e)}finally{Wt=i}}}function Qt(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=At);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):Ot(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=It(t+"");if(arguments.length<2){for(var r=Rt(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?Zt:Qt,null==e&&(e=!1),r=0;r>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=xn.exec(t))?Pn(parseInt(n[1],16)):(n=En.exec(t))?new Dn(n[1],n[2],n[3],1):(n=Mn.exec(t))?new Dn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=kn.exec(t))?On(n[1],n[2],n[3],n[4]):(n=Nn.exec(t))?On(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Sn.exec(t))?Un(n[1],n[2]/100,n[3]/100,1):(n=Tn.exec(t))?Un(n[1],n[2]/100,n[3]/100,n[4]):Cn.hasOwnProperty(t)?Pn(Cn[t]):"transparent"===t?new Dn(NaN,NaN,NaN,0):null}function Pn(t){return new Dn(t>>16&255,t>>8&255,255&t,1)}function On(t,n,e,r){return r<=0&&(t=n=e=NaN),new Dn(t,n,e,r)}function In(t){return t instanceof yn||(t=An(t)),t?new Dn((t=t.rgb()).r,t.g,t.b,t.opacity):new Dn}function Rn(t,n,e,r){return 1===arguments.length?In(t):new Dn(t,n,e,null==r?1:r)}function Dn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ln(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Un(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new jn(t,n,e,r)}function zn(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof jn)return new jn(t.h,t.s,t.l,t.opacity);if(t instanceof yn||(t=An(t)),!t)return new jn;if(t instanceof jn)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new jn(u,a,c,t.opacity)}(t):new jn(t,n,e,null==r?1:r)}function jn(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Fn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}vn(yn,An,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),vn(Dn,Rn,gn(yn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Dn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Dn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+Ln(this.r)+Ln(this.g)+Ln(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),vn(jn,zn,gn(yn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new jn(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new jn(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new Dn(Fn(t>=240?t-240:t+120,i,r),Fn(t,i,r),Fn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var qn=Math.PI/180,Bn=180/Math.PI,Hn=.96422,Yn=1,$n=.82521,Vn=4/29,Wn=6/29,Xn=3*Wn*Wn,Gn=Wn*Wn*Wn;function Qn(t){if(t instanceof Kn)return new Kn(t.l,t.a,t.b,t.opacity);if(t instanceof oe){if(isNaN(t.h))return new Kn(t.l,0,0,t.opacity);var n=t.h*qn;return new Kn(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof Dn||(t=In(t));var e,r,i=ee(t.r),o=ee(t.g),u=ee(t.b),a=Jn((.2225045*i+.7168786*o+.0606169*u)/Yn);return i===o&&o===u?e=r=a:(e=Jn((.4360747*i+.3850649*o+.1430804*u)/Hn),r=Jn((.0139322*i+.0971045*o+.7141733*u)/$n)),new Kn(116*a-16,500*(e-a),200*(a-r),t.opacity)}function Zn(t,n,e,r){return 1===arguments.length?Qn(t):new Kn(t,n,e,null==r?1:r)}function Kn(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Jn(t){return t>Gn?Math.pow(t,1/3):t/Xn+Vn}function te(t){return t>Wn?t*t*t:Xn*(t-Vn)}function ne(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function ee(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function re(t){if(t instanceof oe)return new oe(t.h,t.c,t.l,t.opacity);if(t instanceof Kn||(t=Qn(t)),0===t.a&&0===t.b)return new oe(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*Bn;return new oe(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function ie(t,n,e,r){return 1===arguments.length?re(t):new oe(t,n,e,null==r?1:r)}function oe(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}vn(Kn,Zn,gn(yn,{brighter:function(t){return new Kn(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Kn(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new Dn(ne(3.1338561*(n=Hn*te(n))-1.6168667*(t=Yn*te(t))-.4906146*(e=$n*te(e))),ne(-.9787684*n+1.9161415*t+.033454*e),ne(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),vn(oe,ie,gn(yn,{brighter:function(t){return new oe(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new oe(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return Qn(this).rgb()}}));var ue=-.29227,ae=-.90649,ce=1.97294,le=ce*ae,fe=1.78277*ce,se=1.78277*ue- -.14861*ae;function he(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof de)return new de(t.h,t.s,t.l,t.opacity);t instanceof Dn||(t=In(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(se*r+le*n-fe*e)/(se+le-fe),o=r-i,u=(ce*(e-i)-ue*o)/ae,a=Math.sqrt(u*u+o*o)/(ce*i*(1-i)),c=a?Math.atan2(u,o)*Bn-120:NaN;return new de(c<0?c+360:c,a,i,t.opacity)}(t):new de(t,n,e,null==r?1:r)}function de(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function pe(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}vn(de,he,gn(yn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new de(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new de(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*qn,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new Dn(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(ue*r+ae*i)),255*(n+e*(ce*r)),this.opacity)}}));var ve=function(t){return function(){return t}};function ge(t,n){return function(e){return t+e*n}}function ye(t,n){var e=n-t;return e?ge(t,e>180||e<-180?e-360*Math.round(e/360):e):ve(isNaN(t)?n:t)}function me(t){return 1==(t=+t)?_e:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):ve(isNaN(n)?e:n)}}function _e(t,n){var e=n-t;return e?ge(t,e):ve(isNaN(t)?n:t)}var be=function t(n){var e=me(n);function r(t,n){var r=e((t=Rn(t)).r,(n=Rn(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=_e(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function we(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:xe(e,r)})),o=Me.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:xe(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:xe(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:xe(t,e)},{i:a-2,x:xe(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e=0&&n._call.call(null,t),n=n._next;--Be}()}finally{Be=0,function(){var t,n,e=Fe,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Fe=n);qe=t,rr(r)}(),We=0}}function er(){var t=Ge.now(),n=t-Ve;n>$e&&(Xe-=n,Ve=t)}function rr(t){Be||(He&&(He=clearTimeout(He)),t-We>24?(t<1/0&&(He=setTimeout(nr,t-Ge.now()-Xe)),Ye&&(Ye=clearInterval(Ye))):(Ye||(Ve=Ge.now(),Ye=setInterval(er,$e)),Be=1,Qe(nr)))}Je.prototype=tr.prototype={constructor:Je,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Ze():+e)+(null==n?0:+n),this._next||qe===this||(qe?qe._next=this:Fe=this,qe=this),this._call=t,this._time=e,rr()},stop:function(){this._call&&(this._call=null,this._time=1/0,rr())}};var ir=function(t,n,e){var r=new Je;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},or=ht("start","end","interrupt"),ur=[],ar=0,cr=1,lr=2,fr=3,sr=4,hr=5,dr=6,pr=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(c){var l,f,s,h;if(e.state!==cr)return a();for(l in i)if((h=i[l]).name===e.name){if(h.state===fr)return ir(o);h.state===sr?(h.state=dr,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[l]):+lar)throw new Error("too late; already scheduled");return e}function gr(t,n){var e=yr(t,n);if(e.state>lr)throw new Error("too late; already started");return e}function yr(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}var mr=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>lr&&e.state=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?vr:gr;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}(e,t,n))},attr:function(t,n){var e=vt(t),r="transform"===e?Le:br;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}})(e,r,_r(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}:function(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}})(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=vt(t);return this.tween(e,(r.local?function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}:function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?De:br;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=Ot(this,t),u=(this.style.removeProperty(t),Ot(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}(t,r)).on("end.style."+t,function(t){return function(){this.style.removeProperty(t)}}(t)):this.styleTween(t,"function"==typeof n?function(t,n,e){var r,i,o;return function(){var u=Ot(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=Ot(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}(t,r,_r(this,"style."+t,n)):function(t,n,e){var r,i;return function(){var o=Ot(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(_r(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=yr(this.node(),e).tween,o=0,u=i.length;o0&&(e=i-d),x<0?s=h-p:x>0&&(o=u-p),b=Rr,D.attr("cursor",Fr.selection),z());break;default:return}Or()},!0).on("keyup.brush",function(){switch(Wt.keyCode){case 16:A&&(g=y=A=!1,z());break;case 18:b===Lr&&(w<0?l=f:w>0&&(e=i),x<0?s=h:x>0&&(o=u),b=Dr,z());break;case 32:b===Rr&&(Wt.altKey?(w&&(l=f-d*w,e=i+d*w),x&&(s=h-p*x,o=u+p*x),b=Lr):(w<0?l=f:w>0&&(e=i),x<0?s=h:x>0&&(o=u),b=Dr),D.attr("cursor",Fr[_]),z());break;default:return}Or()},!0).on("mousemove.brush",U,!0).on("mouseup.brush",j,!0);hn(Wt.view)}Pr(),mr(m),a.call(m),I.start()}function U(){var t=fn(m);!A||g||y||(Math.abs(t[0]-O[0])>Math.abs(t[1]-O[1])?y=!0:g=!0),O=t,v=!0,Or(),z()}function z(){var t;switch(d=O[0]-P[0],p=O[1]-P[1],b){case Rr:case Ir:w&&(d=Math.max(N-e,Math.min(T-l,d)),i=e+d,f=l+d),x&&(p=Math.max(S-o,Math.min(C-s,p)),u=o+p,h=s+p);break;case Dr:w<0?(d=Math.max(N-e,Math.min(T-e,d)),i=e+d,f=l):w>0&&(d=Math.max(N-l,Math.min(T-l,d)),i=e,f=l+d),x<0?(p=Math.max(S-o,Math.min(C-o,p)),u=o+p,h=s):x>0&&(p=Math.max(S-s,Math.min(C-s,p)),u=o,h=s+p);break;case Lr:w&&(i=Math.max(N,Math.min(T,e-d*w)),f=Math.max(N,Math.min(T,l+d*w))),x&&(u=Math.max(S,Math.min(C,o-p*x)),h=Math.max(S,Math.min(C,s+p*x)))}fn?1:t>=n?0:NaN};var ei=function(t){return 1===t.length&&(t=function(t){return function(n,e){return ni(t(n),e)}}(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}(ni);ei.right,ei.left;var ri=Array.prototype,ii=(ri.slice,ri.map,function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r1e-6)if(Math.abs(f*a-c*l)>1e-6&&i){var h=e-o,d=r-u,p=a*a+c*c,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(s),m=i*Math.tan((pi-Math.acos((p+s-v)/(2*g*y)))/2),_=m/y,b=m/g;Math.abs(_-1)>1e-6&&(this._+="L"+(t+_*l)+","+(n+_*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>l*d)+","+(this._x1=t+b*a)+","+(this._y1=n+b*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,l=n+a,f=1^o,s=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+l:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-l)>1e-6)&&(this._+="L"+c+","+l),e&&(s<0&&(s=s%vi+vi),s>gi?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=l):s>1e-6&&(this._+="A"+e+","+e+",0,"+ +(s>=pi)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var _i=mi;function bi(t){return t.source}function wi(t){return t.target}function xi(t){return t.radius}function Ei(t){return t.startAngle}function Mi(t){return t.endAngle}var ki=function(){var t=bi,n=wi,e=xi,r=Ei,i=Mi,o=null;function u(){var u,a=hi.call(arguments),c=t.apply(this,a),l=n.apply(this,a),f=+e.apply(this,(a[0]=c,a)),s=r.apply(this,a)-ci,h=i.apply(this,a)-ci,d=f*oi(s),p=f*ui(s),v=+e.apply(this,(a[0]=l,a)),g=r.apply(this,a)-ci,y=i.apply(this,a)-ci;if(o||(o=u=_i()),o.moveTo(d,p),o.arc(0,0,f,s,h),s===g&&h===y||(o.quadraticCurveTo(0,0,v*oi(g),v*ui(g)),o.arc(0,0,v,g,y)),o.quadraticCurveTo(0,0,d,p),o.closePath(),u)return o=null,u+""||null}return u.radius=function(t){return arguments.length?(e="function"==typeof t?t:di(+t),u):e},u.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:di(+t),u):r},u.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:di(+t),u):i},u.source=function(n){return arguments.length?(t=n,u):t},u.target=function(t){return arguments.length?(n=t,u):n},u.context=function(t){return arguments.length?(o=null==t?null:t,u):o},u};function Ni(){}function Si(t,n){var e=new Ni;if(t instanceof Ni)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i=r.length)return null!=t&&e.sort(t),null!=n?n(e):e;for(var c,l,f,s=-1,h=e.length,d=r[i++],p=Ti(),v=u();++sr.length)return e;var u,a=i[o-1];return null!=n&&o>=r.length?u=e.entries():(u=[],e.each(function(n,e){u.push({key:e,values:t(n,o)})})),null!=a?u.sort(function(t,n){return a(t.key,n.key)}):u}(o(t,0,Oi,Ii),0)},key:function(t){return r.push(t),e},sortKeys:function(t){return i[r.length-1]=t,e},sortValues:function(n){return t=n,e},rollup:function(t){return n=t,e}}};function Ai(){return{}}function Pi(t,n,e){t[n]=e}function Oi(){return Ti()}function Ii(t,n,e){t.set(n,e)}function Ri(){}var Di=Ti.prototype;function Li(t,n){var e=new Ri;if(t instanceof Ri)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=Xi.exec(t))?ro(parseInt(n[1],16)):(n=Gi.exec(t))?new ao(n[1],n[2],n[3],1):(n=Qi.exec(t))?new ao(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Zi.exec(t))?io(n[1],n[2],n[3],n[4]):(n=Ki.exec(t))?io(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Ji.exec(t))?co(n[1],n[2]/100,n[3]/100,1):(n=to.exec(t))?co(n[1],n[2]/100,n[3]/100,n[4]):no.hasOwnProperty(t)?ro(no[t]):"transparent"===t?new ao(NaN,NaN,NaN,0):null}function ro(t){return new ao(t>>16&255,t>>8&255,255&t,1)}function io(t,n,e,r){return r<=0&&(t=n=e=NaN),new ao(t,n,e,r)}function oo(t){return t instanceof Hi||(t=eo(t)),t?new ao((t=t.rgb()).r,t.g,t.b,t.opacity):new ao}function uo(t,n,e,r){return 1===arguments.length?oo(t):new ao(t,n,e,null==r?1:r)}function ao(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function co(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new fo(t,n,e,r)}function lo(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof fo)return new fo(t.h,t.s,t.l,t.opacity);if(t instanceof Hi||(t=eo(t)),!t)return new fo;if(t instanceof fo)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new fo(u,a,c,t.opacity)}(t):new fo(t,n,e,null==r?1:r)}function fo(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function so(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}qi(Hi,eo,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+""}}),qi(ao,uo,Bi(Hi,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new ao(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new ao(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),qi(fo,lo,Bi(Hi,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new fo(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new fo(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new ao(so(t>=240?t-240:t+120,i,r),so(t,i,r),so(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var ho=Math.PI/180,po=180/Math.PI,vo=.95047,go=1,yo=1.08883,mo=4/29,_o=6/29,bo=3*_o*_o,wo=_o*_o*_o;function xo(t){if(t instanceof Mo)return new Mo(t.l,t.a,t.b,t.opacity);if(t instanceof Ao){var n=t.h*ho;return new Mo(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof ao||(t=oo(t));var e=To(t.r),r=To(t.g),i=To(t.b),o=ko((.4124564*e+.3575761*r+.1804375*i)/vo),u=ko((.2126729*e+.7151522*r+.072175*i)/go);return new Mo(116*u-16,500*(o-u),200*(u-ko((.0193339*e+.119192*r+.9503041*i)/yo)),t.opacity)}function Eo(t,n,e,r){return 1===arguments.length?xo(t):new Mo(t,n,e,null==r?1:r)}function Mo(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function ko(t){return t>wo?Math.pow(t,1/3):t/bo+mo}function No(t){return t>_o?t*t*t:bo*(t-mo)}function So(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function To(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Co(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof Ao)return new Ao(t.h,t.c,t.l,t.opacity);t instanceof Mo||(t=xo(t));var n=Math.atan2(t.b,t.a)*po;return new Ao(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}(t):new Ao(t,n,e,null==r?1:r)}function Ao(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}qi(Mo,Eo,Bi(Hi,{brighter:function(t){return new Mo(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Mo(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=go*No(t),new ao(So(3.2404542*(n=vo*No(n))-1.5371385*t-.4985314*(e=yo*No(e))),So(-.969266*n+1.8760108*t+.041556*e),So(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),qi(Ao,Co,Bi(Hi,{brighter:function(t){return new Ao(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Ao(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return xo(this).rgb()}}));var Po=-.29227,Oo=-.90649,Io=1.97294,Ro=Io*Oo,Do=1.78277*Io,Lo=1.78277*Po- -.14861*Oo;function Uo(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof zo)return new zo(t.h,t.s,t.l,t.opacity);t instanceof ao||(t=oo(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Lo*r+Ro*n-Do*e)/(Lo+Ro-Do),o=r-i,u=(Io*(e-i)-Po*o)/Oo,a=Math.sqrt(u*u+o*o)/(Io*i*(1-i)),c=a?Math.atan2(u,o)*po-120:NaN;return new zo(c<0?c+360:c,a,i,t.opacity)}(t):new zo(t,n,e,null==r?1:r)}function zo(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}qi(zo,Uo,Bi(Hi,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new zo(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new zo(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*ho,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new ao(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(Po*r+Oo*i)),255*(n+e*(Io*r)),this.opacity)}}));var jo={value:function(){}};function Fo(){for(var t,n=0,e=arguments.length,r={};n=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Ko.hasOwnProperty(n)?{space:Ko[n],local:t}:t};var tu=function(t){var n=Jo(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===Zo&&n.documentElement.namespaceURI===Zo?n.createElement(t):n.createElementNS(e,t)}})(n)};function nu(){}var eu=function(t){return null==t?nu:function(){return this.querySelector(t)}};function ru(){return[]}var iu=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var ou=document.documentElement;if(!ou.matches){var uu=ou.webkitMatchesSelector||ou.msMatchesSelector||ou.mozMatchesSelector||ou.oMatchesSelector;iu=function(t){return function(){return uu.call(this,t)}}}}var au=iu,cu=function(t){return new Array(t.length)};function lu(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}lu.prototype={constructor:lu,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var fu="$";function su(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var pu=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function vu(t){return t.trim().split(/^|\s+/)}function gu(t){return t.classList||new yu(t)}function yu(t){this._node=t,this._names=vu(t.getAttribute("class")||"")}function mu(t,n){for(var e=gu(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function bu(){this.textContent=""}function wu(){this.innerHTML=""}function xu(){this.nextSibling&&this.parentNode.appendChild(this)}function Eu(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function Mu(){return null}function ku(){var t=this.parentNode;t&&t.removeChild(this)}function Nu(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function Su(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var Tu={},Cu=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(Tu={mouseenter:"mouseover",mouseleave:"mouseout"}));function Au(t,n,e){return t=Pu(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function Pu(t,n,e){return function(r){var i=Cu;Cu=r;try{t.call(this,this.__data__,n,e)}finally{Cu=i}}}function Ou(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=du);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):function(t,n){return t.style.getPropertyValue(n)||pu(t).getComputedStyle(t,null).getPropertyValue(n)}(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=vu(t+"");if(arguments.length<2){for(var r=gu(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?Iu:Ou,null==e&&(e=!1),r=0;rs}c.mouse("drag")}function v(){ju(Cu.view).on("mousemove.drag mouseup.drag",null),Gu(Cu.view,e),Wu(),c.mouse("end")}function g(){if(i.apply(this,arguments)){var t,n,e=Cu.changedTouches,r=o.apply(this,arguments),u=e.length;for(t=0;t=o?c=!0:(r=t.charCodeAt(u++))===ua?l=!0:r===aa&&(l=!0,t.charCodeAt(u)===ua&&++u),t.slice(i+1,n-1).replace(/""/g,'"')}for(;u=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(g+m)/2))?g=u:m=u,i=d,!(d=d[s=f<<1|l]))return i[s]=p,t;if(a=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===a&&e===c)return p.next=d,i?i[s]=p:t._root=p,t;do{i=i?i[s]=new Array(4):t._root=new Array(4),(l=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(g+m)/2))?g=u:m=u}while((s=f<<1|l)==(h=(c>=u)<<1|a>=o));return i[h]=d,i[s]=p,t}var sc=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i};function hc(t){return t[0]}function dc(t){return t[1]}function pc(t,n,e){var r=new vc(null==n?hc:n,null==e?dc:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function vc(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function gc(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var yc=pc.prototype=vc.prototype;function mc(t){return t.x+t.vx}function _c(t){return t.y+t.vy}yc.copy=function(){var t,n,e=new vc(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=gc(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=gc(n));return e},yc.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return fc(this.cover(n,e),n,e,t)},yc.addAll=function(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,l=1/0,f=-1/0,s=-1/0;for(e=0;ef&&(f=r),is&&(s=i));for(ft||t>i||r>n||n>o))return this;var u,a,c=i-e,l=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{(u=new Array(4))[a]=l,l=u}while(o=r+(c*=2),t>(i=e+c)||n>o);break;case 1:do{(u=new Array(4))[a]=l,l=u}while(o=r+(c*=2),(e=i-c)>t||n>o);break;case 2:do{(u=new Array(4))[a]=l,l=u}while(r=o-(c*=2),t>(i=e+c)||r>n);break;case 3:do{(u=new Array(4))[a]=l,l=u}while(r=o-(c*=2),(e=i-c)>t||r>n)}this._root&&this._root.length&&(this._root=l)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},yc.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},yc.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},yc.find=function(t,n,e){var r,i,o,u,a,c,l,f=this._x0,s=this._y0,h=this._x1,d=this._y1,p=[],v=this._root;for(v&&p.push(new sc(v,f,s,h,d)),null==e?e=1/0:(f=t-e,s=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>d||(u=c.x1)=y)<<1|t>=g)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-l],p[p.length-1-l]=c)}else{var m=t-+this._x.call(null,v.data),_=n-+this._y.call(null,v.data),b=m*m+_*_;if(b=(a=(p+g)/2))?p=a:g=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=d,!(d=d[s=f<<1|l]))return this;if(!d.length)break;(n[s+1&3]||n[s+2&3]||n[s+3&3])&&(e=n,h=s)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[s]=i:delete n[s],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},yc.removeAll=function(t){for(var n=0,e=t.length;nc+d||il+d||oa.index){var p=c-u.x-u.vx,v=l-u.y-u.vy,g=p*p+v*v;gt.r&&(t.r=t[n].r)}function a(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&n._call.call(null,t),n=n._next;--zc}()}finally{zc=0,function(){var t,n,e=Dc,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Dc=n);Lc=t,Jc(r)}(),Hc=0}}function Kc(){var t=$c.now(),n=t-Bc;n>qc&&(Yc-=n,Bc=t)}function Jc(t){zc||(jc&&(jc=clearTimeout(jc)),t-Hc>24?(t<1/0&&(jc=setTimeout(Zc,t-$c.now()-Yc)),Fc&&(Fc=clearInterval(Fc))):(Fc||(Bc=$c.now(),Fc=setInterval(Kc,qc)),zc=1,Vc(Zc)))}Gc.prototype=Qc.prototype={constructor:Gc,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Wc():+e)+(null==n?0:+n),this._next||Lc===this||(Lc?Lc._next=this:Dc=this,Lc=this),this._call=t,this._time=e,Jc()},stop:function(){this._call&&(this._call=null,this._time=1/0,Jc())}};function tl(t){return t.x}function nl(t){return t.y}var el,rl=10,il=Math.PI*(3-Math.sqrt(5)),ol=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,u=.6,a=Ec(),c=Qc(f),l=Uc("tick","end");function f(){s(),l.call("tick",n),e1?(null==e?a.remove(t):a.set(t,d(e)),n):a.get(t)},find:function(n,e,r){var i,o,u,a,c,l=0,f=t.length;for(null==r?r=1/0:r*=r,l=0;l1?(l.on(t,e),n):l.on(t)}}},ul=function(){var t,n,e,r,i=cc(-30),o=1,u=1/0,a=.81;function c(r){var i,o=t.length,u=pc(t,tl,nl).visitAfter(f);for(e=r,i=0;i=u)){(t.data!==n||t.next)&&(0===f&&(d+=(f=lc())*f),0===s&&(d+=(s=lc())*s),d1?r[0]+r.slice(2):r,+t.slice(e+1)]},sl=function(t){return(t=fl(Math.abs(t)))?t[1]:NaN},hl=function(t,n){var e=fl(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},dl={"":function(t,n){t=t.toPrecision(n);t:for(var e,r=t.length,i=1,o=-1;i0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return hl(100*t,n)},r:hl,s:function(t,n){var e=fl(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(el=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+fl(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},pl=/^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;function vl(t){return new gl(t)}function gl(t){if(!(n=pl.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],l=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,f="g"):dl[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=l,this.type=f}vl.prototype=gl.prototype,gl.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var yl,ml,_l,bl=function(t){return t},wl=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],xl=function(t){var n=t.grouping&&t.thousands?function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}}(t.grouping,t.thousands):bl,e=t.currency,r=t.decimal,i=t.numerals?function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}}(t.numerals):bl,o=t.percent||"%";function u(t){var u=(t=vl(t)).fill,a=t.align,c=t.sign,l=t.symbol,f=t.zero,s=t.width,h=t.comma,d=t.precision,p=t.type,v="$"===l?e[0]:"#"===l&&/[boxX]/.test(p)?"0"+p.toLowerCase():"",g="$"===l?e[1]:/[%p]/.test(p)?o:"",y=dl[p],m=!p||/[defgprs%]/.test(p);function _(t){var e,o,l,_=v,b=g;if("c"===p)b=y(t)+b,t="";else{var w=(t=+t)<0;if(t=y(Math.abs(t),d),w&&0==+t&&(w=!1),_=(w?"("===c?c:"-":"-"===c||"("===c?"":c)+_,b=("s"===p?wl[8+el/3]:"")+b+(w&&"("===c?")":""),m)for(e=-1,o=t.length;++e(l=t.charCodeAt(e))||l>57){b=(46===l?r+t.slice(e+1):t.slice(e))+b,t=t.slice(0,e);break}}h&&!f&&(t=n(t,1/0));var x=_.length+t.length+b.length,E=x>1)+_+t+b+E.slice(x);break;default:t=E+_+t+b}return i(t)}return d=null==d?p?6:12:/[gprs]/.test(p)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),_.toString=function(){return t+""},_}return{format:u,formatPrefix:function(t,n){var e=u(((t=vl(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(sl(n)/3))),i=Math.pow(10,-r),o=wl[8+r/3];return function(t){return e(i*t)+o}}}};function El(t){return yl=xl(t),ml=yl.format,_l=yl.formatPrefix,yl}El({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var Ml=function(t){return Math.max(0,-sl(Math.abs(t)))},kl=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(sl(n)/3)))-sl(Math.abs(t)))},Nl=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,sl(n)-sl(t))+1},Sl=function(){return new Tl};function Tl(){this.reset()}Tl.prototype={constructor:Tl,reset:function(){this.s=this.t=0},add:function(t){Al(Cl,t,this.t),Al(this,Cl.s,this.s),this.s?this.t+=Cl.t:this.s=Cl.t},valueOf:function(){return this.s}};var Cl=new Tl;function Al(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}var Pl=1e-6,Ol=Math.PI,Il=Ol/2,Rl=Ol/4,Dl=2*Ol,Ll=180/Ol,Ul=Ol/180,zl=Math.abs,jl=Math.atan,Fl=Math.atan2,ql=Math.cos,Bl=Math.ceil,Hl=Math.exp,Yl=(Math.floor,Math.log),$l=Math.pow,Vl=Math.sin,Wl=Math.sign||function(t){return t>0?1:t<0?-1:0},Xl=Math.sqrt,Gl=Math.tan;function Ql(t){return t>1?0:t<-1?Ol:Math.acos(t)}function Zl(t){return t>1?Il:t<-1?-Il:Math.asin(t)}function Kl(t){return(t=Vl(t/2))*t}function Jl(){}function tf(t,n){t&&ef.hasOwnProperty(t.type)&&ef[t.type](t,n)}var nf={Feature:function(t,n){tf(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r=0?1:-1,i=r*e,o=ql(n),u=Vl(n),a=ff*u,c=lf*o+a*ql(i),l=a*r*Vl(i);hf.add(Fl(l,c)),cf=t,lf=o,ff=u}var _f=function(t){return df.reset(),sf(t,pf),2*df};function bf(t){return[Fl(t[1],t[0]),Zl(t[2])]}function wf(t){var n=t[0],e=t[1],r=ql(e);return[r*ql(n),r*Vl(n),Vl(e)]}function xf(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Ef(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Mf(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function kf(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function Nf(t){var n=Xl(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var Sf,Tf,Cf,Af,Pf,Of,If,Rf,Df,Lf,Uf=Sl(),zf={point:jf,lineStart:qf,lineEnd:Bf,polygonStart:function(){zf.point=Hf,zf.lineStart=Yf,zf.lineEnd=$f,Uf.reset(),pf.polygonStart()},polygonEnd:function(){pf.polygonEnd(),zf.point=jf,zf.lineStart=qf,zf.lineEnd=Bf,hf<0?(Sf=-(Cf=180),Tf=-(Af=90)):Uf>Pl?Af=90:Uf<-Pl&&(Tf=-90),Lf[0]=Sf,Lf[1]=Cf}};function jf(t,n){Df.push(Lf=[Sf=t,Cf=t]),nAf&&(Af=n)}function Ff(t,n){var e=wf([t*Ul,n*Ul]);if(Rf){var r=Ef(Rf,e),i=Ef([r[1],-r[0],0],r);Nf(i),i=bf(i);var o,u=t-Pf,a=u>0?1:-1,c=i[0]*Ll*a,l=zl(u)>180;l^(a*PfAf&&(Af=o):l^(a*Pf<(c=(c+360)%360-180)&&cAf&&(Af=n)),l?tVf(Sf,Cf)&&(Cf=t):Vf(t,Cf)>Vf(Sf,Cf)&&(Sf=t):Cf>=Sf?(tCf&&(Cf=t)):t>Pf?Vf(Sf,t)>Vf(Sf,Cf)&&(Cf=t):Vf(t,Cf)>Vf(Sf,Cf)&&(Sf=t)}else Df.push(Lf=[Sf=t,Cf=t]);nAf&&(Af=n),Rf=e,Pf=t}function qf(){zf.point=Ff}function Bf(){Lf[0]=Sf,Lf[1]=Cf,zf.point=jf,Rf=null}function Hf(t,n){if(Rf){var e=t-Pf;Uf.add(zl(e)>180?e+(e>0?360:-360):e)}else Of=t,If=n;pf.point(t,n),Ff(t,n)}function Yf(){pf.lineStart()}function $f(){Hf(Of,If),pf.lineEnd(),zl(Uf)>Pl&&(Sf=-(Cf=180)),Lf[0]=Sf,Lf[1]=Cf,Rf=null}function Vf(t,n){return(n-=t)<0?n+360:n}function Wf(t,n){return t[0]-n[0]}function Xf(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:nVf(r[0],r[1])&&(r[1]=i[1]),Vf(i[0],r[1])>Vf(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(a=Vf(r[1],i[0]))>u&&(u=a,Sf=i[0],Cf=r[1])}return Df=Lf=null,Sf===1/0||Tf===1/0?[[NaN,NaN],[NaN,NaN]]:[[Sf,Tf],[Cf,Af]]},hs={sphere:Jl,point:ds,lineStart:vs,lineEnd:ms,polygonStart:function(){hs.lineStart=_s,hs.lineEnd=bs},polygonEnd:function(){hs.lineStart=vs,hs.lineEnd=ms}};function ds(t,n){t*=Ul;var e=ql(n*=Ul);ps(e*ql(t),e*Vl(t),Vl(n))}function ps(t,n,e){Zf+=(t-Zf)/++Gf,Kf+=(n-Kf)/Gf,Jf+=(e-Jf)/Gf}function vs(){hs.point=gs}function gs(t,n){t*=Ul;var e=ql(n*=Ul);cs=e*ql(t),ls=e*Vl(t),fs=Vl(n),hs.point=ys,ps(cs,ls,fs)}function ys(t,n){t*=Ul;var e=ql(n*=Ul),r=e*ql(t),i=e*Vl(t),o=Vl(n),u=Fl(Xl((u=ls*o-fs*i)*u+(u=fs*r-cs*o)*u+(u=cs*i-ls*r)*u),cs*r+ls*i+fs*o);Qf+=u,ts+=u*(cs+(cs=r)),ns+=u*(ls+(ls=i)),es+=u*(fs+(fs=o)),ps(cs,ls,fs)}function ms(){hs.point=ds}function _s(){hs.point=ws}function bs(){xs(us,as),hs.point=ds}function ws(t,n){us=t,as=n,t*=Ul,n*=Ul,hs.point=xs;var e=ql(n);cs=e*ql(t),ls=e*Vl(t),fs=Vl(n),ps(cs,ls,fs)}function xs(t,n){t*=Ul;var e=ql(n*=Ul),r=e*ql(t),i=e*Vl(t),o=Vl(n),u=ls*o-fs*i,a=fs*r-cs*o,c=cs*i-ls*r,l=Xl(u*u+a*a+c*c),f=Zl(l),s=l&&-f/l;rs+=s*u,is+=s*a,os+=s*c,Qf+=f,ts+=f*(cs+(cs=r)),ns+=f*(ls+(ls=i)),es+=f*(fs+(fs=o)),ps(cs,ls,fs)}var Es=function(t){Gf=Qf=Zf=Kf=Jf=ts=ns=es=rs=is=os=0,sf(t,hs);var n=rs,e=is,r=os,i=n*n+e*e+r*r;return i<1e-12&&(n=ts,e=ns,r=es,QfOl?t-Dl:t<-Ol?t+Dl:t,n]}function Ss(t,n,e){return(t%=Dl)?n||e?ks(Cs(t),As(n,e)):Cs(t):n||e?As(n,e):Ns}function Ts(t){return function(n,e){return[(n+=t)>Ol?n-Dl:n<-Ol?n+Dl:n,e]}}function Cs(t){var n=Ts(t);return n.invert=Ts(-t),n}function As(t,n){var e=ql(t),r=Vl(t),i=ql(n),o=Vl(n);function u(t,n){var u=ql(n),a=ql(t)*u,c=Vl(t)*u,l=Vl(n),f=l*e+a*r;return[Fl(c*i-f*o,a*e-l*r),Zl(f*i+c*o)]}return u.invert=function(t,n){var u=ql(n),a=ql(t)*u,c=Vl(t)*u,l=Vl(n),f=l*i-c*o;return[Fl(c*i+l*o,a*e+f*r),Zl(f*e-a*r)]},u}Ns.invert=Ns;var Ps=function(t){function n(n){return(n=t(n[0]*Ul,n[1]*Ul))[0]*=Ll,n[1]*=Ll,n}return t=Ss(t[0]*Ul,t[1]*Ul,t.length>2?t[2]*Ul:0),n.invert=function(n){return(n=t.invert(n[0]*Ul,n[1]*Ul))[0]*=Ll,n[1]*=Ll,n},n};function Os(t,n,e,r,i,o){if(e){var u=ql(n),a=Vl(n),c=r*e;null==i?(i=n+r*Dl,o=n-c/2):(i=Is(u,i),o=Is(u,o),(r>0?io)&&(i+=r*Dl));for(var l,f=i;r>0?f>o:f1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},Ls=function(t,n){return zl(t[0]-n[0])=0;--o)i.point((f=l[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}l=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}};function js(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r=0?1:-1,M=E*x,k=M>Ol,N=p*b;if(Fs.add(Fl(N*E*Vl(M),v*w+N*ql(M))),o+=k?x+E*Dl:x,k^h>=e^m>=e){var S=Ef(wf(s),wf(y));Nf(S);var T=Ef(i,S);Nf(T);var C=(k^x>=0?-1:1)*Zl(T[2]);(r>C||r===C&&(S[0]||S[1]))&&(u+=k^x>=0?1:-1)}}return(o<-Pl||on?1:t>=n?0:NaN};var Hs=function(t){return 1===t.length&&(t=function(t){return function(n,e){return Bs(t(n),e)}}(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}(Bs);Hs.right,Hs.left;var Ys=Array.prototype,$s=(Ys.slice,Ys.map,function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r=0;)for(n=(r=t[i]).length;--n>=0;)e[--u]=r[n];return e};var Ws=function(t,n,e,r){return function(i){var o,u,a,c=n(i),l=Ds(),f=n(l),s=!1,h={point:d,lineStart:v,lineEnd:g,polygonStart:function(){h.point=y,h.lineStart=m,h.lineEnd=_,u=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=v,h.lineEnd=g,u=Vs(u);var t=qs(o,r);u.length?(s||(i.polygonStart(),s=!0),zs(u,Gs,t,e,i)):t&&(s||(i.polygonStart(),s=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),s&&(i.polygonEnd(),s=!1),u=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){c.point(t,n)}function v(){h.point=p,c.lineStart()}function g(){h.point=d,c.lineEnd()}function y(t,n){a.push([t,n]),f.point(t,n)}function m(){f.lineStart(),a=[]}function _(){y(a[0][0],a[0][1]),f.lineEnd();var t,n,e,r,c=f.clean(),h=l.result(),d=h.length;if(a.pop(),o.push(a),a=null,d)if(1&c){if((n=(e=h[0]).length-1)>0){for(s||(i.polygonStart(),s=!0),i.lineStart(),t=0;t1&&2&c&&h.push(h.pop().concat(h.shift())),u.push(h.filter(Xs))}return h}};function Xs(t){return t.length>1}function Gs(t,n){return((t=t.x)[0]<0?t[1]-Il-Pl:Il-t[1])-((n=n.x)[0]<0?n[1]-Il-Pl:Il-n[1])}var Qs=Ws(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?Ol:-Ol,c=zl(o-e);zl(c-Ol)0?Il:-Il),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=Ol&&(zl(e-i)Pl?jl((Vl(n)*(o=ql(r))*Vl(e)-Vl(r)*(i=ql(n))*Vl(t))/(i*o*u)):(n+r)/2}(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*Il,r.point(-Ol,i),r.point(0,i),r.point(Ol,i),r.point(Ol,0),r.point(Ol,-i),r.point(0,-i),r.point(-Ol,-i),r.point(-Ol,0),r.point(-Ol,i);else if(zl(t[0]-n[0])>Pl){var o=t[0]0,i=zl(n)>Pl;function o(t,e){return ql(t)*ql(e)>n}function u(t,e,r){var i=[1,0,0],o=Ef(wf(t),wf(e)),u=xf(o,o),a=o[0],c=u-a*a;if(!c)return!r&&t;var l=n*u/c,f=-n*a/c,s=Ef(i,o),h=kf(i,l);Mf(h,kf(o,f));var d=s,p=xf(h,d),v=xf(d,d),g=p*p-v*(xf(h,h)-1);if(!(g<0)){var y=Xl(g),m=kf(d,(-p-y)/v);if(Mf(m,h),m=bf(m),!r)return m;var _,b=t[0],w=e[0],x=t[1],E=e[1];w0^m[1]<(zl(m[0]-b)Ol^(b<=m[0]&&m[0]<=w)){var N=kf(d,(-p+y)/v);return Mf(N,h),[m,bf(N)]}}}function a(n,e){var i=r?t:Ol-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return Ws(o,function(t){var n,e,c,l,f;return{lineStart:function(){l=c=!1,f=1},point:function(s,h){var d,p=[s,h],v=o(s,h),g=r?v?0:a(s,h):v?a(s+(s<0?Ol:-Ol),h):0;if(!n&&(l=c=v)&&t.lineStart(),v!==c&&(!(d=u(n,p))||Ls(n,d)||Ls(p,d))&&(p[0]+=Pl,p[1]+=Pl,v=o(p[0],p[1])),v!==c)f=0,v?(t.lineStart(),d=u(p,n),t.point(d[0],d[1])):(d=u(n,p),t.point(d[0],d[1]),t.lineEnd()),n=d;else if(i&&n&&r^v){var y;g&e||!(y=u(p,n,!0))||(f=0,r?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&Ls(n,p)||t.point(p[0],p[1]),n=p,c=v,e=g},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return f|(l&&c)<<1}}},function(n,r,i,o){Os(o,t,e,i,n,r)},r?[0,-t]:[-Ol,t-Ol])},Ks=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],l=0,f=1,s=n[0]-a,h=n[1]-c;if(u=e-a,s||!(u>0)){if(u/=s,s<0){if(u0){if(u>f)return;u>l&&(l=u)}if(u=i-a,s||!(u<0)){if(u/=s,s<0){if(u>f)return;u>l&&(l=u)}else if(s>0){if(u0)){if(u/=h,h<0){if(u0){if(u>f)return;u>l&&(l=u)}if(u=o-c,h||!(u<0)){if(u/=h,h<0){if(u>f)return;u>l&&(l=u)}else if(h>0){if(u0&&(t[0]=a+l*s,t[1]=c+l*h),f<1&&(n[0]=a+f*s,n[1]=c+f*h),!0}}}}},Js=1e9,th=-Js;function nh(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,l){var f=0,s=0;if(null==i||(f=u(i,a))!==(s=u(o,a))||c(i,o)<0^a>0)do{l.point(0===f||3===f?t:e,f>1?r:n)}while((f=(f+a+4)%4)!==s);else l.point(o[0],o[1])}function u(r,i){return zl(r[0]-t)0?0:3:zl(r[0]-e)0?2:1:zl(r[1]-n)0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){var c,l,f,s,h,d,p,v,g,y,m,_=u,b=Ds(),w={point:x,lineStart:function(){w.point=E,l&&l.push(f=[]);y=!0,g=!1,p=v=NaN},lineEnd:function(){c&&(E(s,h),d&&g&&b.rejoin(),c.push(b.result()));w.point=x,g&&_.lineEnd()},polygonStart:function(){_=b,c=[],l=[],m=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=l.length;er&&(h-o)*(r-u)>(d-u)*(t-o)&&++n:d<=r&&(h-o)*(r-u)<(d-u)*(t-o)&&--n;return n}(),e=m&&n,i=(c=Vs(c)).length;(e||i)&&(u.polygonStart(),e&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),i&&zs(c,a,n,o,u),u.polygonEnd());_=u,c=l=f=null}};function x(t,n){i(t,n)&&_.point(t,n)}function E(o,u){var a=i(o,u);if(l&&f.push([o,u]),y)s=o,h=u,d=a,y=!1,a&&(_.lineStart(),_.point(o,u));else if(a&&g)_.point(o,u);else{var c=[p=Math.max(th,Math.min(Js,p)),v=Math.max(th,Math.min(Js,v))],b=[o=Math.max(th,Math.min(Js,o)),u=Math.max(th,Math.min(Js,u))];Ks(c,b,t,n,e,r)?(g||(_.lineStart(),_.point(c[0],c[1])),_.point(b[0],b[1]),a||_.lineEnd(),m=!1):a&&(_.lineStart(),_.point(o,u),m=!1)}p=o,v=u,g=a}return w}}var eh,rh,ih,oh=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=nh(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},uh=Sl(),ah={sphere:Jl,point:Jl,lineStart:function(){ah.point=lh,ah.lineEnd=ch},lineEnd:Jl,polygonStart:Jl,polygonEnd:Jl};function ch(){ah.point=ah.lineEnd=Jl}function lh(t,n){eh=t*=Ul,rh=Vl(n*=Ul),ih=ql(n),ah.point=fh}function fh(t,n){t*=Ul;var e=Vl(n*=Ul),r=ql(n),i=zl(t-eh),o=ql(i),u=r*Vl(i),a=ih*e-rh*r*o,c=rh*e+ih*r*o;uh.add(Fl(Xl(u*u+a*a),c)),eh=t,rh=e,ih=r}var sh=function(t){return uh.reset(),sf(t,ah),+uh},hh=[null,null],dh={type:"LineString",coordinates:hh},ph=function(t,n){return hh[0]=t,hh[1]=n,sh(dh)},vh={Feature:function(t,n){return yh(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++rPl}).map(c)).concat($s(Bl(o/d)*d,i,d).filter(function(t){return zl(t%v)>Pl}).map(l))}return y.lines=function(){return m().map(function(t){return{type:"LineString",coordinates:t}})},y.outline=function(){return{type:"Polygon",coordinates:[f(r).concat(s(u).slice(1),f(e).reverse().slice(1),s(a).reverse().slice(1))]}},y.extent=function(t){return arguments.length?y.extentMajor(t).extentMinor(t):y.extentMinor()},y.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],u=+t[1][1],r>e&&(t=r,r=e,e=t),a>u&&(t=a,a=u,u=t),y.precision(g)):[[r,a],[e,u]]},y.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),y.precision(g)):[[n,o],[t,i]]},y.step=function(t){return arguments.length?y.stepMajor(t).stepMinor(t):y.stepMinor()},y.stepMajor=function(t){return arguments.length?(p=+t[0],v=+t[1],y):[p,v]},y.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],y):[h,d]},y.precision=function(h){return arguments.length?(g=+h,c=Mh(o,i,90),l=kh(n,t,g),f=Mh(a,u,90),s=kh(r,e,g),y):g},y.extentMajor([[-180,-90+Pl],[180,90-Pl]]).extentMinor([[-180,-80-Pl],[180,80+Pl]])}function Sh(){return Nh()()}var Th,Ch,Ah,Ph,Oh=function(t,n){var e=t[0]*Ul,r=t[1]*Ul,i=n[0]*Ul,o=n[1]*Ul,u=ql(r),a=Vl(r),c=ql(o),l=Vl(o),f=u*ql(e),s=u*Vl(e),h=c*ql(i),d=c*Vl(i),p=2*Zl(Xl(Kl(o-r)+u*c*Kl(i-e))),v=Vl(p),g=p?function(t){var n=Vl(t*=p)/v,e=Vl(p-t)/v,r=e*f+n*h,i=e*s+n*d,o=e*a+n*l;return[Fl(i,r)*Ll,Fl(o,Xl(r*r+i*i))*Ll]}:function(){return[e*Ll,r*Ll]};return g.distance=p,g},Ih=function(t){return t},Rh=Sl(),Dh=Sl(),Lh={point:Jl,lineStart:Jl,lineEnd:Jl,polygonStart:function(){Lh.lineStart=Uh,Lh.lineEnd=Fh},polygonEnd:function(){Lh.lineStart=Lh.lineEnd=Lh.point=Jl,Rh.add(zl(Dh)),Dh.reset()},result:function(){var t=Rh/2;return Rh.reset(),t}};function Uh(){Lh.point=zh}function zh(t,n){Lh.point=jh,Th=Ah=t,Ch=Ph=n}function jh(t,n){Dh.add(Ph*t-Ah*n),Ah=t,Ph=n}function Fh(){jh(Th,Ch)}var qh=Lh,Bh=1/0,Hh=Bh,Yh=-Bh,$h=Yh;var Vh,Wh,Xh,Gh,Qh={point:function(t,n){tYh&&(Yh=t);n$h&&($h=n)},lineStart:Jl,lineEnd:Jl,polygonStart:Jl,polygonEnd:Jl,result:function(){var t=[[Bh,Hh],[Yh,$h]];return Yh=$h=-(Hh=Bh=1/0),t}},Zh=0,Kh=0,Jh=0,td=0,nd=0,ed=0,rd=0,id=0,od=0,ud={point:ad,lineStart:cd,lineEnd:sd,polygonStart:function(){ud.lineStart=hd,ud.lineEnd=dd},polygonEnd:function(){ud.point=ad,ud.lineStart=cd,ud.lineEnd=sd},result:function(){var t=od?[rd/od,id/od]:ed?[td/ed,nd/ed]:Jh?[Zh/Jh,Kh/Jh]:[NaN,NaN];return Zh=Kh=Jh=td=nd=ed=rd=id=od=0,t}};function ad(t,n){Zh+=t,Kh+=n,++Jh}function cd(){ud.point=ld}function ld(t,n){ud.point=fd,ad(Xh=t,Gh=n)}function fd(t,n){var e=t-Xh,r=n-Gh,i=Xl(e*e+r*r);td+=i*(Xh+t)/2,nd+=i*(Gh+n)/2,ed+=i,ad(Xh=t,Gh=n)}function sd(){ud.point=ad}function hd(){ud.point=pd}function dd(){vd(Vh,Wh)}function pd(t,n){ud.point=vd,ad(Vh=Xh=t,Wh=Gh=n)}function vd(t,n){var e=t-Xh,r=n-Gh,i=Xl(e*e+r*r);td+=i*(Xh+t)/2,nd+=i*(Gh+n)/2,ed+=i,rd+=(i=Gh*t-Xh*n)*(Xh+t),id+=i*(Gh+n),od+=3*i,ad(Xh=t,Gh=n)}var gd=ud;function yd(t){this._context=t}yd.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,Dl)}},result:Jl};var md,_d,bd,wd,xd,Ed=Sl(),Md={point:Jl,lineStart:function(){Md.point=kd},lineEnd:function(){md&&Nd(_d,bd),Md.point=Jl},polygonStart:function(){md=!0},polygonEnd:function(){md=null},result:function(){var t=+Ed;return Ed.reset(),t}};function kd(t,n){Md.point=Nd,_d=wd=t,bd=xd=n}function Nd(t,n){wd-=t,xd-=n,Ed.add(Xl(wd*wd+xd*xd)),wd=t,xd=n}var Sd=Md;function Td(){this._string=[]}function Cd(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}Td.prototype={_radius:4.5,_circle:Cd(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=Cd(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}};var Ad=function(t,n){var e,r,i=4.5;function o(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),sf(t,e(r))),r.result()}return o.area=function(t){return sf(t,e(qh)),qh.result()},o.measure=function(t){return sf(t,e(Sd)),Sd.result()},o.bounds=function(t){return sf(t,e(Qh)),Qh.result()},o.centroid=function(t){return sf(t,e(gd)),gd.result()},o.projection=function(n){return arguments.length?(e=null==n?(t=null,Ih):(t=n).stream,o):t},o.context=function(t){return arguments.length?(r=null==t?(n=null,new Td):new yd(n=t),"function"!=typeof i&&r.pointRadius(i),o):n},o.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),o):i},o.projection(t).context(n)},Pd=function(t){return{stream:Od(t)}};function Od(t){return function(n){var e=new Id;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Id(){}function Rd(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),sf(e,t.stream(Qh)),n(Qh.result()),null!=r&&t.clipExtent(r),t}function Dd(t,n,e){return Rd(t,function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),u=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,a=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([u,a])},e)}function Ld(t,n,e){return Dd(t,[[0,0],n],e)}function Ud(t,n,e){return Rd(t,function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,u=-i*e[0][1];t.scale(150*i).translate([o,u])},e)}function zd(t,n,e){return Rd(t,function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],u=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,u])},e)}Id.prototype={constructor:Id,point:function(t,n){this.stream.point(t,n)},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()}};var jd=16,Fd=ql(30*Ul),qd=function(t,n){return+n?function(t,n){function e(r,i,o,u,a,c,l,f,s,h,d,p,v,g){var y=l-r,m=f-i,_=y*y+m*m;if(_>4*n&&v--){var b=u+h,w=a+d,x=c+p,E=Xl(b*b+w*w+x*x),M=Zl(x/=E),k=zl(zl(x)-1)n||zl((y*C+m*A)/_-.5)>.3||u*h+a*d+c*p2?t[2]%360*Ul:0,T()):[g*Ll,y*Ll,m*Ll]},k.precision=function(t){return arguments.length?(M=qd(S,E=t*t),C()):Xl(E)},k.fitExtent=function(t,n){return Dd(k,t,n)},k.fitSize=function(t,n){return Ld(k,t,n)},k.fitWidth=function(t,n){return Ud(k,t,n)},k.fitHeight=function(t,n){return zd(k,t,n)},function(){return n=t.apply(this,arguments),k.invert=n.invert&&N,T()}}function $d(t){var n=0,e=Ol/3,r=Yd(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*Ul,e=t[1]*Ul):[n*Ll,e*Ll]},i}function Vd(t,n){var e=Vl(t),r=(e+Vl(n))/2;if(zl(r)=.12&&i<.234&&r>=-.425&&r<-.214?a:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:u).invert(t)},f.stream=function(e){return t&&n===e?t:t=function(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i0?n<-Il+Pl&&(n=-Il+Pl):n>Il-Pl&&(n=Il-Pl);var e=i/$l(op(n),r);return[e*Vl(r*t),i-e*ql(r*t)]}return o.invert=function(t,n){var e=i-n,o=Wl(r)*Xl(t*t+e*e);return[Fl(t,zl(e))/r*Wl(e),2*jl($l(i/o,1/r))-Il]},o}var ap=function(){return $d(up).scale(109.5).parallels([30,30])};function cp(t,n){return[t,n]}cp.invert=cp;var lp=function(){return Hd(cp).scale(152.63)};function fp(t,n){var e=ql(t),r=t===n?Vl(t):(e-ql(n))/(n-t),i=e/r+t;if(zl(r)Pl&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]};var yp=function(){return Hd(gp).scale(175.295)};function mp(t,n){return[ql(n)*Vl(t),Vl(n)]}mp.invert=Zd(Zl);var _p=function(){return Hd(mp).scale(249.5).clipAngle(90+Pl)};function bp(t,n){var e=ql(n),r=1+ql(t)*e;return[e*Vl(t)/r,Vl(n)/r]}bp.invert=Zd(function(t){return 2*jl(t)});var wp=function(){return Hd(bp).scale(250).clipAngle(142)};function xp(t,n){return[Yl(Gl((Il+n)/2)),-t]}xp.invert=function(t,n){return[-n,2*jl(Hl(t))-Il]};var Ep=function(){var t=ip(xp),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)};function Mp(t,n){return t.parent===n.parent?1:2}function kp(t,n){return t+n.x}function Np(t,n){return Math.max(t,n.y)}var Sp=function(){var t=Mp,n=1,e=1,r=!1;function i(i){var o,u=0;i.eachAfter(function(n){var e=n.children;e?(n.x=function(t){return t.reduce(kp,0)/t.length}(e),n.y=function(t){return 1+t.reduce(Np,0)}(e)):(n.x=o?u+=t(n,o):0,n.y=0,o=n)});var a=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),l=a.x-t(a,c)/2,f=c.x+t(c,a)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-l)/(f-l)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i};function Tp(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function Cp(t,n){var e,r,i,o,u,a=new Ip(t),c=+t.value&&(a.value=t.value),l=[a];for(null==n&&(n=Ap);e=l.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)l.push(r=e.children[o]=new Ip(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(Op)}function Ap(t){return t.children}function Pp(t){t.data=t.data.data}function Op(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function Ip(t){this.data=t,this.depth=this.height=0,this.parent=null}Ip.prototype=Cp.prototype={constructor:Ip,count:function(){return this.eachAfter(Tp)},each:function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return Cp(this).eachBefore(Pp)}};var Rp=Array.prototype.slice;var Dp=function(t){for(var n,e,r=0,i=(t=function(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}(Rp.call(t))).length,o=[];r0&&e*e>r*r+i*i}function jp(t,n){for(var e=0;ee*e+r*r}function $p(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function Vp(t){this._=t,this.next=null,this.previous=null}function Wp(t){if(!(i=t.length))return 0;var n,e,r,i,o,u,a,c,l,f,s;if((n=t[0]).x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;Hp(e,n,r=t[2]),n=new Vp(n),e=new Vp(e),r=new Vp(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a0)throw new Error("cycle");return o}return e.id=function(n){return arguments.length?(t=Gp(n),e):t},e.parentId=function(t){return arguments.length?(n=Gp(t),e):n},e};function hv(t,n){return t.parent===n.parent?1:2}function dv(t){var n=t.children;return n?n[0]:t.t}function pv(t){var n=t.children;return n?n[n.length-1]:t.t}function vv(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function gv(t,n,e){return t.a.parent===n.parent?t.a:e}function yv(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}yv.prototype=Object.create(Ip.prototype);var mv=function(){var t=hv,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,u=new yv(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new yv(r[i],i)),e.parent=n;return(u.parent=new yv(null,0)).children=[u],u}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(u),r)i.eachBefore(a);else{var l=i,f=i,s=i;i.eachBefore(function(t){t.xf.x&&(f=t),t.depth>s.depth&&(s=t)});var h=l===f?1:t(l,f)/2,d=h-l.x,p=n/(f.x+h+d),v=e/(s.depth||1);i.eachBefore(function(t){t.x=(t.x+d)*p,t.y=t.depth*v})}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,u=n,a=e,c=o.parent.children[0],l=o.m,f=u.m,s=a.m,h=c.m;a=pv(a),o=dv(o),a&&o;)c=dv(c),(u=pv(u)).a=n,(i=a.z+s-o.z-l+t(a._,o._))>0&&(vv(gv(a,n,r),n,i),l+=i,f+=i),s+=a.m,l+=o.m,h+=c.m,f+=u.m;a&&!pv(u)&&(u.t=a,u.m+=s-f),o&&!dv(c)&&(c.t=o,c.m+=l-h,r=n)}return r}(n,i,n.parent.A||r[0])}function u(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function a(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},_v=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,l=t.value&&(i-e)/t.value;++ah&&(h=a),g=f*f*v,(d=Math.max(h/g,g/s))>p){f-=a;break}p=d}y.push(u={value:f,dice:c1?n:1)},e}(bv),Ev=function(){var t=xv,n=!1,e=1,r=1,i=[0],o=Qp,u=Qp,a=Qp,c=Qp,l=Qp;function f(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(s),i=[0],n&&t.eachBefore(rv),t}function s(n){var e=i[n.depth],r=n.x0+e,f=n.y0+e,s=n.x1-e,h=n.y1-e;s=e-1){var f=a[n];return f.x0=i,f.y0=o,f.x1=u,void(f.y1=c)}var s=l[n],h=r/2+s,d=n+1,p=e-1;for(;d>>1;l[v]c-o){var m=(i*y+u*g)/r;t(n,d,g,i,o,m,c),t(d,e,y,m,o,u,c)}else{var _=(o*y+c*g)/r;t(n,d,g,i,o,u,_),t(d,e,y,i,_,u,c)}}(0,c,t.value,n,e,r,i)},kv=function(t,n,e,r,i){(1&t.depth?_v:iv)(t,n,e,r,i)},Nv=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,l,f,s=-1,h=u.length,d=t.value;++s1?n:1)},e}(bv),Sv=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t};function Tv(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Cv(){}var Av="\\s*([+-]?\\d+)\\s*",Pv="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",Ov="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",Iv=/^#([0-9a-f]{3})$/,Rv=/^#([0-9a-f]{6})$/,Dv=new RegExp("^rgb\\("+[Av,Av,Av]+"\\)$"),Lv=new RegExp("^rgb\\("+[Ov,Ov,Ov]+"\\)$"),Uv=new RegExp("^rgba\\("+[Av,Av,Av,Pv]+"\\)$"),zv=new RegExp("^rgba\\("+[Ov,Ov,Ov,Pv]+"\\)$"),jv=new RegExp("^hsl\\("+[Pv,Ov,Ov]+"\\)$"),Fv=new RegExp("^hsla\\("+[Pv,Ov,Ov,Pv]+"\\)$"),qv={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,rebeccapurple:6697881,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};function Bv(t){var n;return t=(t+"").trim().toLowerCase(),(n=Iv.exec(t))?new Wv((n=parseInt(n[1],16))>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=Rv.exec(t))?Hv(parseInt(n[1],16)):(n=Dv.exec(t))?new Wv(n[1],n[2],n[3],1):(n=Lv.exec(t))?new Wv(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Uv.exec(t))?Yv(n[1],n[2],n[3],n[4]):(n=zv.exec(t))?Yv(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=jv.exec(t))?Gv(n[1],n[2]/100,n[3]/100,1):(n=Fv.exec(t))?Gv(n[1],n[2]/100,n[3]/100,n[4]):qv.hasOwnProperty(t)?Hv(qv[t]):"transparent"===t?new Wv(NaN,NaN,NaN,0):null}function Hv(t){return new Wv(t>>16&255,t>>8&255,255&t,1)}function Yv(t,n,e,r){return r<=0&&(t=n=e=NaN),new Wv(t,n,e,r)}function $v(t){return t instanceof Cv||(t=Bv(t)),t?new Wv((t=t.rgb()).r,t.g,t.b,t.opacity):new Wv}function Vv(t,n,e,r){return 1===arguments.length?$v(t):new Wv(t,n,e,null==r?1:r)}function Wv(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Xv(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Gv(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Zv(t,n,e,r)}function Qv(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof Zv)return new Zv(t.h,t.s,t.l,t.opacity);if(t instanceof Cv||(t=Bv(t)),!t)return new Zv;if(t instanceof Zv)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new Zv(u,a,c,t.opacity)}(t):new Zv(t,n,e,null==r?1:r)}function Zv(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Kv(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Sv(Cv,Bv,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),Sv(Wv,Vv,Tv(Cv,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Wv(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Wv(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+Xv(this.r)+Xv(this.g)+Xv(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),Sv(Zv,Qv,Tv(Cv,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Zv(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Zv(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new Wv(Kv(t>=240?t-240:t+120,i,r),Kv(t,i,r),Kv(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Jv=Math.PI/180,tg=180/Math.PI,ng=.96422,eg=1,rg=.82521,ig=4/29,og=6/29,ug=3*og*og,ag=og*og*og;function cg(t){if(t instanceof fg)return new fg(t.l,t.a,t.b,t.opacity);if(t instanceof yg){if(isNaN(t.h))return new fg(t.l,0,0,t.opacity);var n=t.h*Jv;return new fg(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof Wv||(t=$v(t));var e,r,i=pg(t.r),o=pg(t.g),u=pg(t.b),a=sg((.2225045*i+.7168786*o+.0606169*u)/eg);return i===o&&o===u?e=r=a:(e=sg((.4360747*i+.3850649*o+.1430804*u)/ng),r=sg((.0139322*i+.0971045*o+.7141733*u)/rg)),new fg(116*a-16,500*(e-a),200*(a-r),t.opacity)}function lg(t,n,e,r){return 1===arguments.length?cg(t):new fg(t,n,e,null==r?1:r)}function fg(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function sg(t){return t>ag?Math.pow(t,1/3):t/ug+ig}function hg(t){return t>og?t*t*t:ug*(t-ig)}function dg(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function pg(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function vg(t){if(t instanceof yg)return new yg(t.h,t.c,t.l,t.opacity);if(t instanceof fg||(t=cg(t)),0===t.a&&0===t.b)return new yg(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*tg;return new yg(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function gg(t,n,e,r){return 1===arguments.length?vg(t):new yg(t,n,e,null==r?1:r)}function yg(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}Sv(fg,lg,Tv(Cv,{brighter:function(t){return new fg(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new fg(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new Wv(dg(3.1338561*(n=ng*hg(n))-1.6168667*(t=eg*hg(t))-.4906146*(e=rg*hg(e))),dg(-.9787684*n+1.9161415*t+.033454*e),dg(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Sv(yg,gg,Tv(Cv,{brighter:function(t){return new yg(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new yg(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return cg(this).rgb()}}));var mg=-.29227,_g=-.90649,bg=1.97294,wg=bg*_g,xg=1.78277*bg,Eg=1.78277*mg- -.14861*_g;function Mg(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof kg)return new kg(t.h,t.s,t.l,t.opacity);t instanceof Wv||(t=$v(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Eg*r+wg*n-xg*e)/(Eg+wg-xg),o=r-i,u=(bg*(e-i)-mg*o)/_g,a=Math.sqrt(u*u+o*o)/(bg*i*(1-i)),c=a?Math.atan2(u,o)*tg-120:NaN;return new kg(c<0?c+360:c,a,i,t.opacity)}(t):new kg(t,n,e,null==r?1:r)}function kg(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Ng(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}Sv(kg,Mg,Tv(Cv,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new kg(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new kg(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Jv,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new Wv(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(mg*r+_g*i)),255*(n+e*(bg*r)),this.opacity)}}));var Sg=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r180||e<-180?e-360*Math.round(e/360):e):Cg(isNaN(t)?n:t)}function Og(t){return 1==(t=+t)?Ig:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):Cg(isNaN(n)?e:n)}}function Ig(t,n){var e=n-t;return e?Ag(t,e):Cg(isNaN(t)?n:t)}var Rg=function t(n){var e=Og(n);function r(t,n){var r=e((t=Vv(t)).r,(n=Vv(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=Ig(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function Dg(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;eo&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:Fg(e,r)})),o=Hg.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Fg(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Fg(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:Fg(t,e)},{i:a-2,x:Fg(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e1e-6)if(Math.abs(f*a-c*l)>1e-6&&i){var h=e-o,d=r-u,p=a*a+c*c,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(s),m=i*Math.tan((yy-Math.acos((p+s-v)/(2*g*y)))/2),_=m/y,b=m/g;Math.abs(_-1)>1e-6&&(this._+="L"+(t+_*l)+","+(n+_*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>l*d)+","+(this._x1=t+b*a)+","+(this._y1=n+b*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,l=n+a,f=1^o,s=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+l:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-l)>1e-6)&&(this._+="L"+c+","+l),e&&(s<0&&(s=s%my+my),s>_y?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=l):s>1e-6&&(this._+="A"+e+","+e+",0,"+ +(s>=yy)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var xy=wy,Ey=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e1&&ky(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}var Ty=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n=0;--n)l.push(t[r[o[n]][2]]);for(n=+a;na!=l>a&&u<(c-e)*(a-r)/(l-r)+e&&(f=!f),c=e,l=r;return f},Ay=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(g+m)/2))?g=u:m=u,i=d,!(d=d[s=f<<1|l]))return i[s]=p,t;if(a=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===a&&e===c)return p.next=d,i?i[s]=p:t._root=p,t;do{i=i?i[s]=new Array(4):t._root=new Array(4),(l=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(g+m)/2))?g=u:m=u}while((s=f<<1|l)==(h=(c>=u)<<1|a>=o));return i[h]=d,i[s]=p,t}var Oy=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i};function Iy(t){return t[0]}function Ry(t){return t[1]}function Dy(t,n,e){var r=new Ly(null==n?Iy:n,null==e?Ry:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ly(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Uy(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var zy=Dy.prototype=Ly.prototype;zy.copy=function(){var t,n,e=new Ly(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Uy(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=Uy(n));return e},zy.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Py(this.cover(n,e),n,e,t)},zy.addAll=function(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,l=1/0,f=-1/0,s=-1/0;for(e=0;ef&&(f=r),is&&(s=i));for(ft||t>i||r>n||n>o))return this;var u,a,c=i-e,l=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{(u=new Array(4))[a]=l,l=u}while(o=r+(c*=2),t>(i=e+c)||n>o);break;case 1:do{(u=new Array(4))[a]=l,l=u}while(o=r+(c*=2),(e=i-c)>t||n>o);break;case 2:do{(u=new Array(4))[a]=l,l=u}while(r=o-(c*=2),t>(i=e+c)||r>n);break;case 3:do{(u=new Array(4))[a]=l,l=u}while(r=o-(c*=2),(e=i-c)>t||r>n)}this._root&&this._root.length&&(this._root=l)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},zy.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},zy.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},zy.find=function(t,n,e){var r,i,o,u,a,c,l,f=this._x0,s=this._y0,h=this._x1,d=this._y1,p=[],v=this._root;for(v&&p.push(new Oy(v,f,s,h,d)),null==e?e=1/0:(f=t-e,s=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>d||(u=c.x1)=y)<<1|t>=g)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-l],p[p.length-1-l]=c)}else{var m=t-+this._x.call(null,v.data),_=n-+this._y.call(null,v.data),b=m*m+_*_;if(b=(a=(p+g)/2))?p=a:g=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=d,!(d=d[s=f<<1|l]))return this;if(!d.length)break;(n[s+1&3]||n[s+2&3]||n[s+3&3])&&(e=n,h=s)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[s]=i:delete n[s],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},zy.removeAll=function(t){for(var n=0,e=t.length;n=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(n){}t._active=NaN,$y(t)}function $y(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function Vy(t){if(null==t)t=1/0;else if(!((t=+t)>=1))throw new Error("invalid concurrency");return new qy(t)}qy.prototype=Vy.prototype={constructor:qy,defer:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("defer after await");if(null!=this._error)return this;var n=jy.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),By(this),this},abort:function(){return null==this._error&&Yy(this,new Error("abort")),this},await:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=function(n,e){t.apply(null,[n].concat(e))},$y(this),this},awaitAll:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=t,$y(this),this}};var Wy=function(){return Math.random()},Xy=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(Wy),Gy=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(Wy),Qy=function t(n){function e(){var t=Gy.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(Wy),Zy=function t(n){function e(t){return function(){for(var e=0,r=0;r=200&&r<300||304===r){if(i)try{n=i.call(e,c)}catch(t){return void u.call("error",e,t)}else n=c;u.call("load",e,n)}else u.call("error",e,t)}if("undefined"==typeof XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(t)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=c.ontimeout=h:c.onreadystatechange=function(t){c.readyState>3&&h(t)},c.onprogress=function(t){u.call("progress",e,t)},e={header:function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?a.get(t):(null==n?a.remove(t):a.set(t,n+""),e)},mimeType:function(t){return arguments.length?(r=null==t?null:t+"",e):r},responseType:function(t){return arguments.length?(o=t,e):o},timeout:function(t){return arguments.length?(s=+t,e):s},user:function(t){return arguments.length<1?l:(l=null==t?null:t+"",e)},password:function(t){return arguments.length<1?f:(f=null==t?null:t+"",e)},response:function(t){return i=t,e},get:function(t,n){return e.send("GET",t,n)},post:function(t,n){return e.send("POST",t,n)},send:function(n,i,h){return c.open(n,t,!0,l,f),null==r||a.has("accept")||a.set("accept",r+",*/*"),c.setRequestHeader&&a.each(function(t,n){c.setRequestHeader(n,t)}),null!=r&&c.overrideMimeType&&c.overrideMimeType(r),null!=o&&(c.responseType=o),s>0&&(c.timeout=s),null==h&&"function"==typeof i&&(h=i,i=null),null!=h&&1===h.length&&(h=function(t){return function(n,e){t(null==n?e:null)}}(h)),null!=h&&e.on("error",h).on("load",function(t){h(null,t)}),u.call("beforesend",e,c),c.send(null==i?null:i),e},abort:function(){return c.abort(),e},on:function(){var t=u.on.apply(u,arguments);return t===u?e:t}},null!=n){if("function"!=typeof n)throw new Error("invalid callback: "+n);return e.get(n)}return e};var rm=function(t,n){return function(e,r){var i=em(e).mimeType(t).response(n);if(null!=r){if("function"!=typeof r)throw new Error("invalid callback: "+r);return i.get(r)}return i}},im=rm("text/html",function(t){return document.createRange().createContextualFragment(t.responseText)}),om=rm("application/json",function(t){return JSON.parse(t.responseText)}),um=rm("text/plain",function(t){return t.responseText}),am=rm("application/xml",function(t){var n=t.responseXML;if(!n)throw new Error("parse error");return n}),cm=e(7),lm=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=em(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(function(t,n){return function(e){return t(e.responseText,n)}}(n,r=t)):r},o.row(r),i?o.get(i):o}};var fm=lm("text/csv",cm.c),sm=lm("text/tab-separated-values",cm.h),hm=function(t,n){return tn?1:t>=n?0:NaN},dm=function(t){return 1===t.length&&(t=function(t){return function(n,e){return hm(t(n),e)}}(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)>0?i=o:r=o+1}return r}}};var pm=dm(hm),vm=pm.right,gm=(pm.left,vm);var ym=function(t){return null===t?NaN:+t},mm=Array.prototype,_m=(mm.slice,mm.map,function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r0)return[t];if((r=n0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++a=0?(o>=bm?10:o>=wm?5:o>=xm?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=bm?10:o>=wm?5:o>=xm?2:1)}function km(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=bm?i*=10:o>=wm?i*=5:o>=xm&&(i*=2),n=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}};function Sm(){}function Tm(t,n){var e=new Sm;if(t instanceof Sm)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=Vm.exec(t))?n_(parseInt(n[1],16)):(n=Wm.exec(t))?new o_(n[1],n[2],n[3],1):(n=Xm.exec(t))?new o_(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Gm.exec(t))?e_(n[1],n[2],n[3],n[4]):(n=Qm.exec(t))?e_(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Zm.exec(t))?a_(n[1],n[2]/100,n[3]/100,1):(n=Km.exec(t))?a_(n[1],n[2]/100,n[3]/100,n[4]):Jm.hasOwnProperty(t)?n_(Jm[t]):"transparent"===t?new o_(NaN,NaN,NaN,0):null}function n_(t){return new o_(t>>16&255,t>>8&255,255&t,1)}function e_(t,n,e,r){return r<=0&&(t=n=e=NaN),new o_(t,n,e,r)}function r_(t){return t instanceof Bm||(t=t_(t)),t?new o_((t=t.rgb()).r,t.g,t.b,t.opacity):new o_}function i_(t,n,e,r){return 1===arguments.length?r_(t):new o_(t,n,e,null==r?1:r)}function o_(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function u_(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function a_(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new l_(t,n,e,r)}function c_(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof l_)return new l_(t.h,t.s,t.l,t.opacity);if(t instanceof Bm||(t=t_(t)),!t)return new l_;if(t instanceof l_)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new l_(u,a,c,t.opacity)}(t):new l_(t,n,e,null==r?1:r)}function l_(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function f_(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Fm(Bm,t_,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),Fm(o_,i_,qm(Bm,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new o_(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new o_(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+u_(this.r)+u_(this.g)+u_(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),Fm(l_,c_,qm(Bm,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new l_(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new l_(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new o_(f_(t>=240?t-240:t+120,i,r),f_(t,i,r),f_(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var s_=Math.PI/180,h_=180/Math.PI,d_=.96422,p_=1,v_=.82521,g_=4/29,y_=6/29,m_=3*y_*y_,__=y_*y_*y_;function b_(t){if(t instanceof x_)return new x_(t.l,t.a,t.b,t.opacity);if(t instanceof C_){if(isNaN(t.h))return new x_(t.l,0,0,t.opacity);var n=t.h*s_;return new x_(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof o_||(t=r_(t));var e,r,i=N_(t.r),o=N_(t.g),u=N_(t.b),a=E_((.2225045*i+.7168786*o+.0606169*u)/p_);return i===o&&o===u?e=r=a:(e=E_((.4360747*i+.3850649*o+.1430804*u)/d_),r=E_((.0139322*i+.0971045*o+.7141733*u)/v_)),new x_(116*a-16,500*(e-a),200*(a-r),t.opacity)}function w_(t,n,e,r){return 1===arguments.length?b_(t):new x_(t,n,e,null==r?1:r)}function x_(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function E_(t){return t>__?Math.pow(t,1/3):t/m_+g_}function M_(t){return t>y_?t*t*t:m_*(t-g_)}function k_(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function N_(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function S_(t){if(t instanceof C_)return new C_(t.h,t.c,t.l,t.opacity);if(t instanceof x_||(t=b_(t)),0===t.a&&0===t.b)return new C_(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*h_;return new C_(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function T_(t,n,e,r){return 1===arguments.length?S_(t):new C_(t,n,e,null==r?1:r)}function C_(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}Fm(x_,w_,qm(Bm,{brighter:function(t){return new x_(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new x_(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new o_(k_(3.1338561*(n=d_*M_(n))-1.6168667*(t=p_*M_(t))-.4906146*(e=v_*M_(e))),k_(-.9787684*n+1.9161415*t+.033454*e),k_(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Fm(C_,T_,qm(Bm,{brighter:function(t){return new C_(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new C_(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return b_(this).rgb()}}));var A_=-.29227,P_=-.90649,O_=1.97294,I_=O_*P_,R_=1.78277*O_,D_=1.78277*A_- -.14861*P_;function L_(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof U_)return new U_(t.h,t.s,t.l,t.opacity);t instanceof o_||(t=r_(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(D_*r+I_*n-R_*e)/(D_+I_-R_),o=r-i,u=(O_*(e-i)-A_*o)/P_,a=Math.sqrt(u*u+o*o)/(O_*i*(1-i)),c=a?Math.atan2(u,o)*h_-120:NaN;return new U_(c<0?c+360:c,a,i,t.opacity)}(t):new U_(t,n,e,null==r?1:r)}function U_(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function z_(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}Fm(U_,L_,qm(Bm,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new U_(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new U_(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*s_,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new o_(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(A_*r+P_*i)),255*(n+e*(O_*r)),this.opacity)}}));var j_=function(t){return function(){return t}};function F_(t,n){return function(e){return t+e*n}}function q_(t,n){var e=n-t;return e?F_(t,e>180||e<-180?e-360*Math.round(e/360):e):j_(isNaN(t)?n:t)}function B_(t){return 1==(t=+t)?H_:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):j_(isNaN(n)?e:n)}}function H_(t,n){var e=n-t;return e?F_(t,e):j_(isNaN(t)?n:t)}var Y_=function t(n){var e=B_(n);function r(t,n){var r=e((t=i_(t)).r,(n=i_(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=H_(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function $_(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:V_(e,r)})),o=X_.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:V_(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:V_(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:V_(t,e)},{i:a-2,x:V_(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e2?pb:db,r=i=null,f}function f(n){return(r||(r=e(o,u,c?function(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}(t):t,a)))(+n)}return f.invert=function(t){return(i||(i=e(u,o,hb,c?function(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}(n):n)))(+t)},f.domain=function(t){return arguments.length?(o=Rm.call(t,fb),l()):o.slice()},f.range=function(t){return arguments.length?(u=Dm.call(t),l()):u.slice()},f.rangeRound=function(t){return u=Dm.call(t),a=tb,l()},f.clamp=function(t){return arguments.length?(c=!!t,l()):c},f.interpolate=function(t){return arguments.length?(a=t,l()):a},l()}var yb=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},mb=function(t){return(t=yb(Math.abs(t)))?t[1]:NaN},_b=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function bb(t){return new wb(t)}function wb(t){if(!(n=_b.exec(t)))throw new Error("invalid format: "+t);var n;this.fill=n[1]||" ",this.align=n[2]||">",this.sign=n[3]||"-",this.symbol=n[4]||"",this.zero=!!n[5],this.width=n[6]&&+n[6],this.comma=!!n[7],this.precision=n[8]&&+n[8].slice(1),this.trim=!!n[9],this.type=n[10]||""}bb.prototype=wb.prototype,wb.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var xb,Eb,Mb,kb,Nb=function(t){t:for(var n,e=t.length,r=1,i=-1;r0){if(!+t[r])break t;i=0}}return i>0?t.slice(0,i)+t.slice(n+1):t},Sb=function(t,n){var e=yb(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},Tb={"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return Sb(100*t,n)},r:Sb,s:function(t,n){var e=yb(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(xb=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+yb(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},Cb=function(t){return t},Ab=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],Pb=function(t){var n=t.grouping&&t.thousands?function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}}(t.grouping,t.thousands):Cb,e=t.currency,r=t.decimal,i=t.numerals?function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}}(t.numerals):Cb,o=t.percent||"%";function u(t){var u=(t=bb(t)).fill,a=t.align,c=t.sign,l=t.symbol,f=t.zero,s=t.width,h=t.comma,d=t.precision,p=t.trim,v=t.type;"n"===v?(h=!0,v="g"):Tb[v]||(null==d&&(d=12),p=!0,v="g"),(f||"0"===u&&"="===a)&&(f=!0,u="0",a="=");var g="$"===l?e[0]:"#"===l&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",y="$"===l?e[1]:/[%p]/.test(v)?o:"",m=Tb[v],_=/[defgprs%]/.test(v);function b(t){var e,o,l,b=g,w=y;if("c"===v)w=m(t)+w,t="";else{var x=(t=+t)<0;if(t=m(Math.abs(t),d),p&&(t=Nb(t)),x&&0==+t&&(x=!1),b=(x?"("===c?c:"-":"-"===c||"("===c?"":c)+b,w=("s"===v?Ab[8+xb/3]:"")+w+(x&&"("===c?")":""),_)for(e=-1,o=t.length;++e(l=t.charCodeAt(e))||l>57){w=(46===l?r+t.slice(e+1):t.slice(e))+w,t=t.slice(0,e);break}}h&&!f&&(t=n(t,1/0));var E=b.length+t.length+w.length,M=E>1)+b+t+w+M.slice(E);break;default:t=M+b+t+w}return i(t)}return d=null==d?6:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),b.toString=function(){return t+""},b}return{format:u,formatPrefix:function(t,n){var e=u(((t=bb(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(mb(n)/3))),i=Math.pow(10,-r),o=Ab[8+r/3];return function(t){return e(i*t)+o}}}};!function(t){Eb=Pb(t),Mb=Eb.format,kb=Eb.formatPrefix}({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var Ob=function(t,n,e){var r,i=t[0],o=t[t.length-1],u=km(i,o,null==n?10:n);switch((e=bb(null==e?",f":e)).type){case"s":var a=Math.max(Math.abs(i),Math.abs(o));return null!=e.precision||isNaN(r=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(mb(n)/3)))-mb(Math.abs(t)))}(u,a))||(e.precision=r),kb(e,a);case"":case"e":case"g":case"p":case"r":null!=e.precision||isNaN(r=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,mb(n)-mb(t))+1}(u,Math.max(Math.abs(i),Math.abs(o))))||(e.precision=r-("e"===e.type));break;case"f":case"%":null!=e.precision||isNaN(r=function(t){return Math.max(0,-mb(Math.abs(t)))}(u))||(e.precision=r-2*("%"===e.type))}return Mb(e)};function Ib(t){var n=t.domain;return t.ticks=function(t){var e=n();return Em(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return Ob(n(),t,e)},t.nice=function(e){null==e&&(e=10);var r,i=n(),o=0,u=i.length-1,a=i[o],c=i[u];return c0?r=Mm(a=Math.floor(a/r)*r,c=Math.ceil(c/r)*r,e):r<0&&(r=Mm(a=Math.ceil(a*r)/r,c=Math.floor(c*r)/r,e)),r>0?(i[o]=Math.floor(a/r)*r,i[u]=Math.ceil(c/r)*r,n(i)):r<0&&(i[o]=Math.ceil(a*r)/r,i[u]=Math.floor(c*r)/r,n(i)),t},t}function Rb(){var t=gb(hb,V_);return t.copy=function(){return vb(t,Rb())},Ib(t)}function Db(){var t=[0,1];function n(t){return+t}return n.invert=n,n.domain=n.range=function(e){return arguments.length?(t=Rm.call(e,fb),n):t.slice()},n.copy=function(){return Db().domain(t)},Ib(n)}var Lb=function(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],u=t[i];return u0){for(;hc)break;v.push(s)}}else for(;h=1;--f)if(!((s=l*f)c)break;v.push(s)}}else v=Em(h,d,Math.min(d-h,p)).map(i);return o?v.reverse():v},t.tickFormat=function(n,o){if(null==o&&(o=10===e?".0e":","),"function"!=typeof o&&(o=Mb(o)),n===1/0)return o;null==n&&(n=10);var u=Math.max(1,e*n/t.ticks().length);return function(t){var n=t/i(Math.round(r(t)));return n*e0?e[i-1]:t[0],i=e?[r[e-1],n]:[r[u-1],r[u]]},o.copy=function(){return Xb().domain([t,n]).range(i)},Ib(o)}function Gb(){var t=[.5],n=[0,1],e=1;function r(r){if(r<=r)return n[gm(t,r,0,e)]}return r.domain=function(i){return arguments.length?(t=Dm.call(i),e=Math.min(t.length,n.length-1),r):t.slice()},r.range=function(i){return arguments.length?(n=Dm.call(i),e=Math.min(t.length,n.length-1),r):n.slice()},r.invertExtent=function(e){var r=n.indexOf(e);return[t[r-1],t[r]]},r.copy=function(){return Gb().domain(t).range(n)},r}var Qb=new Date,Zb=new Date;function Kb(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n0))return a;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(u=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return Qb.setTime(+n),Zb.setTime(+r),t(Qb),t(Zb),Math.floor(e(Qb,Zb))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var Jb=Kb(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});Jb.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Kb(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):Jb:null};var tw=Jb,nw=(Jb.range,6e4),ew=6048e5,rw=Kb(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),iw=rw,ow=(rw.range,Kb(function(t){t.setTime(Math.floor(t/nw)*nw)},function(t,n){t.setTime(+t+n*nw)},function(t,n){return(n-t)/nw},function(t){return t.getMinutes()})),uw=ow,aw=(ow.range,Kb(function(t){var n=t.getTimezoneOffset()*nw%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()})),cw=aw,lw=(aw.range,Kb(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*nw)/864e5},function(t){return t.getDate()-1})),fw=lw;lw.range;function sw(t){return Kb(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*nw)/ew})}var hw=sw(0),dw=sw(1),pw=sw(2),vw=sw(3),gw=sw(4),yw=sw(5),mw=sw(6),_w=(hw.range,dw.range,pw.range,vw.range,gw.range,yw.range,mw.range,Kb(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()})),bw=_w,ww=(_w.range,Kb(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()}));ww.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Kb(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var xw=ww,Ew=(ww.range,Kb(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*nw)},function(t,n){return(n-t)/nw},function(t){return t.getUTCMinutes()})),Mw=Ew,kw=(Ew.range,Kb(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()})),Nw=kw,Sw=(kw.range,Kb(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1})),Tw=Sw;Sw.range;function Cw(t){return Kb(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/ew})}var Aw=Cw(0),Pw=Cw(1),Ow=Cw(2),Iw=Cw(3),Rw=Cw(4),Dw=Cw(5),Lw=Cw(6),Uw=(Aw.range,Pw.range,Ow.range,Iw.range,Rw.range,Dw.range,Lw.range,Kb(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()})),zw=Uw,jw=(Uw.range,Kb(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()}));jw.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Kb(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Fw=jw;jw.range;function qw(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Bw(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Hw(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}var Yw,$w,Vw,Ww,Xw={"-":"",_:" ",0:"0"},Gw=/^\s*\d+/,Qw=/^%/,Zw=/[\\^$*+?|[\]().{}]/g;function Kw(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o68?1900:2e3),e+r[0].length):-1}function lx(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function fx(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function sx(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function hx(t,n,e){var r=Gw.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function dx(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function px(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function vx(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function gx(t,n,e){var r=Gw.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function yx(t,n,e){var r=Gw.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function mx(t,n,e){var r=Qw.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function _x(t,n,e){var r=Gw.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function bx(t,n,e){var r=Gw.exec(n.slice(e));return r?(t.Q=1e3*+r[0],e+r[0].length):-1}function wx(t,n){return Kw(t.getDate(),n,2)}function xx(t,n){return Kw(t.getHours(),n,2)}function Ex(t,n){return Kw(t.getHours()%12||12,n,2)}function Mx(t,n){return Kw(1+fw.count(xw(t),t),n,3)}function kx(t,n){return Kw(t.getMilliseconds(),n,3)}function Nx(t,n){return kx(t,n)+"000"}function Sx(t,n){return Kw(t.getMonth()+1,n,2)}function Tx(t,n){return Kw(t.getMinutes(),n,2)}function Cx(t,n){return Kw(t.getSeconds(),n,2)}function Ax(t){var n=t.getDay();return 0===n?7:n}function Px(t,n){return Kw(hw.count(xw(t),t),n,2)}function Ox(t,n){var e=t.getDay();return t=e>=4||0===e?gw(t):gw.ceil(t),Kw(gw.count(xw(t),t)+(4===xw(t).getDay()),n,2)}function Ix(t){return t.getDay()}function Rx(t,n){return Kw(dw.count(xw(t),t),n,2)}function Dx(t,n){return Kw(t.getFullYear()%100,n,2)}function Lx(t,n){return Kw(t.getFullYear()%1e4,n,4)}function Ux(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Kw(n/60|0,"0",2)+Kw(n%60,"0",2)}function zx(t,n){return Kw(t.getUTCDate(),n,2)}function jx(t,n){return Kw(t.getUTCHours(),n,2)}function Fx(t,n){return Kw(t.getUTCHours()%12||12,n,2)}function qx(t,n){return Kw(1+Tw.count(Fw(t),t),n,3)}function Bx(t,n){return Kw(t.getUTCMilliseconds(),n,3)}function Hx(t,n){return Bx(t,n)+"000"}function Yx(t,n){return Kw(t.getUTCMonth()+1,n,2)}function $x(t,n){return Kw(t.getUTCMinutes(),n,2)}function Vx(t,n){return Kw(t.getUTCSeconds(),n,2)}function Wx(t){var n=t.getUTCDay();return 0===n?7:n}function Xx(t,n){return Kw(Aw.count(Fw(t),t),n,2)}function Gx(t,n){var e=t.getUTCDay();return t=e>=4||0===e?Rw(t):Rw.ceil(t),Kw(Rw.count(Fw(t),t)+(4===Fw(t).getUTCDay()),n,2)}function Qx(t){return t.getUTCDay()}function Zx(t,n){return Kw(Pw.count(Fw(t),t),n,2)}function Kx(t,n){return Kw(t.getUTCFullYear()%100,n,2)}function Jx(t,n){return Kw(t.getUTCFullYear()%1e4,n,4)}function tE(){return"+0000"}function nE(){return"%"}function eE(t){return+t}function rE(t){return Math.floor(+t/1e3)}!function(t){Yw=function(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,u=t.shortDays,a=t.months,c=t.shortMonths,l=tx(i),f=nx(i),s=tx(o),h=nx(o),d=tx(u),p=nx(u),v=tx(a),g=nx(a),y=tx(c),m=nx(c),_={a:function(t){return u[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return a[t.getMonth()]},c:null,d:wx,e:wx,f:Nx,H:xx,I:Ex,j:Mx,L:kx,m:Sx,M:Tx,p:function(t){return i[+(t.getHours()>=12)]},Q:eE,s:rE,S:Cx,u:Ax,U:Px,V:Ox,w:Ix,W:Rx,x:null,X:null,y:Dx,Y:Lx,Z:Ux,"%":nE},b={a:function(t){return u[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return a[t.getUTCMonth()]},c:null,d:zx,e:zx,f:Hx,H:jx,I:Fx,j:qx,L:Bx,m:Yx,M:$x,p:function(t){return i[+(t.getUTCHours()>=12)]},Q:eE,s:rE,S:Vx,u:Wx,U:Xx,V:Gx,w:Qx,W:Zx,x:null,X:null,y:Kx,Y:Jx,Z:tE,"%":nE},w={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=s.exec(n.slice(e));return r?(t.w=h[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=y.exec(n.slice(e));return r?(t.m=m[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=g[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,e,r){return M(t,n,e,r)},d:sx,e:sx,f:yx,H:dx,I:dx,j:hx,L:gx,m:fx,M:px,p:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.p=f[r[0].toLowerCase()],e+r[0].length):-1},Q:_x,s:bx,S:vx,u:rx,U:ix,V:ox,w:ex,W:ux,x:function(t,n,r){return M(t,e,n,r)},X:function(t,n,e){return M(t,r,n,e)},y:cx,Y:ax,Z:lx,"%":mx};function x(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,l=t.length;for(e instanceof Date||(e=new Date(+e));++a53)return null;"w"in o||(o.w=1),"Z"in o?(r=(i=(r=Bw(Hw(o.y))).getUTCDay())>4||0===i?Pw.ceil(r):Pw(r),r=Tw.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(r=(i=(r=n(Hw(o.y))).getDay())>4||0===i?dw.ceil(r):dw(r),r=fw.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?Bw(Hw(o.y)).getUTCDay():n(Hw(o.y)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,Bw(o)):n(o)}}function M(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=w[i in Xw?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return _.x=x(e,_),_.X=x(r,_),_.c=x(n,_),b.x=x(e,b),b.X=x(r,b),b.c=x(n,b),{format:function(t){var n=x(t+="",_);return n.toString=function(){return t},n},parse:function(t){var n=E(t+="",qw);return n.toString=function(){return t},n},utcFormat:function(t){var n=x(t+="",b);return n.toString=function(){return t},n},utcParse:function(t){var n=E(t,Bw);return n.toString=function(){return t},n}}}(t),$w=Yw.format,Yw.parse,Vw=Yw.utcFormat,Ww=Yw.utcParse}({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});Date.prototype.toISOString||Vw("%Y-%m-%dT%H:%M:%S.%LZ");+new Date("2000-01-01T00:00:00.000Z")||Ww("%Y-%m-%dT%H:%M:%S.%LZ");var iE=1e3,oE=60*iE,uE=60*oE,aE=24*uE,cE=7*aE,lE=30*aE,fE=365*aE;function sE(t){return new Date(t)}function hE(t){return t instanceof Date?+t:+new Date(+t)}function dE(t,n,e,r,i,o,u,a,c){var l=gb(hb,V_),f=l.invert,s=l.domain,h=c(".%L"),d=c(":%S"),p=c("%I:%M"),v=c("%I %p"),g=c("%a %d"),y=c("%b %d"),m=c("%B"),_=c("%Y"),b=[[u,1,iE],[u,5,5*iE],[u,15,15*iE],[u,30,30*iE],[o,1,oE],[o,5,5*oE],[o,15,15*oE],[o,30,30*oE],[i,1,uE],[i,3,3*uE],[i,6,6*uE],[i,12,12*uE],[r,1,aE],[r,2,2*aE],[e,1,cE],[n,1,lE],[n,3,3*lE],[t,1,fE]];function w(a){return(u(a)1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return ME.h=360*t-100,ME.s=1.5-1.5*n,ME.l=.8-.9*n,ME+""};function NE(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var SE=NE(gE("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),TE=NE(gE("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),CE=NE(gE("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),AE=NE(gE("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function PE(t){var n=0,e=1,r=!1;function i(i){var o=(i-n)/(e-n);return t(r?Math.max(0,Math.min(1,o)):o)}return i.domain=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.clamp=function(t){return arguments.length?(r=!!t,i):r},i.interpolator=function(n){return arguments.length?(t=n,i):t},i.copy=function(){return PE(t).domain([n,e]).clamp(r)},Ib(i)}var OE="http://www.w3.org/1999/xhtml",IE={svg:"http://www.w3.org/2000/svg",xhtml:OE,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},RE=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),IE.hasOwnProperty(n)?{space:IE[n],local:t}:t};var DE=function(t){var n=RE(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===OE&&n.documentElement.namespaceURI===OE?n.createElement(t):n.createElementNS(e,t)}})(n)};function LE(){}var UE=function(t){return null==t?LE:function(){return this.querySelector(t)}};function zE(){return[]}var jE=function(t){return null==t?zE:function(){return this.querySelectorAll(t)}},FE=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var qE=document.documentElement;if(!qE.matches){var BE=qE.webkitMatchesSelector||qE.msMatchesSelector||qE.mozMatchesSelector||qE.oMatchesSelector;FE=function(t){return function(){return BE.call(this,t)}}}}var HE=FE,YE=function(t){return new Array(t.length)};function $E(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}$E.prototype={constructor:$E,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var VE="$";function WE(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var QE=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function ZE(t,n){return t.style.getPropertyValue(n)||QE(t).getComputedStyle(t,null).getPropertyValue(n)}function KE(t){return t.trim().split(/^|\s+/)}function JE(t){return t.classList||new tM(t)}function tM(t){this._node=t,this._names=KE(t.getAttribute("class")||"")}function nM(t,n){for(var e=JE(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function rM(){this.textContent=""}function iM(){this.innerHTML=""}function oM(){this.nextSibling&&this.parentNode.appendChild(this)}function uM(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function aM(){return null}function cM(){var t=this.parentNode;t&&t.removeChild(this)}function lM(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function fM(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var sM={},hM=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(sM={mouseenter:"mouseover",mouseleave:"mouseout"}));function dM(t,n,e){return t=pM(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function pM(t,n,e){return function(r){var i=hM;hM=r;try{t.call(this,this.__data__,n,e)}finally{hM=i}}}function vM(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=GE);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):ZE(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=KE(t+"");if(arguments.length<2){for(var r=JE(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?gM:vM,null==e&&(e=!1),r=0;r1e-6)if(Math.abs(f*a-c*l)>1e-6&&i){var h=e-o,d=r-u,p=a*a+c*c,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(s),m=i*Math.tan((RM-Math.acos((p+s-v)/(2*g*y)))/2),_=m/y,b=m/g;Math.abs(_-1)>1e-6&&(this._+="L"+(t+_*l)+","+(n+_*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>l*d)+","+(this._x1=t+b*a)+","+(this._y1=n+b*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,l=n+a,f=1^o,s=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+l:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-l)>1e-6)&&(this._+="L"+c+","+l),e&&(s<0&&(s=s%DM+DM),s>LM?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=l):s>1e-6&&(this._+="A"+e+","+e+",0,"+ +(s>=RM)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var jM=zM,FM=function(t){return function(){return t}},qM=Math.abs,BM=Math.atan2,HM=Math.cos,YM=Math.max,$M=Math.min,VM=Math.sin,WM=Math.sqrt,XM=1e-12,GM=Math.PI,QM=GM/2,ZM=2*GM;function KM(t){return t>=1?QM:t<=-1?-QM:Math.asin(t)}function JM(t){return t.innerRadius}function tk(t){return t.outerRadius}function nk(t){return t.startAngle}function ek(t){return t.endAngle}function rk(t){return t&&t.padAngle}function ik(t,n,e,r,i,o,u){var a=t-e,c=n-r,l=(u?o:-o)/WM(a*a+c*c),f=l*c,s=-l*a,h=t+f,d=n+s,p=e+f,v=r+s,g=(h+p)/2,y=(d+v)/2,m=p-h,_=v-d,b=m*m+_*_,w=i-o,x=h*v-p*d,E=(_<0?-1:1)*WM(YM(0,w*w*b-x*x)),M=(x*_-m*E)/b,k=(-x*m-_*E)/b,N=(x*_+m*E)/b,S=(-x*m+_*E)/b,T=M-g,C=k-y,A=N-g,P=S-y;return T*T+C*C>A*A+P*P&&(M=N,k=S),{cx:M,cy:k,x01:-f,y01:-s,x11:M*(i/w-1),y11:k*(i/w-1)}}var ok=function(){var t=JM,n=tk,e=FM(0),r=null,i=nk,o=ek,u=rk,a=null;function c(){var c,l,f=+t.apply(this,arguments),s=+n.apply(this,arguments),h=i.apply(this,arguments)-QM,d=o.apply(this,arguments)-QM,p=qM(d-h),v=d>h;if(a||(a=c=jM()),sXM)if(p>ZM-XM)a.moveTo(s*HM(h),s*VM(h)),a.arc(0,0,s,h,d,!v),f>XM&&(a.moveTo(f*HM(d),f*VM(d)),a.arc(0,0,f,d,h,v));else{var g,y,m=h,_=d,b=h,w=d,x=p,E=p,M=u.apply(this,arguments)/2,k=M>XM&&(r?+r.apply(this,arguments):WM(f*f+s*s)),N=$M(qM(s-f)/2,+e.apply(this,arguments)),S=N,T=N;if(k>XM){var C=KM(k/f*VM(M)),A=KM(k/s*VM(M));(x-=2*C)>XM?(b+=C*=v?1:-1,w-=C):(x=0,b=w=(h+d)/2),(E-=2*A)>XM?(m+=A*=v?1:-1,_-=A):(E=0,m=_=(h+d)/2)}var P=s*HM(m),O=s*VM(m),I=f*HM(w),R=f*VM(w);if(N>XM){var D=s*HM(_),L=s*VM(_),U=f*HM(b),z=f*VM(b);if(pXM?function(t,n,e,r,i,o,u,a){var c=e-t,l=r-n,f=u-i,s=a-o,h=(f*(n-o)-s*(t-i))/(s*c-f*l);return[t+h*c,n+h*l]}(P,O,U,z,D,L,I,R):[I,R],F=P-j[0],q=O-j[1],B=D-j[0],H=L-j[1],Y=1/VM(function(t){return t>1?0:t<-1?GM:Math.acos(t)}((F*B+q*H)/(WM(F*F+q*q)*WM(B*B+H*H)))/2),$=WM(j[0]*j[0]+j[1]*j[1]);S=$M(N,(f-$)/(Y-1)),T=$M(N,(s-$)/(Y+1))}}E>XM?T>XM?(g=ik(U,z,P,O,s,T,v),y=ik(D,L,I,R,s,T,v),a.moveTo(g.cx+g.x01,g.cy+g.y01),TXM&&x>XM?S>XM?(g=ik(I,R,D,L,f,-S,v),y=ik(P,O,U,z,f,-S,v),a.lineTo(g.cx+g.x01,g.cy+g.y01),S=f;--s)a.point(g[s],y[s]);a.lineEnd(),a.areaEnd()}v&&(g[l]=+t(h,l,c),y[l]=+e(h,l,c),a.point(n?+n(h,l,c):g[l],r?+r(h,l,c):y[l]))}if(d)return a=null,d+""||null}function l(){return fk().defined(i).curve(u).context(o)}return c.x=function(e){return arguments.length?(t="function"==typeof e?e:FM(+e),n=null,c):t},c.x0=function(n){return arguments.length?(t="function"==typeof n?n:FM(+n),c):t},c.x1=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:FM(+t),c):n},c.y=function(t){return arguments.length?(e="function"==typeof t?t:FM(+t),r=null,c):e},c.y0=function(t){return arguments.length?(e="function"==typeof t?t:FM(+t),c):e},c.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:FM(+t),c):r},c.lineX0=c.lineY0=function(){return l().x(t).y(e)},c.lineY1=function(){return l().x(t).y(r)},c.lineX1=function(){return l().x(n).y(e)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:FM(!!t),c):i},c.curve=function(t){return arguments.length?(u=t,null!=o&&(a=u(o)),c):u},c.context=function(t){return arguments.length?(null==t?o=a=null:a=u(o=t),c):o},c},hk=function(t,n){return nt?1:n>=t?0:NaN},dk=function(t){return t},pk=function(){var t=dk,n=hk,e=null,r=FM(0),i=FM(ZM),o=FM(0);function u(u){var a,c,l,f,s,h=u.length,d=0,p=new Array(h),v=new Array(h),g=+r.apply(this,arguments),y=Math.min(ZM,Math.max(-ZM,i.apply(this,arguments)-g)),m=Math.min(Math.abs(y)/h,o.apply(this,arguments)),_=m*(y<0?-1:1);for(a=0;a0&&(d+=s);for(null!=n?p.sort(function(t,e){return n(v[t],v[e])}):null!=e&&p.sort(function(t,n){return e(u[t],u[n])}),a=0,l=d?(y-h*_)/d:0;a0?s*l:0)+_,v[c]={data:u[c],index:a,value:s,startAngle:g,endAngle:f,padAngle:m};return v}return u.value=function(n){return arguments.length?(t="function"==typeof n?n:FM(+n),u):t},u.sortValues=function(t){return arguments.length?(n=t,e=null,u):n},u.sort=function(t){return arguments.length?(e=t,n=null,u):e},u.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:FM(+t),u):r},u.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:FM(+t),u):i},u.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:FM(+t),u):o},u},vk=yk(ak);function gk(t){this._curve=t}function yk(t){function n(n){return new gk(t(n))}return n._curve=t,n}function mk(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(yk(t)):n()._curve},t}gk.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var _k=function(){return mk(fk().curve(vk))},bk=function(){var t=sk().curve(vk),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return mk(e())},delete t.lineX0,t.lineEndAngle=function(){return mk(r())},delete t.lineX1,t.lineInnerRadius=function(){return mk(i())},delete t.lineY0,t.lineOuterRadius=function(){return mk(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(yk(t)):n()._curve},t},wk=function(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]},xk=Array.prototype.slice;function Ek(t){return t.source}function Mk(t){return t.target}function kk(t){var n=Ek,e=Mk,r=ck,i=lk,o=null;function u(){var u,a=xk.call(arguments),c=n.apply(this,a),l=e.apply(this,a);if(o||(o=u=jM()),t(o,+r.apply(this,(a[0]=c,a)),+i.apply(this,a),+r.apply(this,(a[0]=l,a)),+i.apply(this,a)),u)return o=null,u+""||null}return u.source=function(t){return arguments.length?(n=t,u):n},u.target=function(t){return arguments.length?(e=t,u):e},u.x=function(t){return arguments.length?(r="function"==typeof t?t:FM(+t),u):r},u.y=function(t){return arguments.length?(i="function"==typeof t?t:FM(+t),u):i},u.context=function(t){return arguments.length?(o=null==t?null:t,u):o},u}function Nk(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function Sk(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function Tk(t,n,e,r,i){var o=wk(n,e),u=wk(n,e=(e+i)/2),a=wk(r,e),c=wk(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(u[0],u[1],a[0],a[1],c[0],c[1])}function Ck(){return kk(Nk)}function Ak(){return kk(Sk)}function Pk(){var t=kk(Tk);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t}var Ok={draw:function(t,n){var e=Math.sqrt(n/GM);t.moveTo(e,0),t.arc(0,0,e,0,ZM)}},Ik={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Rk=Math.sqrt(1/3),Dk=2*Rk,Lk={draw:function(t,n){var e=Math.sqrt(n/Dk),r=e*Rk;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},Uk=Math.sin(GM/10)/Math.sin(7*GM/10),zk=Math.sin(ZM/10)*Uk,jk=-Math.cos(ZM/10)*Uk,Fk={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=zk*e,i=jk*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=ZM*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},qk={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Bk=Math.sqrt(3),Hk={draw:function(t,n){var e=-Math.sqrt(n/(3*Bk));t.moveTo(0,2*e),t.lineTo(-Bk*e,-e),t.lineTo(Bk*e,-e),t.closePath()}},Yk=Math.sqrt(3)/2,$k=1/Math.sqrt(12),Vk=3*($k/2+1),Wk={draw:function(t,n){var e=Math.sqrt(n/Vk),r=e/2,i=e*$k,o=r,u=e*$k+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(-.5*r-Yk*i,Yk*r+-.5*i),t.lineTo(-.5*o-Yk*u,Yk*o+-.5*u),t.lineTo(-.5*a-Yk*c,Yk*a+-.5*c),t.lineTo(-.5*r+Yk*i,-.5*i-Yk*r),t.lineTo(-.5*o+Yk*u,-.5*u-Yk*o),t.lineTo(-.5*a+Yk*c,-.5*c-Yk*a),t.closePath()}},Xk=[Ok,Ik,Lk,qk,Fk,Hk,Wk],Gk=function(){var t=FM(Ok),n=FM(64),e=null;function r(){var r;if(e||(e=r=jM()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),r)return e=null,r+""||null}return r.type=function(n){return arguments.length?(t="function"==typeof n?n:FM(n),r):t},r.size=function(t){return arguments.length?(n="function"==typeof t?t:FM(+t),r):n},r.context=function(t){return arguments.length?(e=null==t?null:t,r):e},r},Qk=function(){};function Zk(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Kk(t){this._context=t}Kk.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Zk(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Zk(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var Jk=function(t){return new Kk(t)};function tN(t){this._context=t}tN.prototype={areaStart:Qk,areaEnd:Qk,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Zk(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var nN=function(t){return new tN(t)};function eN(t){this._context=t}eN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Zk(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var rN=function(t){return new eN(t)};function iN(t,n){this._basis=new Kk(t),this._beta=n}iN.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var oN=function t(n){function e(t){return 1===n?new Kk(t):new iN(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function uN(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function aN(t,n){this._context=t,this._k=(1-n)/6}aN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:uN(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:uN(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var cN=function t(n){function e(t){return new aN(t,n)}return e.tension=function(n){return t(+n)},e}(0);function lN(t,n){this._context=t,this._k=(1-n)/6}lN.prototype={areaStart:Qk,areaEnd:Qk,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:uN(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var fN=function t(n){function e(t){return new lN(t,n)}return e.tension=function(n){return t(+n)},e}(0);function sN(t,n){this._context=t,this._k=(1-n)/6}sN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:uN(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var hN=function t(n){function e(t){return new sN(t,n)}return e.tension=function(n){return t(+n)},e}(0);function dN(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>XM){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>XM){var l=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*l+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*l+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function pN(t,n){this._context=t,this._alpha=n}pN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:dN(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var vN=function t(n){function e(t){return n?new pN(t,n):new aN(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function gN(t,n){this._context=t,this._alpha=n}gN.prototype={areaStart:Qk,areaEnd:Qk,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:dN(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var yN=function t(n){function e(t){return n?new gN(t,n):new lN(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function mN(t,n){this._context=t,this._alpha=n}mN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:dN(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var _N=function t(n){function e(t){return n?new mN(t,n):new sN(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function bN(t){this._context=t}bN.prototype={areaStart:Qk,areaEnd:Qk,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};var wN=function(t){return new bN(t)};function xN(t){return t<0?-1:1}function EN(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(xN(o)+xN(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function MN(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function kN(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function NN(t){this._context=t}function SN(t){this._context=new TN(t)}function TN(t){this._context=t}function CN(t){return new NN(t)}function AN(t){return new SN(t)}function PN(t){this._context=t}function ON(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var DN=function(t){return new RN(t,.5)};function LN(t){return new RN(t,0)}function UN(t){return new RN(t,1)}var zN=function(t,n){if((i=t.length)>1)for(var e,r,i,o=1,u=t[n[0]],a=u.length;o=0;)e[n]=n;return e};function FN(t,n){return t[n]}var qN=function(){var t=FM([]),n=jN,e=zN,r=FN;function i(i){var o,u,a=t.apply(this,arguments),c=i.length,l=a.length,f=new Array(l);for(o=0;o0){for(var e,r,i,o=0,u=t[0].length;o1)for(var e,r,i,o,u,a,c=0,l=t[n[0]].length;c=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=u,r[0]=u+=i):r[0]=o},YN=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u0))return a;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(u=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return ZN.setTime(+n),KN.setTime(+r),t(ZN),t(KN),Math.floor(e(ZN,KN))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var tS=JN(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});tS.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?JN(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):tS:null};var nS=tS,eS=tS.range,rS=6e4,iS=6048e5,oS=JN(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),uS=oS,aS=oS.range,cS=JN(function(t){t.setTime(Math.floor(t/rS)*rS)},function(t,n){t.setTime(+t+n*rS)},function(t,n){return(n-t)/rS},function(t){return t.getMinutes()}),lS=cS,fS=cS.range,sS=JN(function(t){var n=t.getTimezoneOffset()*rS%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),hS=sS,dS=sS.range,pS=JN(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*rS)/864e5},function(t){return t.getDate()-1}),vS=pS,gS=pS.range;function yS(t){return JN(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*rS)/iS})}var mS=yS(0),_S=yS(1),bS=yS(2),wS=yS(3),xS=yS(4),ES=yS(5),MS=yS(6),kS=mS.range,NS=_S.range,SS=bS.range,TS=wS.range,CS=xS.range,AS=ES.range,PS=MS.range,OS=JN(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),IS=OS,RS=OS.range,DS=JN(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});DS.every=function(t){return isFinite(t=Math.floor(t))&&t>0?JN(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var LS=DS,US=DS.range,zS=JN(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*rS)},function(t,n){return(n-t)/rS},function(t){return t.getUTCMinutes()}),jS=zS,FS=zS.range,qS=JN(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),BS=qS,HS=qS.range,YS=JN(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),$S=YS,VS=YS.range;function WS(t){return JN(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/iS})}var XS=WS(0),GS=WS(1),QS=WS(2),ZS=WS(3),KS=WS(4),JS=WS(5),tT=WS(6),nT=XS.range,eT=GS.range,rT=QS.range,iT=ZS.range,oT=KS.range,uT=JS.range,aT=tT.range,cT=JN(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),lT=cT,fT=cT.range,sT=JN(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});sT.every=function(t){return isFinite(t=Math.floor(t))&&t>0?JN(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var hT=sT,dT=sT.range,pT=new Date,vT=new Date;function gT(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n0))return a;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(u=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return pT.setTime(+n),vT.setTime(+r),t(pT),t(vT),Math.floor(e(pT,vT))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var yT=gT(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});yT.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?gT(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):yT:null};yT.range;var mT=6e4,_T=6048e5,bT=gT(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),wT=(bT.range,gT(function(t){t.setTime(Math.floor(t/mT)*mT)},function(t,n){t.setTime(+t+n*mT)},function(t,n){return(n-t)/mT},function(t){return t.getMinutes()})),xT=(wT.range,gT(function(t){var n=t.getTimezoneOffset()*mT%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()})),ET=(xT.range,gT(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*mT)/864e5},function(t){return t.getDate()-1})),MT=ET;ET.range;function kT(t){return gT(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*mT)/_T})}var NT=kT(0),ST=kT(1),TT=kT(2),CT=kT(3),AT=kT(4),PT=kT(5),OT=kT(6),IT=(NT.range,ST.range,TT.range,CT.range,AT.range,PT.range,OT.range,gT(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()})),RT=(IT.range,gT(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()}));RT.every=function(t){return isFinite(t=Math.floor(t))&&t>0?gT(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var DT=RT,LT=(RT.range,gT(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*mT)},function(t,n){return(n-t)/mT},function(t){return t.getUTCMinutes()})),UT=(LT.range,gT(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()})),zT=(UT.range,gT(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1})),jT=zT;zT.range;function FT(t){return gT(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/_T})}var qT=FT(0),BT=FT(1),HT=FT(2),YT=FT(3),$T=FT(4),VT=FT(5),WT=FT(6),XT=(qT.range,BT.range,HT.range,YT.range,$T.range,VT.range,WT.range,gT(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()})),GT=(XT.range,gT(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()}));GT.every=function(t){return isFinite(t=Math.floor(t))&&t>0?gT(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var QT=GT;GT.range;function ZT(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function KT(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function JT(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function tC(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,u=t.shortDays,a=t.months,c=t.shortMonths,l=hC(i),f=dC(i),s=hC(o),h=dC(o),d=hC(u),p=dC(u),v=hC(a),g=dC(a),y=hC(c),m=dC(c),_={a:function(t){return u[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return a[t.getMonth()]},c:null,d:IC,e:IC,f:zC,H:RC,I:DC,j:LC,L:UC,m:jC,M:FC,p:function(t){return i[+(t.getHours()>=12)]},Q:pA,s:vA,S:qC,u:BC,U:HC,V:YC,w:$C,W:VC,x:null,X:null,y:WC,Y:XC,Z:GC,"%":dA},b={a:function(t){return u[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return a[t.getUTCMonth()]},c:null,d:QC,e:QC,f:nA,H:ZC,I:KC,j:JC,L:tA,m:eA,M:rA,p:function(t){return i[+(t.getUTCHours()>=12)]},Q:pA,s:vA,S:iA,u:oA,U:uA,V:aA,w:cA,W:lA,x:null,X:null,y:fA,Y:sA,Z:hA,"%":dA},w={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=s.exec(n.slice(e));return r?(t.w=h[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=y.exec(n.slice(e));return r?(t.m=m[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=g[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,e,r){return M(t,n,e,r)},d:EC,e:EC,f:CC,H:kC,I:kC,j:MC,L:TC,m:xC,M:NC,p:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.p=f[r[0].toLowerCase()],e+r[0].length):-1},Q:PC,s:OC,S:SC,u:vC,U:gC,V:yC,w:pC,W:mC,x:function(t,n,r){return M(t,e,n,r)},X:function(t,n,e){return M(t,r,n,e)},y:bC,Y:_C,Z:wC,"%":AC};function x(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,l=t.length;for(e instanceof Date||(e=new Date(+e));++a53)return null;"w"in o||(o.w=1),"Z"in o?(r=(i=(r=KT(JT(o.y))).getUTCDay())>4||0===i?BT.ceil(r):BT(r),r=jT.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(r=(i=(r=n(JT(o.y))).getDay())>4||0===i?ST.ceil(r):ST(r),r=MT.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?KT(JT(o.y)).getUTCDay():n(JT(o.y)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,KT(o)):n(o)}}function M(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=w[i in uC?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return _.x=x(e,_),_.X=x(r,_),_.c=x(n,_),b.x=x(e,b),b.X=x(r,b),b.c=x(n,b),{format:function(t){var n=x(t+="",_);return n.toString=function(){return t},n},parse:function(t){var n=E(t+="",ZT);return n.toString=function(){return t},n},utcFormat:function(t){var n=x(t+="",b);return n.toString=function(){return t},n},utcParse:function(t){var n=E(t,KT);return n.toString=function(){return t},n}}}var nC,eC,rC,iC,oC,uC={"-":"",_:" ",0:"0"},aC=/^\s*\d+/,cC=/^%/,lC=/[\\^$*+?|[\]().{}]/g;function fC(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o68?1900:2e3),e+r[0].length):-1}function wC(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function xC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function EC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function MC(t,n,e){var r=aC.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function kC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function NC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function SC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function TC(t,n,e){var r=aC.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function CC(t,n,e){var r=aC.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function AC(t,n,e){var r=cC.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function PC(t,n,e){var r=aC.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function OC(t,n,e){var r=aC.exec(n.slice(e));return r?(t.Q=1e3*+r[0],e+r[0].length):-1}function IC(t,n){return fC(t.getDate(),n,2)}function RC(t,n){return fC(t.getHours(),n,2)}function DC(t,n){return fC(t.getHours()%12||12,n,2)}function LC(t,n){return fC(1+MT.count(DT(t),t),n,3)}function UC(t,n){return fC(t.getMilliseconds(),n,3)}function zC(t,n){return UC(t,n)+"000"}function jC(t,n){return fC(t.getMonth()+1,n,2)}function FC(t,n){return fC(t.getMinutes(),n,2)}function qC(t,n){return fC(t.getSeconds(),n,2)}function BC(t){var n=t.getDay();return 0===n?7:n}function HC(t,n){return fC(NT.count(DT(t),t),n,2)}function YC(t,n){var e=t.getDay();return t=e>=4||0===e?AT(t):AT.ceil(t),fC(AT.count(DT(t),t)+(4===DT(t).getDay()),n,2)}function $C(t){return t.getDay()}function VC(t,n){return fC(ST.count(DT(t),t),n,2)}function WC(t,n){return fC(t.getFullYear()%100,n,2)}function XC(t,n){return fC(t.getFullYear()%1e4,n,4)}function GC(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+fC(n/60|0,"0",2)+fC(n%60,"0",2)}function QC(t,n){return fC(t.getUTCDate(),n,2)}function ZC(t,n){return fC(t.getUTCHours(),n,2)}function KC(t,n){return fC(t.getUTCHours()%12||12,n,2)}function JC(t,n){return fC(1+jT.count(QT(t),t),n,3)}function tA(t,n){return fC(t.getUTCMilliseconds(),n,3)}function nA(t,n){return tA(t,n)+"000"}function eA(t,n){return fC(t.getUTCMonth()+1,n,2)}function rA(t,n){return fC(t.getUTCMinutes(),n,2)}function iA(t,n){return fC(t.getUTCSeconds(),n,2)}function oA(t){var n=t.getUTCDay();return 0===n?7:n}function uA(t,n){return fC(qT.count(QT(t),t),n,2)}function aA(t,n){var e=t.getUTCDay();return t=e>=4||0===e?$T(t):$T.ceil(t),fC($T.count(QT(t),t)+(4===QT(t).getUTCDay()),n,2)}function cA(t){return t.getUTCDay()}function lA(t,n){return fC(BT.count(QT(t),t),n,2)}function fA(t,n){return fC(t.getUTCFullYear()%100,n,2)}function sA(t,n){return fC(t.getUTCFullYear()%1e4,n,4)}function hA(){return"+0000"}function dA(){return"%"}function pA(t){return+t}function vA(t){return Math.floor(+t/1e3)}function gA(t){return nC=tC(t),eC=nC.format,rC=nC.parse,iC=nC.utcFormat,oC=nC.utcParse,nC}gA({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var yA=Date.prototype.toISOString?function(t){return t.toISOString()}:iC("%Y-%m-%dT%H:%M:%S.%LZ");var mA,_A,bA=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:oC("%Y-%m-%dT%H:%M:%S.%LZ"),wA=0,xA=0,EA=0,MA=1e3,kA=0,NA=0,SA=0,TA="object"==typeof performance&&performance.now?performance:Date,CA="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function AA(){return NA||(CA(PA),NA=TA.now()+SA)}function PA(){NA=0}function OA(){this._call=this._time=this._next=null}function IA(t,n,e){var r=new OA;return r.restart(t,n,e),r}function RA(){AA(),++wA;for(var t,n=mA;n;)(t=NA-n._time)>=0&&n._call.call(null,t),n=n._next;--wA}function DA(){NA=(kA=TA.now())+SA,wA=xA=0;try{RA()}finally{wA=0,function(){var t,n,e=mA,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:mA=n);_A=t,UA(r)}(),NA=0}}function LA(){var t=TA.now(),n=t-kA;n>MA&&(SA-=n,kA=t)}function UA(t){wA||(xA&&(xA=clearTimeout(xA)),t-NA>24?(t<1/0&&(xA=setTimeout(DA,t-TA.now()-SA)),EA&&(EA=clearInterval(EA))):(EA||(kA=TA.now(),EA=setInterval(LA,MA)),wA=1,CA(DA)))}OA.prototype=IA.prototype={constructor:OA,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?AA():+e)+(null==n?0:+n),this._next||_A===this||(_A?_A._next=this:mA=this,_A=this),this._call=t,this._time=e,UA()},stop:function(){this._call&&(this._call=null,this._time=1/0,UA())}};var zA=function(t,n,e){var r=new OA;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},jA=function(t,n,e){var r=new OA,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?AA():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},FA="http://www.w3.org/1999/xhtml",qA={svg:"http://www.w3.org/2000/svg",xhtml:FA,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},BA=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),qA.hasOwnProperty(n)?{space:qA[n],local:t}:t};var HA=function(t){var n=BA(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===FA&&n.documentElement.namespaceURI===FA?n.createElement(t):n.createElementNS(e,t)}})(n)};function YA(){}var $A=function(t){return null==t?YA:function(){return this.querySelector(t)}};function VA(){return[]}var WA=function(t){return null==t?VA:function(){return this.querySelectorAll(t)}},XA=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var GA=document.documentElement;if(!GA.matches){var QA=GA.webkitMatchesSelector||GA.msMatchesSelector||GA.mozMatchesSelector||GA.oMatchesSelector;XA=function(t){return function(){return QA.call(this,t)}}}}var ZA=XA,KA=function(t){return new Array(t.length)};function JA(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}JA.prototype={constructor:JA,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var tP="$";function nP(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var iP=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function oP(t,n){return t.style.getPropertyValue(n)||iP(t).getComputedStyle(t,null).getPropertyValue(n)}function uP(t){return t.trim().split(/^|\s+/)}function aP(t){return t.classList||new cP(t)}function cP(t){this._node=t,this._names=uP(t.getAttribute("class")||"")}function lP(t,n){for(var e=aP(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function sP(){this.textContent=""}function hP(){this.innerHTML=""}function dP(){this.nextSibling&&this.parentNode.appendChild(this)}function pP(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function vP(){return null}function gP(){var t=this.parentNode;t&&t.removeChild(this)}function yP(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function mP(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var _P={},bP=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(_P={mouseenter:"mouseover",mouseleave:"mouseout"}));function wP(t,n,e){return t=xP(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function xP(t,n,e){return function(r){var i=bP;bP=r;try{t.call(this,this.__data__,n,e)}finally{bP=i}}}function EP(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=rP);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):oP(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=uP(t+"");if(arguments.length<2){for(var r=aP(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?MP:EP,null==e&&(e=!1),r=0;r=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&n._call.call(null,t),n=n._next;--FP}()}finally{FP=0,function(){var t,n,e=UP,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:UP=n);zP=t,nO(r)}(),$P=0}}function tO(){var t=WP.now(),n=t-YP;n>HP&&(VP-=n,YP=t)}function nO(t){FP||(qP&&(qP=clearTimeout(qP)),t-$P>24?(t<1/0&&(qP=setTimeout(JP,t-WP.now()-VP)),BP&&(BP=clearInterval(BP))):(BP||(YP=WP.now(),BP=setInterval(tO,HP)),FP=1,XP(JP)))}ZP.prototype=KP.prototype={constructor:ZP,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?GP():+e)+(null==n?0:+n),this._next||zP===this||(zP?zP._next=this:UP=this,zP=this),this._call=t,this._time=e,nO()},stop:function(){this._call&&(this._call=null,this._time=1/0,nO())}};var eO=function(t,n,e){var r=new ZP;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},rO=jP("start","end","interrupt"),iO=[],oO=0,uO=1,aO=2,cO=3,lO=4,fO=5,sO=6,hO=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(c){var l,f,s,h;if(e.state!==uO)return a();for(l in i)if((h=i[l]).name===e.name){if(h.state===cO)return eO(o);h.state===lO?(h.state=sO,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[l]):+loO)throw new Error("too late; already scheduled");return e}function pO(t,n){var e=vO(t,n);if(e.state>aO)throw new Error("too late; already started");return e}function vO(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}var gO=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>aO&&e.state>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=xO.exec(t))?PO(parseInt(n[1],16)):(n=EO.exec(t))?new DO(n[1],n[2],n[3],1):(n=MO.exec(t))?new DO(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=kO.exec(t))?OO(n[1],n[2],n[3],n[4]):(n=NO.exec(t))?OO(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=SO.exec(t))?UO(n[1],n[2]/100,n[3]/100,1):(n=TO.exec(t))?UO(n[1],n[2]/100,n[3]/100,n[4]):CO.hasOwnProperty(t)?PO(CO[t]):"transparent"===t?new DO(NaN,NaN,NaN,0):null}function PO(t){return new DO(t>>16&255,t>>8&255,255&t,1)}function OO(t,n,e,r){return r<=0&&(t=n=e=NaN),new DO(t,n,e,r)}function IO(t){return t instanceof _O||(t=AO(t)),t?new DO((t=t.rgb()).r,t.g,t.b,t.opacity):new DO}function RO(t,n,e,r){return 1===arguments.length?IO(t):new DO(t,n,e,null==r?1:r)}function DO(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function LO(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function UO(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new jO(t,n,e,r)}function zO(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof jO)return new jO(t.h,t.s,t.l,t.opacity);if(t instanceof _O||(t=AO(t)),!t)return new jO;if(t instanceof jO)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new jO(u,a,c,t.opacity)}(t):new jO(t,n,e,null==r?1:r)}function jO(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function FO(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}yO(_O,AO,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),yO(DO,RO,mO(_O,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new DO(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new DO(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+LO(this.r)+LO(this.g)+LO(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),yO(jO,zO,mO(_O,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new jO(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new jO(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new DO(FO(t>=240?t-240:t+120,i,r),FO(t,i,r),FO(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var qO=Math.PI/180,BO=180/Math.PI,HO=.96422,YO=1,$O=.82521,VO=4/29,WO=6/29,XO=3*WO*WO,GO=WO*WO*WO;function QO(t){if(t instanceof KO)return new KO(t.l,t.a,t.b,t.opacity);if(t instanceof oI){if(isNaN(t.h))return new KO(t.l,0,0,t.opacity);var n=t.h*qO;return new KO(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof DO||(t=IO(t));var e,r,i=eI(t.r),o=eI(t.g),u=eI(t.b),a=JO((.2225045*i+.7168786*o+.0606169*u)/YO);return i===o&&o===u?e=r=a:(e=JO((.4360747*i+.3850649*o+.1430804*u)/HO),r=JO((.0139322*i+.0971045*o+.7141733*u)/$O)),new KO(116*a-16,500*(e-a),200*(a-r),t.opacity)}function ZO(t,n,e,r){return 1===arguments.length?QO(t):new KO(t,n,e,null==r?1:r)}function KO(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function JO(t){return t>GO?Math.pow(t,1/3):t/XO+VO}function tI(t){return t>WO?t*t*t:XO*(t-VO)}function nI(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function eI(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function rI(t){if(t instanceof oI)return new oI(t.h,t.c,t.l,t.opacity);if(t instanceof KO||(t=QO(t)),0===t.a&&0===t.b)return new oI(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*BO;return new oI(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function iI(t,n,e,r){return 1===arguments.length?rI(t):new oI(t,n,e,null==r?1:r)}function oI(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}yO(KO,ZO,mO(_O,{brighter:function(t){return new KO(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new KO(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new DO(nI(3.1338561*(n=HO*tI(n))-1.6168667*(t=YO*tI(t))-.4906146*(e=$O*tI(e))),nI(-.9787684*n+1.9161415*t+.033454*e),nI(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),yO(oI,iI,mO(_O,{brighter:function(t){return new oI(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new oI(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return QO(this).rgb()}}));var uI=-.29227,aI=-.90649,cI=1.97294,lI=cI*aI,fI=1.78277*cI,sI=1.78277*uI- -.14861*aI;function hI(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof dI)return new dI(t.h,t.s,t.l,t.opacity);t instanceof DO||(t=IO(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(sI*r+lI*n-fI*e)/(sI+lI-fI),o=r-i,u=(cI*(e-i)-uI*o)/aI,a=Math.sqrt(u*u+o*o)/(cI*i*(1-i)),c=a?Math.atan2(u,o)*BO-120:NaN;return new dI(c<0?c+360:c,a,i,t.opacity)}(t):new dI(t,n,e,null==r?1:r)}function dI(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function pI(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}yO(dI,hI,mO(_O,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new dI(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new dI(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*qO,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new DO(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(uI*r+aI*i)),255*(n+e*(cI*r)),this.opacity)}}));var vI=function(t){return function(){return t}};function gI(t,n){return function(e){return t+e*n}}function yI(t,n){var e=n-t;return e?gI(t,e>180||e<-180?e-360*Math.round(e/360):e):vI(isNaN(t)?n:t)}function mI(t){return 1==(t=+t)?_I:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):vI(isNaN(n)?e:n)}}function _I(t,n){var e=n-t;return e?gI(t,e):vI(isNaN(t)?n:t)}var bI=function t(n){var e=mI(n);function r(t,n){var r=e((t=RO(t)).r,(n=RO(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=_I(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function wI(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:xI(e,r)})),o=MI.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:xI(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:xI(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:xI(t,e)},{i:a-2,x:xI(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?dO:pO;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}(e,t,n))},attr:function(t,n){var e=BA(t),r="transform"===e?DI:FI;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}})(e,r,jI(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}:function(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}})(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=BA(t);return this.tween(e,(r.local?function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}:function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?RI:FI;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=oP(this,t),u=(this.style.removeProperty(t),oP(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}(t,r)).on("end.style."+t,function(t){return function(){this.style.removeProperty(t)}}(t)):this.styleTween(t,"function"==typeof n?function(t,n,e){var r,i,o;return function(){var u=oP(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=oP(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}(t,r,jI(this,"style."+t,n)):function(t,n,e){var r,i;return function(){var o=oP(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(jI(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=vO(this.node(),e).tween,o=0,u=i.length;ouO&&e.name===n)return new HI([[t]],QI,n,+r);return null},KI=function(t){return function(){return t}};function JI(t){return t[0]}function tR(t){return t[1]}function nR(){this._=null}function eR(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function rR(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function iR(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function oR(t){for(;t.L;)t=t.L;return t}nR.prototype={constructor:nR,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=oR(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(rR(this,e),e=(t=e).U),e.C=!1,r.C=!0,iR(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(iR(this,e),e=(t=e).U),e.C=!1,r.C=!0,rR(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?oR(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,rR(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,iR(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,rR(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,iR(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,rR(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,iR(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var uR=nR;function aR(t,n,e,r){var i=[null,null],o=CR.push(i)-1;return i.left=t,i.right=n,e&&lR(i,t,n,e),r&&lR(i,n,t,r),SR[t.index].halfedges.push(o),SR[n.index].halfedges.push(o),i}function cR(t,n,e){var r=[n,e];return r.left=t,r}function lR(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function fR(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],l=u[1],f=0,s=1,h=a[0]-c,d=a[1]-l;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o0){if(o>s)return;o>f&&(f=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>s)return;o>f&&(f=o)}else if(h>0){if(o0)){if(o/=d,d<0){if(o0){if(o>s)return;o>f&&(f=o)}if(o=i-l,d||!(o<0)){if(o/=d,d<0){if(o>s)return;o>f&&(f=o)}else if(d>0){if(o0||s<1)||(f>0&&(t[0]=[c+f*h,l+f*d]),s<1&&(t[1]=[c+s*h,l+s*d]),!0)}}}}}function sR(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],l=t.left,f=t.right,s=l[0],h=l[1],d=f[0],p=f[1],v=(s+d)/2,g=(h+p)/2;if(p===h){if(v=r)return;if(s>d){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]1)if(s>d){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]=-PR)){var d=c*c+l*l,p=f*f+s*s,v=(s*d-l*p)/h,g=(c*p-f*d)/h,y=gR.pop()||new function(){eR(this),this.x=this.y=this.arc=this.site=this.cy=null};y.arc=t,y.site=i,y.x=v+u,y.y=(y.cy=g+a)+Math.sqrt(v*v+g*g),t.circle=y;for(var m=null,_=TR._;_;)if(y.y<_.y||y.y===_.y&&y.x<=_.x){if(!_.L){m=_.P;break}_=_.L}else{if(!_.R){m=_;break}_=_.R}TR.insert(m,y),m||(vR=y)}}}}function mR(t){var n=t.circle;n&&(n.P||(vR=n.N),TR.remove(n),gR.push(n),eR(n),t.circle=null)}var _R=[];function bR(t){var n=_R.pop()||new function(){eR(this),this.edge=this.site=this.circle=null};return n.site=t,n}function wR(t){mR(t),NR.remove(t),_R.push(t),eR(t)}function xR(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];wR(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)AR)a=a.L;else{if(!((i=o-kR(a,u))>AR)){r>-AR?(n=a.P,e=a):i>-AR?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}!function(t){SR[t.index]={site:t,halfedges:[]}}(t);var c=bR(t);if(NR.insert(n,c),n||e){if(n===e)return mR(n),e=bR(n.site),NR.insert(c,e),c.edge=e.edge=aR(n.site,c.site),yR(n),void yR(e);if(e){mR(n),mR(e);var l=n.site,f=l[0],s=l[1],h=t[0]-f,d=t[1]-s,p=e.site,v=p[0]-f,g=p[1]-s,y=2*(h*g-d*v),m=h*h+d*d,_=v*v+g*g,b=[(g*m-d*_)/y+f,(h*_-v*m)/y+s];lR(e.edge,l,p,b),c.edge=aR(l,t,null,b),e.edge=aR(t,p,null,b),yR(n),yR(e)}else c.edge=aR(n.site,c.site)}}function MR(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-1/0;var a=(e=u.site)[0],c=e[1],l=c-n;if(!l)return a;var f=a-r,s=1/o-1/l,h=f/l;return s?(-h+Math.sqrt(h*h-2*s*(f*f/(-2*l)-c+l/2+i-o/2)))/s+r:(r+a)/2}function kR(t,n){var e=t.N;if(e)return MR(e,n);var r=t.site;return r[1]===n?r[0]:1/0}var NR,SR,TR,CR,AR=1e-6,PR=1e-12;function OR(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function IR(t,n){return n[1]-t[1]||n[0]-t[0]}function RR(t,n){var e,r,i,o=t.sort(IR).pop();for(CR=[],SR=new Array(t.length),NR=new uR,TR=new uR;;)if(i=vR,o&&(!i||o[1]AR||Math.abs(i[0][1]-i[1][1])>AR)||delete CR[o]}(u,a,c,l),function(t,n,e,r){var i,o,u,a,c,l,f,s,h,d,p,v,g=SR.length,y=!0;for(i=0;iAR||Math.abs(v-h)>AR)&&(c.splice(a,0,CR.push(cR(u,d,Math.abs(p-t)AR?[t,Math.abs(s-t)AR?[Math.abs(h-r)AR?[e,Math.abs(s-e)AR?[Math.abs(h-n)=a)return null;var c=t-i.site[0],l=n-i.site[1],f=c*c+l*l;do{i=o.cells[r=u],u=null,i.halfedges.forEach(function(e){var r=o.edges[e],a=r.left;if(a!==i.site&&a||(a=r.right)){var c=t-a[0],l=n-a[1],s=c*c+l*l;s=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),HR.hasOwnProperty(n)?{space:HR[n],local:t}:t};var $R=function(t){var n=YR(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===BR&&n.documentElement.namespaceURI===BR?n.createElement(t):n.createElementNS(e,t)}})(n)};function VR(){}var WR=function(t){return null==t?VR:function(){return this.querySelector(t)}};function XR(){return[]}var GR=function(t){return null==t?XR:function(){return this.querySelectorAll(t)}},QR=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var ZR=document.documentElement;if(!ZR.matches){var KR=ZR.webkitMatchesSelector||ZR.msMatchesSelector||ZR.mozMatchesSelector||ZR.oMatchesSelector;QR=function(t){return function(){return KR.call(this,t)}}}}var JR=QR,tD=function(t){return new Array(t.length)};function nD(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}nD.prototype={constructor:nD,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var eD="$";function rD(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var uD=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function aD(t,n){return t.style.getPropertyValue(n)||uD(t).getComputedStyle(t,null).getPropertyValue(n)}function cD(t){return t.trim().split(/^|\s+/)}function lD(t){return t.classList||new fD(t)}function fD(t){this._node=t,this._names=cD(t.getAttribute("class")||"")}function sD(t,n){for(var e=lD(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function dD(){this.textContent=""}function pD(){this.innerHTML=""}function vD(){this.nextSibling&&this.parentNode.appendChild(this)}function gD(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function yD(){return null}function mD(){var t=this.parentNode;t&&t.removeChild(this)}function _D(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function bD(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var wD={},xD=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(wD={mouseenter:"mouseover",mouseleave:"mouseout"}));function ED(t,n,e){return t=MD(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function MD(t,n,e){return function(r){var i=xD;xD=r;try{t.call(this,this.__data__,n,e)}finally{xD=i}}}function kD(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=oD);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):aD(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=cD(t+"");if(arguments.length<2){for(var r=lD(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?ND:kD,null==e&&(e=!1),r=0;r>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=XD.exec(t))?rL(parseInt(n[1],16)):(n=GD.exec(t))?new aL(n[1],n[2],n[3],1):(n=QD.exec(t))?new aL(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=ZD.exec(t))?iL(n[1],n[2],n[3],n[4]):(n=KD.exec(t))?iL(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=JD.exec(t))?lL(n[1],n[2]/100,n[3]/100,1):(n=tL.exec(t))?lL(n[1],n[2]/100,n[3]/100,n[4]):nL.hasOwnProperty(t)?rL(nL[t]):"transparent"===t?new aL(NaN,NaN,NaN,0):null}function rL(t){return new aL(t>>16&255,t>>8&255,255&t,1)}function iL(t,n,e,r){return r<=0&&(t=n=e=NaN),new aL(t,n,e,r)}function oL(t){return t instanceof VD||(t=eL(t)),t?new aL((t=t.rgb()).r,t.g,t.b,t.opacity):new aL}function uL(t,n,e,r){return 1===arguments.length?oL(t):new aL(t,n,e,null==r?1:r)}function aL(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function cL(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function lL(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new sL(t,n,e,r)}function fL(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof sL)return new sL(t.h,t.s,t.l,t.opacity);if(t instanceof VD||(t=eL(t)),!t)return new sL;if(t instanceof sL)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new sL(u,a,c,t.opacity)}(t):new sL(t,n,e,null==r?1:r)}function sL(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function hL(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}YD(VD,eL,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),YD(aL,uL,$D(VD,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new aL(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new aL(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+cL(this.r)+cL(this.g)+cL(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),YD(sL,fL,$D(VD,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new sL(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new sL(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new aL(hL(t>=240?t-240:t+120,i,r),hL(t,i,r),hL(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var dL=Math.PI/180,pL=180/Math.PI,vL=.96422,gL=1,yL=.82521,mL=4/29,_L=6/29,bL=3*_L*_L,wL=_L*_L*_L;function xL(t){if(t instanceof ML)return new ML(t.l,t.a,t.b,t.opacity);if(t instanceof PL){if(isNaN(t.h))return new ML(t.l,0,0,t.opacity);var n=t.h*dL;return new ML(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof aL||(t=oL(t));var e,r,i=TL(t.r),o=TL(t.g),u=TL(t.b),a=kL((.2225045*i+.7168786*o+.0606169*u)/gL);return i===o&&o===u?e=r=a:(e=kL((.4360747*i+.3850649*o+.1430804*u)/vL),r=kL((.0139322*i+.0971045*o+.7141733*u)/yL)),new ML(116*a-16,500*(e-a),200*(a-r),t.opacity)}function EL(t,n,e,r){return 1===arguments.length?xL(t):new ML(t,n,e,null==r?1:r)}function ML(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function kL(t){return t>wL?Math.pow(t,1/3):t/bL+mL}function NL(t){return t>_L?t*t*t:bL*(t-mL)}function SL(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function TL(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function CL(t){if(t instanceof PL)return new PL(t.h,t.c,t.l,t.opacity);if(t instanceof ML||(t=xL(t)),0===t.a&&0===t.b)return new PL(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*pL;return new PL(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function AL(t,n,e,r){return 1===arguments.length?CL(t):new PL(t,n,e,null==r?1:r)}function PL(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}YD(ML,EL,$D(VD,{brighter:function(t){return new ML(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new ML(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new aL(SL(3.1338561*(n=vL*NL(n))-1.6168667*(t=gL*NL(t))-.4906146*(e=yL*NL(e))),SL(-.9787684*n+1.9161415*t+.033454*e),SL(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),YD(PL,AL,$D(VD,{brighter:function(t){return new PL(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new PL(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return xL(this).rgb()}}));var OL=-.29227,IL=-.90649,RL=1.97294,DL=RL*IL,LL=1.78277*RL,UL=1.78277*OL- -.14861*IL;function zL(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof jL)return new jL(t.h,t.s,t.l,t.opacity);t instanceof aL||(t=oL(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(UL*r+DL*n-LL*e)/(UL+DL-LL),o=r-i,u=(RL*(e-i)-OL*o)/IL,a=Math.sqrt(u*u+o*o)/(RL*i*(1-i)),c=a?Math.atan2(u,o)*pL-120:NaN;return new jL(c<0?c+360:c,a,i,t.opacity)}(t):new jL(t,n,e,null==r?1:r)}function jL(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function FL(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}YD(jL,zL,$D(VD,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new jL(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new jL(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*dL,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new aL(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(OL*r+IL*i)),255*(n+e*(RL*r)),this.opacity)}}));var qL=function(t){return function(){return t}};function BL(t,n){return function(e){return t+e*n}}function HL(t,n){var e=n-t;return e?BL(t,e>180||e<-180?e-360*Math.round(e/360):e):qL(isNaN(t)?n:t)}function YL(t){return 1==(t=+t)?$L:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):qL(isNaN(n)?e:n)}}function $L(t,n){var e=n-t;return e?BL(t,e):qL(isNaN(t)?n:t)}var VL=function t(n){var e=YL(n);function r(t,n){var r=e((t=uL(t)).r,(n=uL(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=$L(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function WL(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:XL(e,r)})),o=QL.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:XL(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:XL(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:XL(t,e)},{i:a-2,x:XL(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e=0&&n._call.call(null,t),n=n._next;--gU}()}finally{gU=0,function(){var t,n,e=pU,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:pU=n);vU=t,PU(r)}(),wU=0}}function AU(){var t=EU.now(),n=t-bU;n>_U&&(xU-=n,bU=t)}function PU(t){gU||(yU&&(yU=clearTimeout(yU)),t-wU>24?(t<1/0&&(yU=setTimeout(CU,t-EU.now()-xU)),mU&&(mU=clearInterval(mU))):(mU||(bU=EU.now(),mU=setInterval(AU,_U)),gU=1,MU(CU)))}SU.prototype=TU.prototype={constructor:SU,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?kU():+e)+(null==n?0:+n),this._next||vU===this||(vU?vU._next=this:pU=this,vU=this),this._call=t,this._time=e,PU()},stop:function(){this._call&&(this._call=null,this._time=1/0,PU())}};var OU=function(t,n,e){var r=new SU;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},IU=qR("start","end","interrupt"),RU=[],DU=0,LU=1,UU=2,zU=3,jU=4,FU=5,qU=6,BU=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(c){var l,f,s,h;if(e.state!==LU)return a();for(l in i)if((h=i[l]).name===e.name){if(h.state===zU)return OU(o);h.state===jU?(h.state=qU,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[l]):+lDU)throw new Error("too late; already scheduled");return e}function YU(t,n){var e=$U(t,n);if(e.state>UU)throw new Error("too late; already started");return e}function $U(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}var VU=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>UU&&e.state=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?HU:YU;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}(e,t,n))},attr:function(t,n){var e=YR(t),r="transform"===e?aU:XU;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}})(e,r,WU(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}:function(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}})(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=YR(t);return this.tween(e,(r.local?function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}:function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?uU:XU;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=aD(this,t),u=(this.style.removeProperty(t),aD(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}(t,r)).on("end.style."+t,function(t){return function(){this.style.removeProperty(t)}}(t)):this.styleTween(t,"function"==typeof n?function(t,n,e){var r,i,o;return function(){var u=aD(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=aD(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}(t,r,WU(this,"style."+t,n)):function(t,n,e){var r,i;return function(){var o=aD(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(WU(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=$U(this.node(),e).tween,o=0,u=i.length;or?(r+i)/2:Math.min(0,r)||Math.max(0,i),u>o?(o+u)/2:Math.min(0,o)||Math.max(0,u))}var vz=function(){var t,n,e=lz,r=fz,i=pz,o=hz,u=dz,a=[0,1/0],c=[[-1/0,-1/0],[1/0,1/0]],l=250,f=fU,s=[],h=qR("start","zoom","end"),d=500,p=150,v=0;function g(t){t.property("__zoom",sz).on("wheel.zoom",E).on("mousedown.zoom",M).on("dblclick.zoom",k).filter(u).on("touchstart.zoom",N).on("touchmove.zoom",S).on("touchend.zoom touchcancel.zoom",T).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function y(t,n){return(n=Math.max(a[0],Math.min(a[1],n)))===t.k?t:new iz(n,t.x,t.y)}function m(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new iz(t.k,r,i)}function _(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function b(t,n,e){t.on("start.zoom",function(){w(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){w(this,arguments).end()}).tween("zoom",function(){var t=arguments,i=w(this,t),o=r.apply(this,t),u=e||_(o),a=Math.max(o[1][0]-o[0][0],o[1][1]-o[0][1]),c=this.__zoom,l="function"==typeof n?n.apply(this,t):n,s=f(c.invert(u).concat(a/c.k),l.invert(u).concat(a/l.k));return function(t){if(1===t)t=l;else{var n=s(t),e=a/n[2];t=new iz(e,u[0]-n[0]*e,u[1]-n[1]*e)}i.zoom(null,t)}})}function w(t,n){for(var e,r=0,i=s.length;rv}t.zoom("mouse",i(m(t.that.__zoom,t.mouse[0]=zD(t.that),t.mouse[1]),t.extent,c))},!0).on("mouseup.zoom",function(){r.on("mousemove.zoom mouseup.zoom",null),BD(xD.view,t.moved),cz(),t.end()},!0),o=zD(this),u=xD.clientX,a=xD.clientY;qD(xD.view),az(),t.mouse=[o,this.__zoom.invert(o)],VU(this),t.start()}}function k(){if(e.apply(this,arguments)){var t=this.__zoom,n=zD(this),o=t.invert(n),u=t.k*(xD.shiftKey?.5:2),a=i(m(y(t,u),n,o),r.apply(this,arguments),c);cz(),l>0?ID(this).transition().duration(l).call(b,a,n):ID(this).call(g.transform,a)}}function N(){if(e.apply(this,arguments)){var n,r,i,o,u=w(this,arguments),a=xD.changedTouches,c=a.length;for(az(),r=0;r3e4)&&($("#no-connection-modal").modal(),t.setState({modalShown:!0}))})}},{key:"resetTimer",value:function(){clearTimeout(this.timeoutId),this.timeoutId=setTimeout(this.refreshLoop.bind(this),1e3)}},{key:"componentDidMount",value:function(){this.refreshLoop.bind(this)()}},{key:"renderStatusLight",value:function(){return this.state.noConnection?this.state.lightShown?i.default.createElement("span",{className:"status-light status-light-red",id:"status-indicator"}):i.default.createElement("span",{className:"status-light",id:"status-indicator"}):i.default.createElement("span",{className:"status-light status-light-green",id:"status-indicator"})}},{key:"render",value:function(){var t=this.state.info;return t?i.default.createElement("div",null,i.default.createElement("nav",{className:"navbar"},i.default.createElement("div",{className:"container-fluid"},i.default.createElement("div",{className:"navbar-header"},i.default.createElement("table",null,i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",null,i.default.createElement("a",{href:"/ui/"},i.default.createElement("img",{src:"assets/logo.png"}))),i.default.createElement("td",null,i.default.createElement("span",{className:"navbar-brand"},this.props.title)))))),i.default.createElement("div",{id:"navbar",className:"navbar-collapse collapse"},i.default.createElement("ul",{className:"nav navbar-nav navbar-right"},i.default.createElement("li",null,i.default.createElement("span",{className:"navbar-cluster-info"},i.default.createElement("span",{className:"uppercase"},"Version"),i.default.createElement("br",null),i.default.createElement("span",{className:"text uppercase",id:"version-number"},t.nodeVersion.version))),i.default.createElement("li",null,i.default.createElement("span",{className:"navbar-cluster-info"},i.default.createElement("span",{className:"uppercase"},"Environment"),i.default.createElement("br",null),i.default.createElement("span",{className:"text uppercase",id:"environment"},t.environment))),i.default.createElement("li",null,i.default.createElement("span",{className:"navbar-cluster-info"},i.default.createElement("span",{className:"uppercase"},"Uptime"),i.default.createElement("br",null),i.default.createElement("span",{"data-toggle":"tooltip","data-placement":"bottom",title:"Connection status"},this.renderStatusLight())," ",i.default.createElement("span",{className:"text",id:"uptime"},t.uptime))))))),i.default.createElement("div",{id:"no-connection-modal",className:"modal",tabIndex:"-1",role:"dialog"},i.default.createElement("div",{className:"modal-dialog modal-sm",role:"document"},i.default.createElement("div",{className:"modal-content"},i.default.createElement("div",{className:"row error-message"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("br",null),i.default.createElement("h4",null,"Unable to connect to server"),i.default.createElement("p",null,this.state.errorText?"Error: "+this.state.errorText:null))))))):null}}]),n}()},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.QueryHeader=void 0;var r=function(){function t(t,n){for(var e=0;e0&&t.queryStats.runningDrivers>=0,t.queryStats.fullyBlocked,t.queryStats.blockedReasons,t.memoryPool,t.errorType,t.errorCode?t.errorCode.name:null),r=(0,o.getProgressBarPercentage)(t.queryStats.progressPercentage,t.state),u={width:r+"%",backgroundColor:n},a=(0,o.getProgressBarTitle)(t.queryStats.progressPercentage,t.state,e);return(0,o.isQueryEnded)(t.state)?i.default.createElement("div",{className:"progress-large"},i.default.createElement("div",{className:"progress-bar progress-bar-info",role:"progressbar","aria-valuenow":r,"aria-valuemin":"0","aria-valuemax":"100",style:u},a)):i.default.createElement("table",null,i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{width:"100%"},i.default.createElement("div",{className:"progress-large"},i.default.createElement("div",{className:"progress-bar progress-bar-info",role:"progressbar","aria-valuenow":r,"aria-valuemin":"0","aria-valuemax":"100",style:u},a))),i.default.createElement("td",null,i.default.createElement("a",{onClick:function(){return $.ajax({url:"/v1/query/"+t.queryId+"/preempted",type:"PUT",data:"Preempted via web UI"})},className:"btn btn-warning",target:"_blank"},"Preempt")),i.default.createElement("td",null,i.default.createElement("a",{onClick:function(){return $.ajax({url:"/v1/query/"+t.queryId+"/killed",type:"PUT",data:"Killed via web UI"})},className:"btn btn-warning",target:"_blank"},"Kill")))))}},{key:"renderTab",value:function(t,n){var e=this.props.query.queryId;return window.location.pathname.includes(t)?i.default.createElement("a",{href:t+"?"+e,className:"btn btn-info navbar-btn nav-disabled"},n):i.default.createElement("a",{href:t+"?"+e,className:"btn btn-info navbar-btn"},n)}},{key:"render",value:function(){var t=this.props.query;return i.default.createElement("div",null,i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",{className:"query-id"},i.default.createElement("span",{id:"query-id"},t.queryId),i.default.createElement("a",{className:"btn copy-button","data-clipboard-target":"#query-id","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"})))),i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("table",{className:"header-inline-links"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",null,this.renderTab("query.html","Overview")," ",this.renderTab("plan.html","Live Plan")," ",this.renderTab("stage.html","Stage Performance")," ",this.renderTab("timeline.html","Splits")," ",i.default.createElement("a",{href:"/v1/query/"+t.queryId+"?pretty",className:"btn btn-info navbar-btn",target:"_blank"},"JSON"))))))),i.default.createElement("hr",{className:"h2-hr"}),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},this.renderProgressBar())))}}]),n}()},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.filterPropsFrom=function(t){t=t||{};var n={};for(var e in t)e in r||(n[e]=t[e]);return n};var r={hideTableHeader:!0,column:!0,columns:!0,sortable:!0,filterable:!0,filtering:!0,onFilter:!0,filterPlaceholder:!0,filterClassName:!0,currentFilter:!0,sort:!0,sortBy:!0,sortableColumns:!0,onSort:!0,defaultSort:!0,defaultSortDescending:!0,itemsPerPage:!0,filterBy:!0,hideFilterInput:!0,noDataText:!0,currentPage:!0,onPageChange:!0,previousPageLabel:!0,nextPageLabel:!0,pageButtonLimit:!0,childNode:!0,data:!0,children:!0}},,,,,,function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function t(t,n){for(var e=0;e0&&(i+=" "+o),"object"==typeof e.props&&"string"==typeof e.props.className&&(i+=" "+e.props.className),t.push(u.default.createElement(a.Th,r({},e.props,{className:i,key:n,onClick:this.handleClickTh.bind(this,e),onKeyDown:this.handleKeyDownTh.bind(this,e),role:f,tabIndex:"0"}),e.label))}var s=(0,l.filterPropsFrom)(this.props);return u.default.createElement("thead",s,!0===this.props.filtering?u.default.createElement(c.Filterer,{colSpan:this.props.columns.length,onFilter:this.props.onFilter,placeholder:this.props.filterPlaceholder,value:this.props.currentFilter,className:this.props.filterClassName}):null,u.default.createElement("tr",{className:"reactable-column-header"},t))}}],[{key:"getColumns",value:function(t){var n=[];return u.default.Children.forEach(t.props.children,function(t){var e={};if(t){if(void 0!==t.props&&(e.props=(0,l.filterPropsFrom)(t.props),void 0!==t.props.children&&(e.label=t.props.children,e.key=e.label),"string"==typeof t.props.column&&(e.key=t.props.column,void 0===e.label&&(e.label=e.key))),void 0===e.key)throw new TypeError(' must have either a "column" property or a string child');n.push(e)}}),n}}]),n}();n.Thead=f},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=Object.assign||function(t){for(var n=1;n=0||Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e}(t,["props"]);if(this.props.data.hasOwnProperty(o.key)){var c=this.props.data[o.key];return void 0!==c&&null!==c&&!0===c.__reactableMeta&&(i=c.props,c=c.value),u.default.createElement(a.Td,r({column:o,key:o.key},i),c)}return u.default.createElement(a.Td,{column:o,key:o.key})}.bind(this))));var n=(0,l.filterPropsFrom)(this.props);return u.default.createElement("tr",n,t)}}]),n}();n.Tr=f,f.childNode=a.Td,f.dataType="object"},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=Object.assign||function(t){for(var n=1;ni.length)return 1;for(var o=0;oa?1:-1}return 0}},{key:"showPortNumbers",value:function(t){for(var n={},e=0;e=1e3){var o=Date.now(),a=(0,u.getStageNumber)(t.stageId);if(n.renderHistogram("#scheduled-time-histogram-"+a,r,u.formatDuration),n.renderHistogram("#cpu-time-histogram-"+a,i,u.formatDuration),this.state.expanded){for(var c={offset:{}},l=0;l=0){var s=((0,u.parseDuration)(t.queryStats.totalScheduledTime)-r)/(1e3*f),h=((0,u.parseDuration)(t.queryStats.totalCpuTime)-i)/(1e3*f),d=(t.queryStats.processedInputPositions-o)/f,p=((0,u.parseDataSize)(t.queryStats.processedInputDataSize)-a)/f;this.setState({scheduledTimeRate:(0,u.addToHistory)(s,this.state.scheduledTimeRate),cpuTimeRate:(0,u.addToHistory)(h,this.state.cpuTimeRate),rowInputRate:(0,u.addToHistory)(d,this.state.rowInputRate),byteInputRate:(0,u.addToHistory)(p,this.state.byteInputRate),reservedMemory:(0,u.addToHistory)((0,u.parseDataSize)(t.queryStats.userMemoryReservation),this.state.reservedMemory)})}this.resetTimer()}}.bind(this)).error(function(){t.setState({initialized:!0}),t.resetTimer()})}},{key:"handleStageRefreshClick",value:function(){this.state.stageRefresh?this.setState({stageRefresh:!1,lastSnapshotStages:this.state.query.outputStage}):this.setState({stageRefresh:!0})}},{key:"renderStageRefreshButton",value:function(){return this.state.stageRefresh?i.default.createElement("button",{className:"btn btn-info live-button",onClick:this.handleStageRefreshClick.bind(this)},"Auto-Refresh: On"):i.default.createElement("button",{className:"btn btn-info live-button",onClick:this.handleStageRefreshClick.bind(this)},"Auto-Refresh: Off")}},{key:"componentDidMount",value:function(){this.refreshLoop()}},{key:"componentDidUpdate",value:function(){if(null===this.state.lastRender||Date.now()-this.state.lastRender>=1e3){var t=Date.now();$("#scheduled-time-rate-sparkline").sparkline(this.state.scheduledTimeRate,$.extend({},x,{chartRangeMin:0,numberFormatter:u.precisionRound})),$("#cpu-time-rate-sparkline").sparkline(this.state.cpuTimeRate,$.extend({},x,{chartRangeMin:0,numberFormatter:u.precisionRound})),$("#row-input-rate-sparkline").sparkline(this.state.rowInputRate,$.extend({},x,{numberFormatter:u.formatCount})),$("#byte-input-rate-sparkline").sparkline(this.state.byteInputRate,$.extend({},x,{numberFormatter:u.formatDataSize})),$("#reserved-memory-sparkline").sparkline(this.state.reservedMemory,$.extend({},x,{numberFormatter:u.formatDataSize})),null===this.state.lastRender&&($("#query").each(function(t,n){hljs.highlightBlock(n)}),$("#prepared-query").each(function(t,n){hljs.highlightBlock(n)})),this.setState({lastRender:t})}$('[data-toggle="tooltip"]').tooltip(),new Clipboard(".copy-button")}},{key:"renderStages",value:function(){if(null!==this.state.lastSnapshotStage)return i.default.createElement("div",null,i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-9"},i.default.createElement("h3",null,"Stages")),i.default.createElement("div",{className:"col-xs-3"},i.default.createElement("table",{className:"header-inline-links"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",null,this.renderStageRefreshButton())))))),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement(w,{key:this.state.query.queryId,outputStage:this.state.lastSnapshotStage}))))}},{key:"renderPreparedQuery",value:function(){var t=this.state.query;if(t.hasOwnProperty("preparedQuery")&&null!==t.preparedQuery)return i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h3",null,"Prepared Query",i.default.createElement("a",{className:"btn copy-button","data-clipboard-target":"#prepared-query-text","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"}))),i.default.createElement("pre",{id:"prepared-query"},i.default.createElement("code",{className:"lang-sql",id:"prepared-query-text"},t.preparedQuery)))}},{key:"renderSessionProperties",value:function(){var t=this.state.query,n=[];for(var e in t.session.systemProperties)t.session.systemProperties.hasOwnProperty(e)&&n.push(i.default.createElement("span",null,"- ",e+"="+t.session.systemProperties[e]," ",i.default.createElement("br",null)));for(var r in t.session.catalogProperties)if(t.session.catalogProperties.hasOwnProperty(r))for(var o in t.session.catalogProperties[r])t.session.catalogProperties[r].hasOwnProperty(o)&&n.push(i.default.createElement("span",null,"- ",r+"."+o+"="+t.session.catalogProperties[r][o]," ",i.default.createElement("br",null)));return n}},{key:"renderResourceEstimates",value:function(){var t=this.state.query,n=t.session.resourceEstimates,e=[];for(var r in n)if(n.hasOwnProperty(r)){for(var o=r.match(/([A-Z])/g)||[],u=r,a=0,c=o.length;a0?i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h3",null,"Warnings"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table",id:"warnings-table"},t.warnings.map(function(t){return i.default.createElement("tr",null,i.default.createElement("td",null,t.warningCode.name),i.default.createElement("td",null,t.message))})))):null}},{key:"renderMetricValue",value:function(t,n){return t.includes("Nanos")?(0,u.formatDuration)((0,u.parseDuration)(n+"ns")):(0,u.formatCount)(n)}},{key:"renderRuntimeStats",value:function(){var t=this,n=this.state.query;return 0==Object.values(n.queryStats.runtimeStats).length?null:i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"RuntimeStats"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table",id:"runtime-stats-table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("th",{className:"info-text"},"Metric Name"),i.default.createElement("th",{className:"info-text"},"Sum"),i.default.createElement("th",{className:"info-text"},"Count"),i.default.createElement("th",{className:"info-text"},"Min"),i.default.createElement("th",{className:"info-text"},"Max")),Object.values(n.queryStats.runtimeStats).sort(function(t,n){return t.name.localeCompare(n.name)}).map(function(n){return i.default.createElement("tr",null,i.default.createElement("td",{className:"info-text"},n.name),i.default.createElement("td",{className:"info-text"},t.renderMetricValue(n.name,n.sum)),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(n.count)),i.default.createElement("td",{className:"info-text"},t.renderMetricValue(n.name,n.min)),i.default.createElement("td",{className:"info-text"},t.renderMetricValue(n.name,n.max)))})))))}},{key:"renderFailureInfo",value:function(){var t=this.state.query;return t.failureInfo?i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h3",null,"Error Information"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Error Type"),i.default.createElement("td",{className:"info-text"},t.errorType)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Error Code"),i.default.createElement("td",{className:"info-text"},t.errorCode.name+" ("+this.state.query.errorCode.code+")")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Stack Trace",i.default.createElement("a",{className:"btn copy-button","data-clipboard-target":"#stack-trace","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"}))),i.default.createElement("td",{className:"info-text"},i.default.createElement("pre",{id:"stack-trace"},n.formatStackTrace(t.failureInfo)))))))):""}},{key:"render",value:function(){var t=this.state.query;if(null===t||!1===this.state.initialized){var n=i.default.createElement("div",{className:"loader"},"Loading...");return this.state.initialized&&(n="Query not found"),i.default.createElement("div",{className:"row error-message"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h4",null,n)))}return i.default.createElement("div",null,i.default.createElement(a.QueryHeader,{query:t}),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"Session"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"User"),i.default.createElement("td",{className:"info-text wrap-text"},i.default.createElement("span",{id:"query-user"},t.session.user),"  ",i.default.createElement("a",{href:"#",className:"copy-button","data-clipboard-target":"#query-user","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"})))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Principal"),i.default.createElement("td",{className:"info-text wrap-text"},t.session.principal)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Source"),i.default.createElement("td",{className:"info-text wrap-text"},t.session.source)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Catalog"),i.default.createElement("td",{className:"info-text"},t.session.catalog)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Schema"),i.default.createElement("td",{className:"info-text"},t.session.schema)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Client Address"),i.default.createElement("td",{className:"info-text"},t.session.remoteUserAddress)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Client Tags"),i.default.createElement("td",{className:"info-text"},t.session.clientTags.join(", "))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Session Properties"),i.default.createElement("td",{className:"info-text wrap-text"},this.renderSessionProperties())),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Resource Estimates"),i.default.createElement("td",{className:"info-text wrap-text"},this.renderResourceEstimates()))))),i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"Execution"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Resource Group"),i.default.createElement("td",{className:"info-text wrap-text"},t.resourceGroupId?t.resourceGroupId.join("."):"n/a")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Submission Time"),i.default.createElement("td",{className:"info-text"},(0,u.formatShortDateTime)(new Date(t.queryStats.createTime)))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Completion Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.endTime?(0,u.formatShortDateTime)(new Date(t.queryStats.endTime)):"")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Elapsed Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.elapsedTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Prerequisites Wait Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.waitingForPrerequisitesTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Queued Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.queuedTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Planning Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.totalPlanningTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Execution Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.executionTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Coordinator"),i.default.createElement("td",{className:"info-text"},(0,u.getHostname)(t.self))))))),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"Resource Utilization Summary"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"CPU Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.totalCpuTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Scheduled Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.totalScheduledTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Blocked Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.totalBlockedTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Input Rows"),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(t.queryStats.processedInputPositions))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Input Data"),i.default.createElement("td",{className:"info-text"},t.queryStats.processedInputDataSize)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Raw Input Rows"),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(t.queryStats.rawInputPositions))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Raw Input Data"),i.default.createElement("td",{className:"info-text"},t.queryStats.rawInputDataSize)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Peak User Memory"),i.default.createElement("td",{className:"info-text"},t.queryStats.peakUserMemoryReservation)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Peak Total Memory"),i.default.createElement("td",{className:"info-text"},t.queryStats.peakTotalMemoryReservation)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Memory Pool"),i.default.createElement("td",{className:"info-text"},t.memoryPool)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Cumulative User Memory"),i.default.createElement("td",{className:"info-text"},(0,u.formatDataSizeBytes)(t.queryStats.cumulativeUserMemory/1e3)+" seconds")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Cumulative Total"),i.default.createElement("td",{className:"info-text"},(0,u.formatDataSizeBytes)(t.queryStats.cumulativeTotalMemory/1e3)+" seconds")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Output Rows"),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(t.queryStats.outputPositions))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Output Data"),i.default.createElement("td",{className:"info-text"},t.queryStats.outputDataSize)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Written Output Rows"),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(t.queryStats.writtenOutputPositions))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Written Output Logical Data Size"),i.default.createElement("td",{className:"info-text"},t.queryStats.writtenOutputLogicalDataSize)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Written Output Physical Data Size"),i.default.createElement("td",{className:"info-text"},t.queryStats.writtenOutputPhysicalDataSize)),(0,u.parseDataSize)(t.queryStats.spilledDataSize)>0&&i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Spilled Data"),i.default.createElement("td",{className:"info-text"},t.queryStats.spilledDataSize))))),i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"Timeline"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Parallelism"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"cpu-time-rate-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatCount)(this.state.cpuTimeRate[this.state.cpuTimeRate.length-1]))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Scheduled Time/s"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"scheduled-time-rate-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatCount)(this.state.scheduledTimeRate[this.state.scheduledTimeRate.length-1]))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Input Rows/s"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"row-input-rate-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatCount)(this.state.rowInputRate[this.state.rowInputRate.length-1]))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Input Bytes/s"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"byte-input-rate-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatDataSize)(this.state.byteInputRate[this.state.byteInputRate.length-1]))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Memory Utilization"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"reserved-memory-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatDataSize)(this.state.reservedMemory[this.state.reservedMemory.length-1]))))))))),this.renderRuntimeStats(),this.renderWarningInfo(),this.renderFailureInfo(),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h3",null,"Query",i.default.createElement("a",{className:"btn copy-button","data-clipboard-target":"#query-text","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"}))),i.default.createElement("pre",{id:"query"},i.default.createElement("code",{className:"lang-sql",id:"query-text"},t.query))),this.renderPreparedQuery()),this.renderStages())}}],[{key:"formatStackTrace",value:function(t){return n.formatStackTraceHelper(t,[],"","")}},{key:"formatStackTraceHelper",value:function(t,e,r,i){var o=i+r+n.failureInfoToString(t)+"\n";if(t.stack){var u=0;null!==e&&(u=n.countSharedStackFrames(t.stack,e));for(var a=0;a>>0,i=arguments[1],o=0;o, but more than one was specified.Ignoring all but the last one"),e=t;break;case s.Tr:var r=t.props.data||{};u.default.Children.forEach(t.props.children,function(t){if("object"==typeof t&&null!=t)if(void 0!==t.props.column){var n=void 0;if(void 0!==t.props.data)n=t.props.data;else{if(void 0===t.props.children)return void console.warn("exports.Td specified without a `data` property or children, ignoring");n=t.props.children}r[t.props.column]={value:n,props:(0,a.filterPropsFrom)(t.props),__reactableMeta:!0}}else console.warn("exports.Td specified without a `column` property, ignoring")}),n.push({data:r,props:(0,a.filterPropsFrom)(t.props),__reactableMeta:!0});break;default:console.warn("The only possible children of are , , or one .")}}.bind(this)),{data:n,tfoot:e}}},{key:"initialize",value:function(t){this.data=t.data||[];var n=this.parseChildData(t),e=n.data,r=n.tfoot;this.data=this.data.concat(e),this.tfoot=r,this.initializeSorts(t),this.initializeFilters(t)}},{key:"initializeFilters",value:function(t){for(var n in this._filterable={},t.filterable){var e=t.filterable[n],r=void 0,i=void 0;if(e instanceof Object){if(void 0===e.column){console.warn("Filterable column specified without column name");continue}r=e.column,i="function"==typeof e.filterFunction?e.filterFunction:"default"}else r=e,i="default";this._filterable[r]=i}}},{key:"initializeSorts",value:function(t){for(var n in this._sortable={},t.sortable){var e=t.sortable[n],r=void 0,i=void 0;if(e instanceof Object){if(void 0===e.column)return void console.warn("Sortable column specified without column name");r=e.column,i="function"==typeof e.sortFunction?e.sortFunction:"default"}else r=e,i="default";this._sortable[r]=i}}},{key:"getCurrentSort",value:function(t){var n=void 0,e=void 0;if(t instanceof Object){if(void 0===t.column)return void console.warn("Default column specified without column name");if(n=t.column,void 0!==t.direction)if(1===t.direction||"asc"===t.direction)e=1;else if(-1===t.direction||"desc"===t.direction)e=-1;else{var r=this.props.defaultSortDescending?"descending":"ascending";console.warn("Invalid default sort specified. Defaulting to "+r),e=this.props.defaultSortDescending?-1:1}else e=this.props.defaultSortDescending?-1:1}else n=t,e=this.props.defaultSortDescending?-1:1;return{column:n,direction:e}}},{key:"updateCurrentSort",value:function(t){!1!==t&&t.column!==this.state.currentSort.column&&t.direction!==this.state.currentSort.direction&&this.setState({currentSort:this.getCurrentSort(t)})}},{key:"updateCurrentPage",value:function(t){void 0!==t&&t!==this.state.currentPage&&this.setState({currentPage:t})}},{key:"componentWillMount",value:function(){this.initialize(this.props),this.sortByCurrentSort(),this.filterBy(this.props.filterBy)}},{key:"componentWillReceiveProps",value:function(t){this.initialize(t),this.updateCurrentPage(t.currentPage),this.updateCurrentSort(t.sortBy),this.sortByCurrentSort(),this.filterBy(t.filterBy)}},{key:"applyFilter",value:function(t,n){t=t.toLowerCase();for(var e=[],r=0;r-1){e.push(n[r]);break}}else if(this._filterable[o]((0,c.extractDataFrom)(i,o).toString(),t)){e.push(n[r]);break}}return e}},{key:"sortByCurrentSort",value:function(){var t=this.state.currentSort;null!==t.column&&this.data.sort(function(n,e){var r=(0,c.extractDataFrom)(n,t.column);r=(0,l.isUnsafe)(r)?r.toString():r||"";var i=(0,c.extractDataFrom)(e,t.column);return i=(0,l.isUnsafe)(i)?i.toString():i||"",void 0===this._sortable[t.column]||"default"===this._sortable[t.column]?ri?1*t.direction:0:1===t.direction?this._sortable[t.column](r,i):this._sortable[t.column](i,r)}.bind(this))}},{key:"onSort",value:function(t){if(void 0!==this._sortable[t]){var n=this.state.currentSort;n.column===t?n.direction*=-1:(n.column=t,n.direction=this.props.defaultSortDescending?-1:1),this.setState({currentSort:n}),this.sortByCurrentSort(),"function"==typeof this.props.onSort&&this.props.onSort(n)}}},{key:"render",value:function(){var t=this,n=[],e=void 0,i=!1,o=void 0===this.props.hideTableHeader,c=null;if(this.props.children&&(this.props.children.length>0&&this.props.children[0]&&this.props.children[0].type===f.Thead?c=this.props.children[0]:this.props.children.type===f.Thead&&(c=this.props.children)),(e=null!==c?f.Thead.getColumns(c):this.props.columns||[]).length>0&&(i=!0,e=this.translateColumnsArray(e)),this.data&&"function"==typeof this.data.map&&(n=n.concat(this.data.map(function(t,n){var o=t,a={};for(var c in!0===t.__reactableMeta&&(o=t.data,a=t.props),o)o.hasOwnProperty(c)&&!1===i&&function(){var t={key:c,label:c};void 0===e.find(function(n){return n.key===t.key})&&e.push(t)}();return u.default.createElement(s.Tr,r({columns:e,key:n,data:o},a))}.bind(this)))),!0===this.props.sortable)for(var l=0;l0&&!this.props.hideFilterInput&&(h=!0);var p=n;""!==this.state.filter&&(p=this.applyFilter(this.state.filter,p));var v=0,g=!1,y=void 0,m=this.state.currentPage,_=this.props.pageButtonLimit||10,b=p;this.props.itemsPerPage>0&&(v=this.props.itemsPerPage,m>(y=Math.ceil(p.length/v))-1&&(m=y-1),g=!0,b=p.slice(m*v,(m+1)*v));var w=(0,a.filterPropsFrom)(this.props),x=this.props.noDataText?u.default.createElement("tr",{className:"reactable-no-data"},u.default.createElement("td",{colSpan:e.length},this.props.noDataText)):null,E=null;return e&&e.length>0&&o&&(E=u.default.createElement(f.Thead,{columns:e,filtering:h,onFilter:function(n){t.setState({filter:n}),t.props.onFilter&&t.props.onFilter(n)},filterPlaceholder:this.props.filterPlaceholder,filterClassName:this.props.filterClassName,currentFilter:this.state.filter,sort:this.state.currentSort,sortableColumns:this._sortable,onSort:this.onSort.bind(this),key:"thead"})),u.default.createElement("table",w,E,u.default.createElement("tbody",{className:"reactable-data",key:"tbody"},b.length>0?b:x),!0===g?u.default.createElement(d.Paginator,{colSpan:e.length,pageButtonLimit:_,numPages:y,currentPage:m,onPageChange:function(n){t.setState({currentPage:n}),t.props.onPageChange&&t.props.onPageChange(n)},previousPageLabel:this.props.previousPageLabel,nextPageLabel:this.props.nextPageLabel,key:"paginator"}):null,this.tfoot)}}]),n}();n.Table=p,p.defaultProps={sortBy:!1,defaultSort:!1,defaultSortDescending:!1,itemsPerPage:0,filterBy:"",hideFilterInput:!1}},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.extractDataFrom=function(t,n){var e;e=void 0!==t&&null!==t&&!0===t.__reactableMeta?t.data[n]:t[n];void 0!==e&&null!==e&&!0===e.__reactableMeta&&(e=void 0!==e.props.value&&null!==e.props.value?e.props.value:e.value);return(0,r.stringable)(e)?e:""};var r=e(113)},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function t(t,n){for(var e=0;e0)return o.default.createElement("a",{className:"reactable-previous-page",href:u(this.props.currentPage-1),onClick:this.handlePrevious.bind(this)},this.props.previousPageLabel||"Previous")}},{key:"renderNext",value:function(){if(this.props.currentPage0&&(e>r-i?t.splice(0,r-n):t.splice(0,e-n+i)),r-e>u&&t.splice(n,t.length-n),o.default.createElement("tbody",{className:"reactable-pagination"},o.default.createElement("tr",null,o.default.createElement("td",{colSpan:this.props.colSpan},this.renderPrevious(),t,this.renderNext())))}}]),n}();n.Paginator=a},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r={Numeric:function(t,n){var e=parseFloat(t.toString().replace(/,/g,"")),r=parseFloat(n.toString().replace(/,/g,""));if(isNaN(e)&&isNaN(r))e=t,r=n;else{if(isNaN(e))return 1;if(isNaN(r))return-1}return er?1:0},NumericInteger:function(t,n){return isNaN(t)||isNaN(n)?t>n?1:-1:t-n},Currency:function(t,e){return t=t.replace(/[^0-9\.\-\,]+/g,""),e=e.replace(/[^0-9\.\-\,]+/g,""),n.Sort.Numeric(t,e)},Date:function(t){function n(n,e){return t.apply(this,arguments)}return n.toString=function(){return t.toString()},n}(function(t,e){var r=Date.parse(t),i=Date.parse(e);return isNaN(r)||isNaN(i)?n.Sort.Numeric(t,e):r>i?1:i>r?-1:0}),CaseInsensitive:function(t,n){return t.toLowerCase().localeCompare(n.toLowerCase())}};n.Sort=r}]); \ No newline at end of file + */(function(){var o,u=200,a="Unsupported core-js use. Try https://npms.io/search?q=ponyfill.",c="Expected a function",l="__lodash_hash_undefined__",f=500,s="__lodash_placeholder__",h=1,d=2,p=4,v=1,g=2,y=1,m=2,_=4,b=8,w=16,x=32,E=64,M=128,k=256,N=512,S=30,T="...",C=800,A=16,P=1,O=2,I=1/0,R=9007199254740991,D=1.7976931348623157e308,L=NaN,U=4294967295,z=U-1,j=U>>>1,F=[["ary",M],["bind",y],["bindKey",m],["curry",b],["curryRight",w],["flip",N],["partial",x],["partialRight",E],["rearg",k]],q="[object Arguments]",B="[object Array]",H="[object AsyncFunction]",Y="[object Boolean]",$="[object Date]",V="[object DOMException]",W="[object Error]",X="[object Function]",G="[object GeneratorFunction]",Q="[object Map]",Z="[object Number]",K="[object Null]",J="[object Object]",tt="[object Proxy]",nt="[object RegExp]",et="[object Set]",rt="[object String]",it="[object Symbol]",ot="[object Undefined]",ut="[object WeakMap]",at="[object WeakSet]",ct="[object ArrayBuffer]",lt="[object DataView]",ft="[object Float32Array]",st="[object Float64Array]",ht="[object Int8Array]",dt="[object Int16Array]",pt="[object Int32Array]",vt="[object Uint8Array]",gt="[object Uint8ClampedArray]",yt="[object Uint16Array]",mt="[object Uint32Array]",_t=/\b__p \+= '';/g,bt=/\b(__p \+=) '' \+/g,wt=/(__e\(.*?\)|\b__t\)) \+\n'';/g,xt=/&(?:amp|lt|gt|quot|#39);/g,Et=/[&<>"']/g,Mt=RegExp(xt.source),kt=RegExp(Et.source),Nt=/<%-([\s\S]+?)%>/g,St=/<%([\s\S]+?)%>/g,Tt=/<%=([\s\S]+?)%>/g,Ct=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,At=/^\w*$/,Pt=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Ot=/[\\^$.*+?()[\]{}|]/g,It=RegExp(Ot.source),Rt=/^\s+|\s+$/g,Dt=/^\s+/,Lt=/\s+$/,Ut=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,zt=/\{\n\/\* \[wrapped with (.+)\] \*/,jt=/,? & /,Ft=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,qt=/\\(\\)?/g,Bt=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,Ht=/\w*$/,Yt=/^[-+]0x[0-9a-f]+$/i,$t=/^0b[01]+$/i,Vt=/^\[object .+?Constructor\]$/,Wt=/^0o[0-7]+$/i,Xt=/^(?:0|[1-9]\d*)$/,Gt=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,Qt=/($^)/,Zt=/['\n\r\u2028\u2029\\]/g,Kt="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",Jt="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",tn="[\\ud800-\\udfff]",nn="["+Jt+"]",en="["+Kt+"]",rn="\\d+",on="[\\u2700-\\u27bf]",un="[a-z\\xdf-\\xf6\\xf8-\\xff]",an="[^\\ud800-\\udfff"+Jt+rn+"\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde]",cn="\\ud83c[\\udffb-\\udfff]",ln="[^\\ud800-\\udfff]",fn="(?:\\ud83c[\\udde6-\\uddff]){2}",sn="[\\ud800-\\udbff][\\udc00-\\udfff]",hn="[A-Z\\xc0-\\xd6\\xd8-\\xde]",dn="(?:"+un+"|"+an+")",pn="(?:"+hn+"|"+an+")",vn="(?:"+en+"|"+cn+")"+"?",gn="[\\ufe0e\\ufe0f]?"+vn+("(?:\\u200d(?:"+[ln,fn,sn].join("|")+")[\\ufe0e\\ufe0f]?"+vn+")*"),yn="(?:"+[on,fn,sn].join("|")+")"+gn,mn="(?:"+[ln+en+"?",en,fn,sn,tn].join("|")+")",_n=RegExp("['’]","g"),bn=RegExp(en,"g"),wn=RegExp(cn+"(?="+cn+")|"+mn+gn,"g"),xn=RegExp([hn+"?"+un+"+(?:['’](?:d|ll|m|re|s|t|ve))?(?="+[nn,hn,"$"].join("|")+")",pn+"+(?:['’](?:D|LL|M|RE|S|T|VE))?(?="+[nn,hn+dn,"$"].join("|")+")",hn+"?"+dn+"+(?:['’](?:d|ll|m|re|s|t|ve))?",hn+"+(?:['’](?:D|LL|M|RE|S|T|VE))?","\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",rn,yn].join("|"),"g"),En=RegExp("[\\u200d\\ud800-\\udfff"+Kt+"\\ufe0e\\ufe0f]"),Mn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,kn=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Nn=-1,Sn={};Sn[ft]=Sn[st]=Sn[ht]=Sn[dt]=Sn[pt]=Sn[vt]=Sn[gt]=Sn[yt]=Sn[mt]=!0,Sn[q]=Sn[B]=Sn[ct]=Sn[Y]=Sn[lt]=Sn[$]=Sn[W]=Sn[X]=Sn[Q]=Sn[Z]=Sn[J]=Sn[nt]=Sn[et]=Sn[rt]=Sn[ut]=!1;var Tn={};Tn[q]=Tn[B]=Tn[ct]=Tn[lt]=Tn[Y]=Tn[$]=Tn[ft]=Tn[st]=Tn[ht]=Tn[dt]=Tn[pt]=Tn[Q]=Tn[Z]=Tn[J]=Tn[nt]=Tn[et]=Tn[rt]=Tn[it]=Tn[vt]=Tn[gt]=Tn[yt]=Tn[mt]=!0,Tn[W]=Tn[X]=Tn[ut]=!1;var Cn={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},An=parseFloat,Pn=parseInt,On="object"==typeof t&&t&&t.Object===Object&&t,In="object"==typeof self&&self&&self.Object===Object&&self,Rn=On||In||Function("return this")(),Dn="object"==typeof n&&n&&!n.nodeType&&n,Ln=Dn&&"object"==typeof r&&r&&!r.nodeType&&r,Un=Ln&&Ln.exports===Dn,zn=Un&&On.process,jn=function(){try{var t=Ln&&Ln.require&&Ln.require("util").types;return t||zn&&zn.binding&&zn.binding("util")}catch(t){}}(),Fn=jn&&jn.isArrayBuffer,qn=jn&&jn.isDate,Bn=jn&&jn.isMap,Hn=jn&&jn.isRegExp,Yn=jn&&jn.isSet,$n=jn&&jn.isTypedArray;function Vn(t,n,e){switch(e.length){case 0:return t.call(n);case 1:return t.call(n,e[0]);case 2:return t.call(n,e[0],e[1]);case 3:return t.call(n,e[0],e[1],e[2])}return t.apply(n,e)}function Wn(t,n,e,r){for(var i=-1,o=null==t?0:t.length;++i-1}function Jn(t,n,e){for(var r=-1,i=null==t?0:t.length;++r-1;);return e}function we(t,n){for(var e=t.length;e--&&ce(n,t[e],0)>-1;);return e}var xe=de({"À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","Ç":"C","ç":"c","Ð":"D","ð":"d","È":"E","É":"E","Ê":"E","Ë":"E","è":"e","é":"e","ê":"e","ë":"e","Ì":"I","Í":"I","Î":"I","Ï":"I","ì":"i","í":"i","î":"i","ï":"i","Ñ":"N","ñ":"n","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","Ù":"U","Ú":"U","Û":"U","Ü":"U","ù":"u","ú":"u","û":"u","ü":"u","Ý":"Y","ý":"y","ÿ":"y","Æ":"Ae","æ":"ae","Þ":"Th","þ":"th","ß":"ss","Ā":"A","Ă":"A","Ą":"A","ā":"a","ă":"a","ą":"a","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","ć":"c","ĉ":"c","ċ":"c","č":"c","Ď":"D","Đ":"D","ď":"d","đ":"d","Ē":"E","Ĕ":"E","Ė":"E","Ę":"E","Ě":"E","ē":"e","ĕ":"e","ė":"e","ę":"e","ě":"e","Ĝ":"G","Ğ":"G","Ġ":"G","Ģ":"G","ĝ":"g","ğ":"g","ġ":"g","ģ":"g","Ĥ":"H","Ħ":"H","ĥ":"h","ħ":"h","Ĩ":"I","Ī":"I","Ĭ":"I","Į":"I","İ":"I","ĩ":"i","ī":"i","ĭ":"i","į":"i","ı":"i","Ĵ":"J","ĵ":"j","Ķ":"K","ķ":"k","ĸ":"k","Ĺ":"L","Ļ":"L","Ľ":"L","Ŀ":"L","Ł":"L","ĺ":"l","ļ":"l","ľ":"l","ŀ":"l","ł":"l","Ń":"N","Ņ":"N","Ň":"N","Ŋ":"N","ń":"n","ņ":"n","ň":"n","ŋ":"n","Ō":"O","Ŏ":"O","Ő":"O","ō":"o","ŏ":"o","ő":"o","Ŕ":"R","Ŗ":"R","Ř":"R","ŕ":"r","ŗ":"r","ř":"r","Ś":"S","Ŝ":"S","Ş":"S","Š":"S","ś":"s","ŝ":"s","ş":"s","š":"s","Ţ":"T","Ť":"T","Ŧ":"T","ţ":"t","ť":"t","ŧ":"t","Ũ":"U","Ū":"U","Ŭ":"U","Ů":"U","Ű":"U","Ų":"U","ũ":"u","ū":"u","ŭ":"u","ů":"u","ű":"u","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","Ż":"Z","Ž":"Z","ź":"z","ż":"z","ž":"z","IJ":"IJ","ij":"ij","Œ":"Oe","œ":"oe","ʼn":"'n","ſ":"s"}),Ee=de({"&":"&","<":"<",">":">",'"':""","'":"'"});function Me(t){return"\\"+Cn[t]}function ke(t){return En.test(t)}function Ne(t){var n=-1,e=Array(t.size);return t.forEach(function(t,r){e[++n]=[r,t]}),e}function Se(t,n){return function(e){return t(n(e))}}function Te(t,n){for(var e=-1,r=t.length,i=0,o=[];++e",""":'"',"'":"'"});var Re=function t(n){var e=(n=null==n?Rn:Re.defaults(Rn.Object(),n,Re.pick(Rn,kn))).Array,r=n.Date,i=n.Error,Kt=n.Function,Jt=n.Math,tn=n.Object,nn=n.RegExp,en=n.String,rn=n.TypeError,on=e.prototype,un=Kt.prototype,an=tn.prototype,cn=n["__core-js_shared__"],ln=un.toString,fn=an.hasOwnProperty,sn=0,hn=function(){var t=/[^.]+$/.exec(cn&&cn.keys&&cn.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""}(),dn=an.toString,pn=ln.call(tn),vn=Rn._,gn=nn("^"+ln.call(fn).replace(Ot,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),yn=Un?n.Buffer:o,mn=n.Symbol,wn=n.Uint8Array,En=yn?yn.allocUnsafe:o,Cn=Se(tn.getPrototypeOf,tn),On=tn.create,In=an.propertyIsEnumerable,Dn=on.splice,Ln=mn?mn.isConcatSpreadable:o,zn=mn?mn.iterator:o,jn=mn?mn.toStringTag:o,oe=function(){try{var t=zo(tn,"defineProperty");return t({},"",{}),t}catch(t){}}(),de=n.clearTimeout!==Rn.clearTimeout&&n.clearTimeout,De=r&&r.now!==Rn.Date.now&&r.now,Le=n.setTimeout!==Rn.setTimeout&&n.setTimeout,Ue=Jt.ceil,ze=Jt.floor,je=tn.getOwnPropertySymbols,Fe=yn?yn.isBuffer:o,qe=n.isFinite,Be=on.join,He=Se(tn.keys,tn),Ye=Jt.max,$e=Jt.min,Ve=r.now,We=n.parseInt,Xe=Jt.random,Ge=on.reverse,Qe=zo(n,"DataView"),Ze=zo(n,"Map"),Ke=zo(n,"Promise"),Je=zo(n,"Set"),tr=zo(n,"WeakMap"),nr=zo(tn,"create"),er=tr&&new tr,rr={},ir=fu(Qe),or=fu(Ze),ur=fu(Ke),ar=fu(Je),cr=fu(tr),lr=mn?mn.prototype:o,fr=lr?lr.valueOf:o,sr=lr?lr.toString:o;function hr(t){if(Sa(t)&&!ga(t)&&!(t instanceof gr)){if(t instanceof vr)return t;if(fn.call(t,"__wrapped__"))return su(t)}return new vr(t)}var dr=function(){function t(){}return function(n){if(!Na(n))return{};if(On)return On(n);t.prototype=n;var e=new t;return t.prototype=o,e}}();function pr(){}function vr(t,n){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!n,this.__index__=0,this.__values__=o}function gr(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=U,this.__views__=[]}function yr(t){var n=-1,e=null==t?0:t.length;for(this.clear();++n=n?t:n)),t}function Rr(t,n,e,r,i,u){var a,c=n&h,l=n&d,f=n&p;if(e&&(a=i?e(t,r,i,u):e(t)),a!==o)return a;if(!Na(t))return t;var s=ga(t);if(s){if(a=function(t){var n=t.length,e=new t.constructor(n);return n&&"string"==typeof t[0]&&fn.call(t,"index")&&(e.index=t.index,e.input=t.input),e}(t),!c)return no(t,a)}else{var v=qo(t),g=v==X||v==G;if(ba(t))return Gi(t,c);if(v==J||v==q||g&&!i){if(a=l||g?{}:Ho(t),!c)return l?function(t,n){return eo(t,Fo(t),n)}(t,function(t,n){return t&&eo(n,ic(n),t)}(a,t)):function(t,n){return eo(t,jo(t),n)}(t,Ar(a,t))}else{if(!Tn[v])return i?t:{};a=function(t,n,e){var r=t.constructor;switch(n){case ct:return Qi(t);case Y:case $:return new r(+t);case lt:return function(t,n){var e=n?Qi(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.byteLength)}(t,e);case ft:case st:case ht:case dt:case pt:case vt:case gt:case yt:case mt:return Zi(t,e);case Q:return new r;case Z:case rt:return new r(t);case nt:return function(t){var n=new t.constructor(t.source,Ht.exec(t));return n.lastIndex=t.lastIndex,n}(t);case et:return new r;case it:return function(t){return fr?tn(fr.call(t)):{}}(t)}}(t,v,c)}}u||(u=new wr);var y=u.get(t);if(y)return y;if(u.set(t,a),Oa(t))return t.forEach(function(r){a.add(Rr(r,n,e,r,t,u))}),a;if(Ta(t))return t.forEach(function(r,i){a.set(i,Rr(r,n,e,i,t,u))}),a;var m=s?o:(f?l?Po:Ao:l?ic:rc)(t);return Xn(m||t,function(r,i){m&&(r=t[i=r]),Sr(a,i,Rr(r,n,e,i,t,u))}),a}function Dr(t,n,e){var r=e.length;if(null==t)return!r;for(t=tn(t);r--;){var i=e[r],u=n[i],a=t[i];if(a===o&&!(i in t)||!u(a))return!1}return!0}function Lr(t,n,e){if("function"!=typeof t)throw new rn(c);return ru(function(){t.apply(o,e)},n)}function Ur(t,n,e,r){var i=-1,o=Kn,a=!0,c=t.length,l=[],f=n.length;if(!c)return l;e&&(n=te(n,ye(e))),r?(o=Jn,a=!1):n.length>=u&&(o=_e,a=!1,n=new br(n));t:for(;++i-1},mr.prototype.set=function(t,n){var e=this.__data__,r=Tr(e,t);return r<0?(++this.size,e.push([t,n])):e[r][1]=n,this},_r.prototype.clear=function(){this.size=0,this.__data__={hash:new yr,map:new(Ze||mr),string:new yr}},_r.prototype.delete=function(t){var n=Lo(this,t).delete(t);return this.size-=n?1:0,n},_r.prototype.get=function(t){return Lo(this,t).get(t)},_r.prototype.has=function(t){return Lo(this,t).has(t)},_r.prototype.set=function(t,n){var e=Lo(this,t),r=e.size;return e.set(t,n),this.size+=e.size==r?0:1,this},br.prototype.add=br.prototype.push=function(t){return this.__data__.set(t,l),this},br.prototype.has=function(t){return this.__data__.has(t)},wr.prototype.clear=function(){this.__data__=new mr,this.size=0},wr.prototype.delete=function(t){var n=this.__data__,e=n.delete(t);return this.size=n.size,e},wr.prototype.get=function(t){return this.__data__.get(t)},wr.prototype.has=function(t){return this.__data__.has(t)},wr.prototype.set=function(t,n){var e=this.__data__;if(e instanceof mr){var r=e.__data__;if(!Ze||r.length0&&e(a)?n>1?Hr(a,n-1,e,r,i):ne(i,a):r||(i[i.length]=a)}return i}var Yr=uo(),$r=uo(!0);function Vr(t,n){return t&&Yr(t,n,rc)}function Wr(t,n){return t&&$r(t,n,rc)}function Xr(t,n){return Zn(n,function(n){return Ea(t[n])})}function Gr(t,n){for(var e=0,r=(n=$i(n,t)).length;null!=t&&en}function Jr(t,n){return null!=t&&fn.call(t,n)}function ti(t,n){return null!=t&&n in tn(t)}function ni(t,n,r){for(var i=r?Jn:Kn,u=t[0].length,a=t.length,c=a,l=e(a),f=1/0,s=[];c--;){var h=t[c];c&&n&&(h=te(h,ye(n))),f=$e(h.length,f),l[c]=!r&&(n||u>=120&&h.length>=120)?new br(c&&h):o}h=t[0];var d=-1,p=l[0];t:for(;++d=a)return c;var l=e[r];return c*("desc"==l?-1:1)}}return t.index-n.index}(t,n,e)})}function yi(t,n,e){for(var r=-1,i=n.length,o={};++r-1;)a!==t&&Dn.call(a,c,1),Dn.call(t,c,1);return t}function _i(t,n){for(var e=t?n.length:0,r=e-1;e--;){var i=n[e];if(e==r||i!==o){var o=i;$o(i)?Dn.call(t,i,1):Ui(t,i)}}return t}function bi(t,n){return t+ze(Xe()*(n-t+1))}function wi(t,n){var e="";if(!t||n<1||n>R)return e;do{n%2&&(e+=t),(n=ze(n/2))&&(t+=t)}while(n);return e}function xi(t,n){return iu(Jo(t,n,Cc),t+"")}function Ei(t){return Er(hc(t))}function Mi(t,n){var e=hc(t);return au(e,Ir(n,0,e.length))}function ki(t,n,e,r){if(!Na(t))return t;for(var i=-1,u=(n=$i(n,t)).length,a=u-1,c=t;null!=c&&++io?0:o+n),(r=r>o?o:r)<0&&(r+=o),o=n>r?0:r-n>>>0,n>>>=0;for(var u=e(o);++i>>1,u=t[o];null!==u&&!Ra(u)&&(e?u<=n:u=u){var f=n?null:xo(t);if(f)return Ce(f);a=!1,i=_e,l=new br}else l=n?[]:c;t:for(;++r=r?t:Ci(t,n,e)}var Xi=de||function(t){return Rn.clearTimeout(t)};function Gi(t,n){if(n)return t.slice();var e=t.length,r=En?En(e):new t.constructor(e);return t.copy(r),r}function Qi(t){var n=new t.constructor(t.byteLength);return new wn(n).set(new wn(t)),n}function Zi(t,n){var e=n?Qi(t.buffer):t.buffer;return new t.constructor(e,t.byteOffset,t.length)}function Ki(t,n){if(t!==n){var e=t!==o,r=null===t,i=t==t,u=Ra(t),a=n!==o,c=null===n,l=n==n,f=Ra(n);if(!c&&!f&&!u&&t>n||u&&a&&l&&!c&&!f||r&&a&&l||!e&&l||!i)return 1;if(!r&&!u&&!f&&t1?e[i-1]:o,a=i>2?e[2]:o;for(u=t.length>3&&"function"==typeof u?(i--,u):o,a&&Vo(e[0],e[1],a)&&(u=i<3?o:u,i=1),n=tn(n);++r-1?i[u?n[a]:a]:o}}function so(t){return Co(function(n){var e=n.length,r=e,i=vr.prototype.thru;for(t&&n.reverse();r--;){var u=n[r];if("function"!=typeof u)throw new rn(c);if(i&&!a&&"wrapper"==Io(u))var a=new vr([],!0)}for(r=a?r:e;++r1&&b.reverse(),h&&fc))return!1;var f=u.get(t);if(f&&u.get(n))return f==n;var s=-1,h=!0,d=e&g?new br:o;for(u.set(t,n),u.set(n,t);++s-1&&t%1==0&&t1?"& ":"")+n[r],n=n.join(e>2?", ":" "),t.replace(Ut,"{\n/* [wrapped with "+n+"] */\n")}(r,function(t,n){return Xn(F,function(e){var r="_."+e[0];n&e[1]&&!Kn(t,r)&&t.push(r)}),t.sort()}(function(t){var n=t.match(zt);return n?n[1].split(jt):[]}(r),e)))}function uu(t){var n=0,e=0;return function(){var r=Ve(),i=A-(r-e);if(e=r,i>0){if(++n>=C)return arguments[0]}else n=0;return t.apply(o,arguments)}}function au(t,n){var e=-1,r=t.length,i=r-1;for(n=n===o?r:n;++e1?t[n-1]:o;return Pu(t,e="function"==typeof e?(t.pop(),e):o)});function zu(t){var n=hr(t);return n.__chain__=!0,n}function ju(t,n){return n(t)}var Fu=Co(function(t){var n=t.length,e=n?t[0]:0,r=this.__wrapped__,i=function(n){return Or(n,t)};return!(n>1||this.__actions__.length)&&r instanceof gr&&$o(e)?((r=r.slice(e,+e+(n?1:0))).__actions__.push({func:ju,args:[i],thisArg:o}),new vr(r,this.__chain__).thru(function(t){return n&&!t.length&&t.push(o),t})):this.thru(i)});var qu=ro(function(t,n,e){fn.call(t,e)?++t[e]:Pr(t,e,1)});var Bu=fo(vu),Hu=fo(gu);function Yu(t,n){return(ga(t)?Xn:zr)(t,Do(n,3))}function $u(t,n){return(ga(t)?Gn:jr)(t,Do(n,3))}var Vu=ro(function(t,n,e){fn.call(t,e)?t[e].push(n):Pr(t,e,[n])});var Wu=xi(function(t,n,r){var i=-1,o="function"==typeof n,u=ma(t)?e(t.length):[];return zr(t,function(t){u[++i]=o?Vn(n,t,r):ei(t,n,r)}),u}),Xu=ro(function(t,n,e){Pr(t,e,n)});function Gu(t,n){return(ga(t)?te:si)(t,Do(n,3))}var Qu=ro(function(t,n,e){t[e?0:1].push(n)},function(){return[[],[]]});var Zu=xi(function(t,n){if(null==t)return[];var e=n.length;return e>1&&Vo(t,n[0],n[1])?n=[]:e>2&&Vo(n[0],n[1],n[2])&&(n=[n[0]]),gi(t,Hr(n,1),[])}),Ku=De||function(){return Rn.Date.now()};function Ju(t,n,e){return n=e?o:n,n=t&&null==n?t.length:n,Mo(t,M,o,o,o,o,n)}function ta(t,n){var e;if("function"!=typeof n)throw new rn(c);return t=Fa(t),function(){return--t>0&&(e=n.apply(this,arguments)),t<=1&&(n=o),e}}var na=xi(function(t,n,e){var r=y;if(e.length){var i=Te(e,Ro(na));r|=x}return Mo(t,r,n,e,i)}),ea=xi(function(t,n,e){var r=y|m;if(e.length){var i=Te(e,Ro(ea));r|=x}return Mo(n,r,t,e,i)});function ra(t,n,e){var r,i,u,a,l,f,s=0,h=!1,d=!1,p=!0;if("function"!=typeof t)throw new rn(c);function v(n){var e=r,u=i;return r=i=o,s=n,a=t.apply(u,e)}function g(t){var e=t-f;return f===o||e>=n||e<0||d&&t-s>=u}function y(){var t=Ku();if(g(t))return m(t);l=ru(y,function(t){var e=n-(t-f);return d?$e(e,u-(t-s)):e}(t))}function m(t){return l=o,p&&r?v(t):(r=i=o,a)}function _(){var t=Ku(),e=g(t);if(r=arguments,i=this,f=t,e){if(l===o)return function(t){return s=t,l=ru(y,n),h?v(t):a}(f);if(d)return l=ru(y,n),v(f)}return l===o&&(l=ru(y,n)),a}return n=Ba(n)||0,Na(e)&&(h=!!e.leading,u=(d="maxWait"in e)?Ye(Ba(e.maxWait)||0,n):u,p="trailing"in e?!!e.trailing:p),_.cancel=function(){l!==o&&Xi(l),s=0,r=f=i=l=o},_.flush=function(){return l===o?a:m(Ku())},_}var ia=xi(function(t,n){return Lr(t,1,n)}),oa=xi(function(t,n,e){return Lr(t,Ba(n)||0,e)});function ua(t,n){if("function"!=typeof t||null!=n&&"function"!=typeof n)throw new rn(c);var e=function(){var r=arguments,i=n?n.apply(this,r):r[0],o=e.cache;if(o.has(i))return o.get(i);var u=t.apply(this,r);return e.cache=o.set(i,u)||o,u};return e.cache=new(ua.Cache||_r),e}function aa(t){if("function"!=typeof t)throw new rn(c);return function(){var n=arguments;switch(n.length){case 0:return!t.call(this);case 1:return!t.call(this,n[0]);case 2:return!t.call(this,n[0],n[1]);case 3:return!t.call(this,n[0],n[1],n[2])}return!t.apply(this,n)}}ua.Cache=_r;var ca=Vi(function(t,n){var e=(n=1==n.length&&ga(n[0])?te(n[0],ye(Do())):te(Hr(n,1),ye(Do()))).length;return xi(function(r){for(var i=-1,o=$e(r.length,e);++i=n}),va=ri(function(){return arguments}())?ri:function(t){return Sa(t)&&fn.call(t,"callee")&&!In.call(t,"callee")},ga=e.isArray,ya=Fn?ye(Fn):function(t){return Sa(t)&&Zr(t)==ct};function ma(t){return null!=t&&ka(t.length)&&!Ea(t)}function _a(t){return Sa(t)&&ma(t)}var ba=Fe||Bc,wa=qn?ye(qn):function(t){return Sa(t)&&Zr(t)==$};function xa(t){if(!Sa(t))return!1;var n=Zr(t);return n==W||n==V||"string"==typeof t.message&&"string"==typeof t.name&&!Aa(t)}function Ea(t){if(!Na(t))return!1;var n=Zr(t);return n==X||n==G||n==H||n==tt}function Ma(t){return"number"==typeof t&&t==Fa(t)}function ka(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=R}function Na(t){var n=typeof t;return null!=t&&("object"==n||"function"==n)}function Sa(t){return null!=t&&"object"==typeof t}var Ta=Bn?ye(Bn):function(t){return Sa(t)&&qo(t)==Q};function Ca(t){return"number"==typeof t||Sa(t)&&Zr(t)==Z}function Aa(t){if(!Sa(t)||Zr(t)!=J)return!1;var n=Cn(t);if(null===n)return!0;var e=fn.call(n,"constructor")&&n.constructor;return"function"==typeof e&&e instanceof e&&ln.call(e)==pn}var Pa=Hn?ye(Hn):function(t){return Sa(t)&&Zr(t)==nt};var Oa=Yn?ye(Yn):function(t){return Sa(t)&&qo(t)==et};function Ia(t){return"string"==typeof t||!ga(t)&&Sa(t)&&Zr(t)==rt}function Ra(t){return"symbol"==typeof t||Sa(t)&&Zr(t)==it}var Da=$n?ye($n):function(t){return Sa(t)&&ka(t.length)&&!!Sn[Zr(t)]};var La=_o(fi),Ua=_o(function(t,n){return t<=n});function za(t){if(!t)return[];if(ma(t))return Ia(t)?Oe(t):no(t);if(zn&&t[zn])return function(t){for(var n,e=[];!(n=t.next()).done;)e.push(n.value);return e}(t[zn]());var n=qo(t);return(n==Q?Ne:n==et?Ce:hc)(t)}function ja(t){return t?(t=Ba(t))===I||t===-I?(t<0?-1:1)*D:t==t?t:0:0===t?t:0}function Fa(t){var n=ja(t),e=n%1;return n==n?e?n-e:n:0}function qa(t){return t?Ir(Fa(t),0,U):0}function Ba(t){if("number"==typeof t)return t;if(Ra(t))return L;if(Na(t)){var n="function"==typeof t.valueOf?t.valueOf():t;t=Na(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=t.replace(Rt,"");var e=$t.test(t);return e||Wt.test(t)?Pn(t.slice(2),e?2:8):Yt.test(t)?L:+t}function Ha(t){return eo(t,ic(t))}function Ya(t){return null==t?"":Di(t)}var $a=io(function(t,n){if(Qo(n)||ma(n))eo(n,rc(n),t);else for(var e in n)fn.call(n,e)&&Sr(t,e,n[e])}),Va=io(function(t,n){eo(n,ic(n),t)}),Wa=io(function(t,n,e,r){eo(n,ic(n),t,r)}),Xa=io(function(t,n,e,r){eo(n,rc(n),t,r)}),Ga=Co(Or);var Qa=xi(function(t,n){t=tn(t);var e=-1,r=n.length,i=r>2?n[2]:o;for(i&&Vo(n[0],n[1],i)&&(r=1);++e1),n}),eo(t,Po(t),e),r&&(e=Rr(e,h|d|p,So));for(var i=n.length;i--;)Ui(e,n[i]);return e});var cc=Co(function(t,n){return null==t?{}:function(t,n){return yi(t,n,function(n,e){return Ja(t,e)})}(t,n)});function lc(t,n){if(null==t)return{};var e=te(Po(t),function(t){return[t]});return n=Do(n),yi(t,e,function(t,e){return n(t,e[0])})}var fc=Eo(rc),sc=Eo(ic);function hc(t){return null==t?[]:me(t,rc(t))}var dc=co(function(t,n,e){return n=n.toLowerCase(),t+(e?pc(n):n)});function pc(t){return xc(Ya(t).toLowerCase())}function vc(t){return(t=Ya(t))&&t.replace(Gt,xe).replace(bn,"")}var gc=co(function(t,n,e){return t+(e?"-":"")+n.toLowerCase()}),yc=co(function(t,n,e){return t+(e?" ":"")+n.toLowerCase()}),mc=ao("toLowerCase");var _c=co(function(t,n,e){return t+(e?"_":"")+n.toLowerCase()});var bc=co(function(t,n,e){return t+(e?" ":"")+xc(n)});var wc=co(function(t,n,e){return t+(e?" ":"")+n.toUpperCase()}),xc=ao("toUpperCase");function Ec(t,n,e){return t=Ya(t),(n=e?o:n)===o?function(t){return Mn.test(t)}(t)?function(t){return t.match(xn)||[]}(t):function(t){return t.match(Ft)||[]}(t):t.match(n)||[]}var Mc=xi(function(t,n){try{return Vn(t,o,n)}catch(t){return xa(t)?t:new i(t)}}),kc=Co(function(t,n){return Xn(n,function(n){n=lu(n),Pr(t,n,na(t[n],t))}),t});function Nc(t){return function(){return t}}var Sc=so(),Tc=so(!0);function Cc(t){return t}function Ac(t){return ai("function"==typeof t?t:Rr(t,h))}var Pc=xi(function(t,n){return function(e){return ei(e,t,n)}}),Oc=xi(function(t,n){return function(e){return ei(t,e,n)}});function Ic(t,n,e){var r=rc(n),i=Xr(n,r);null!=e||Na(n)&&(i.length||!r.length)||(e=n,n=t,t=this,i=Xr(n,rc(n)));var o=!(Na(e)&&"chain"in e&&!e.chain),u=Ea(t);return Xn(i,function(e){var r=n[e];t[e]=r,u&&(t.prototype[e]=function(){var n=this.__chain__;if(o||n){var e=t(this.__wrapped__);return(e.__actions__=no(this.__actions__)).push({func:r,args:arguments,thisArg:t}),e.__chain__=n,e}return r.apply(t,ne([this.value()],arguments))})}),t}function Rc(){}var Dc=go(te),Lc=go(Qn),Uc=go(ie);function zc(t){return Wo(t)?he(lu(t)):function(t){return function(n){return Gr(n,t)}}(t)}var jc=mo(),Fc=mo(!0);function qc(){return[]}function Bc(){return!1}var Hc=vo(function(t,n){return t+n},0),Yc=wo("ceil"),$c=vo(function(t,n){return t/n},1),Vc=wo("floor");var Wc=vo(function(t,n){return t*n},1),Xc=wo("round"),Gc=vo(function(t,n){return t-n},0);return hr.after=function(t,n){if("function"!=typeof n)throw new rn(c);return t=Fa(t),function(){if(--t<1)return n.apply(this,arguments)}},hr.ary=Ju,hr.assign=$a,hr.assignIn=Va,hr.assignInWith=Wa,hr.assignWith=Xa,hr.at=Ga,hr.before=ta,hr.bind=na,hr.bindAll=kc,hr.bindKey=ea,hr.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return ga(t)?t:[t]},hr.chain=zu,hr.chunk=function(t,n,r){n=(r?Vo(t,n,r):n===o)?1:Ye(Fa(n),0);var i=null==t?0:t.length;if(!i||n<1)return[];for(var u=0,a=0,c=e(Ue(i/n));ui?0:i+e),(r=r===o||r>i?i:Fa(r))<0&&(r+=i),r=e>r?0:qa(r);e>>0)?(t=Ya(t))&&("string"==typeof n||null!=n&&!Pa(n))&&!(n=Di(n))&&ke(t)?Wi(Oe(t),0,e):t.split(n,e):[]},hr.spread=function(t,n){if("function"!=typeof t)throw new rn(c);return n=null==n?0:Ye(Fa(n),0),xi(function(e){var r=e[n],i=Wi(e,0,n);return r&&ne(i,r),Vn(t,this,i)})},hr.tail=function(t){var n=null==t?0:t.length;return n?Ci(t,1,n):[]},hr.take=function(t,n,e){return t&&t.length?Ci(t,0,(n=e||n===o?1:Fa(n))<0?0:n):[]},hr.takeRight=function(t,n,e){var r=null==t?0:t.length;return r?Ci(t,(n=r-(n=e||n===o?1:Fa(n)))<0?0:n,r):[]},hr.takeRightWhile=function(t,n){return t&&t.length?ji(t,Do(n,3),!1,!0):[]},hr.takeWhile=function(t,n){return t&&t.length?ji(t,Do(n,3)):[]},hr.tap=function(t,n){return n(t),t},hr.throttle=function(t,n,e){var r=!0,i=!0;if("function"!=typeof t)throw new rn(c);return Na(e)&&(r="leading"in e?!!e.leading:r,i="trailing"in e?!!e.trailing:i),ra(t,n,{leading:r,maxWait:n,trailing:i})},hr.thru=ju,hr.toArray=za,hr.toPairs=fc,hr.toPairsIn=sc,hr.toPath=function(t){return ga(t)?te(t,lu):Ra(t)?[t]:no(cu(Ya(t)))},hr.toPlainObject=Ha,hr.transform=function(t,n,e){var r=ga(t),i=r||ba(t)||Da(t);if(n=Do(n,4),null==e){var o=t&&t.constructor;e=i?r?new o:[]:Na(t)&&Ea(o)?dr(Cn(t)):{}}return(i?Xn:Vr)(t,function(t,r,i){return n(e,t,r,i)}),e},hr.unary=function(t){return Ju(t,1)},hr.union=Su,hr.unionBy=Tu,hr.unionWith=Cu,hr.uniq=function(t){return t&&t.length?Li(t):[]},hr.uniqBy=function(t,n){return t&&t.length?Li(t,Do(n,2)):[]},hr.uniqWith=function(t,n){return n="function"==typeof n?n:o,t&&t.length?Li(t,o,n):[]},hr.unset=function(t,n){return null==t||Ui(t,n)},hr.unzip=Au,hr.unzipWith=Pu,hr.update=function(t,n,e){return null==t?t:zi(t,n,Yi(e))},hr.updateWith=function(t,n,e,r){return r="function"==typeof r?r:o,null==t?t:zi(t,n,Yi(e),r)},hr.values=hc,hr.valuesIn=function(t){return null==t?[]:me(t,ic(t))},hr.without=Ou,hr.words=Ec,hr.wrap=function(t,n){return la(Yi(n),t)},hr.xor=Iu,hr.xorBy=Ru,hr.xorWith=Du,hr.zip=Lu,hr.zipObject=function(t,n){return Bi(t||[],n||[],Sr)},hr.zipObjectDeep=function(t,n){return Bi(t||[],n||[],ki)},hr.zipWith=Uu,hr.entries=fc,hr.entriesIn=sc,hr.extend=Va,hr.extendWith=Wa,Ic(hr,hr),hr.add=Hc,hr.attempt=Mc,hr.camelCase=dc,hr.capitalize=pc,hr.ceil=Yc,hr.clamp=function(t,n,e){return e===o&&(e=n,n=o),e!==o&&(e=(e=Ba(e))==e?e:0),n!==o&&(n=(n=Ba(n))==n?n:0),Ir(Ba(t),n,e)},hr.clone=function(t){return Rr(t,p)},hr.cloneDeep=function(t){return Rr(t,h|p)},hr.cloneDeepWith=function(t,n){return Rr(t,h|p,n="function"==typeof n?n:o)},hr.cloneWith=function(t,n){return Rr(t,p,n="function"==typeof n?n:o)},hr.conformsTo=function(t,n){return null==n||Dr(t,n,rc(n))},hr.deburr=vc,hr.defaultTo=function(t,n){return null==t||t!=t?n:t},hr.divide=$c,hr.endsWith=function(t,n,e){t=Ya(t),n=Di(n);var r=t.length,i=e=e===o?r:Ir(Fa(e),0,r);return(e-=n.length)>=0&&t.slice(e,i)==n},hr.eq=ha,hr.escape=function(t){return(t=Ya(t))&&kt.test(t)?t.replace(Et,Ee):t},hr.escapeRegExp=function(t){return(t=Ya(t))&&It.test(t)?t.replace(Ot,"\\$&"):t},hr.every=function(t,n,e){var r=ga(t)?Qn:Fr;return e&&Vo(t,n,e)&&(n=o),r(t,Do(n,3))},hr.find=Bu,hr.findIndex=vu,hr.findKey=function(t,n){return ue(t,Do(n,3),Vr)},hr.findLast=Hu,hr.findLastIndex=gu,hr.findLastKey=function(t,n){return ue(t,Do(n,3),Wr)},hr.floor=Vc,hr.forEach=Yu,hr.forEachRight=$u,hr.forIn=function(t,n){return null==t?t:Yr(t,Do(n,3),ic)},hr.forInRight=function(t,n){return null==t?t:$r(t,Do(n,3),ic)},hr.forOwn=function(t,n){return t&&Vr(t,Do(n,3))},hr.forOwnRight=function(t,n){return t&&Wr(t,Do(n,3))},hr.get=Ka,hr.gt=da,hr.gte=pa,hr.has=function(t,n){return null!=t&&Bo(t,n,Jr)},hr.hasIn=Ja,hr.head=mu,hr.identity=Cc,hr.includes=function(t,n,e,r){t=ma(t)?t:hc(t),e=e&&!r?Fa(e):0;var i=t.length;return e<0&&(e=Ye(i+e,0)),Ia(t)?e<=i&&t.indexOf(n,e)>-1:!!i&&ce(t,n,e)>-1},hr.indexOf=function(t,n,e){var r=null==t?0:t.length;if(!r)return-1;var i=null==e?0:Fa(e);return i<0&&(i=Ye(r+i,0)),ce(t,n,i)},hr.inRange=function(t,n,e){return n=ja(n),e===o?(e=n,n=0):e=ja(e),function(t,n,e){return t>=$e(n,e)&&t=-R&&t<=R},hr.isSet=Oa,hr.isString=Ia,hr.isSymbol=Ra,hr.isTypedArray=Da,hr.isUndefined=function(t){return t===o},hr.isWeakMap=function(t){return Sa(t)&&qo(t)==ut},hr.isWeakSet=function(t){return Sa(t)&&Zr(t)==at},hr.join=function(t,n){return null==t?"":Be.call(t,n)},hr.kebabCase=gc,hr.last=xu,hr.lastIndexOf=function(t,n,e){var r=null==t?0:t.length;if(!r)return-1;var i=r;return e!==o&&(i=(i=Fa(e))<0?Ye(r+i,0):$e(i,r-1)),n==n?function(t,n,e){for(var r=e+1;r--;)if(t[r]===n)return r;return r}(t,n,i):ae(t,fe,i,!0)},hr.lowerCase=yc,hr.lowerFirst=mc,hr.lt=La,hr.lte=Ua,hr.max=function(t){return t&&t.length?qr(t,Cc,Kr):o},hr.maxBy=function(t,n){return t&&t.length?qr(t,Do(n,2),Kr):o},hr.mean=function(t){return se(t,Cc)},hr.meanBy=function(t,n){return se(t,Do(n,2))},hr.min=function(t){return t&&t.length?qr(t,Cc,fi):o},hr.minBy=function(t,n){return t&&t.length?qr(t,Do(n,2),fi):o},hr.stubArray=qc,hr.stubFalse=Bc,hr.stubObject=function(){return{}},hr.stubString=function(){return""},hr.stubTrue=function(){return!0},hr.multiply=Wc,hr.nth=function(t,n){return t&&t.length?vi(t,Fa(n)):o},hr.noConflict=function(){return Rn._===this&&(Rn._=vn),this},hr.noop=Rc,hr.now=Ku,hr.pad=function(t,n,e){t=Ya(t);var r=(n=Fa(n))?Pe(t):0;if(!n||r>=n)return t;var i=(n-r)/2;return yo(ze(i),e)+t+yo(Ue(i),e)},hr.padEnd=function(t,n,e){t=Ya(t);var r=(n=Fa(n))?Pe(t):0;return n&&rn){var r=t;t=n,n=r}if(e||t%1||n%1){var i=Xe();return $e(t+i*(n-t+An("1e-"+((i+"").length-1))),n)}return bi(t,n)},hr.reduce=function(t,n,e){var r=ga(t)?ee:pe,i=arguments.length<3;return r(t,Do(n,4),e,i,zr)},hr.reduceRight=function(t,n,e){var r=ga(t)?re:pe,i=arguments.length<3;return r(t,Do(n,4),e,i,jr)},hr.repeat=function(t,n,e){return n=(e?Vo(t,n,e):n===o)?1:Fa(n),wi(Ya(t),n)},hr.replace=function(){var t=arguments,n=Ya(t[0]);return t.length<3?n:n.replace(t[1],t[2])},hr.result=function(t,n,e){var r=-1,i=(n=$i(n,t)).length;for(i||(i=1,t=o);++rR)return[];var e=U,r=$e(t,U);n=Do(n),t-=U;for(var i=ge(r,n);++e=u)return t;var c=e-Pe(r);if(c<1)return r;var l=a?Wi(a,0,c).join(""):t.slice(0,c);if(i===o)return l+r;if(a&&(c+=l.length-c),Pa(i)){if(t.slice(c).search(i)){var f,s=l;for(i.global||(i=nn(i.source,Ya(Ht.exec(i))+"g")),i.lastIndex=0;f=i.exec(s);)var h=f.index;l=l.slice(0,h===o?c:h)}}else if(t.indexOf(Di(i),c)!=c){var d=l.lastIndexOf(i);d>-1&&(l=l.slice(0,d))}return l+r},hr.unescape=function(t){return(t=Ya(t))&&Mt.test(t)?t.replace(xt,Ie):t},hr.uniqueId=function(t){var n=++sn;return Ya(t)+n},hr.upperCase=wc,hr.upperFirst=xc,hr.each=Yu,hr.eachRight=$u,hr.first=mu,Ic(hr,function(){var t={};return Vr(hr,function(n,e){fn.call(hr.prototype,e)||(t[e]=n)}),t}(),{chain:!1}),hr.VERSION="4.17.11",Xn(["bind","bindKey","curry","curryRight","partial","partialRight"],function(t){hr[t].placeholder=hr}),Xn(["drop","take"],function(t,n){gr.prototype[t]=function(e){e=e===o?1:Ye(Fa(e),0);var r=this.__filtered__&&!n?new gr(this):this.clone();return r.__filtered__?r.__takeCount__=$e(e,r.__takeCount__):r.__views__.push({size:$e(e,U),type:t+(r.__dir__<0?"Right":"")}),r},gr.prototype[t+"Right"]=function(n){return this.reverse()[t](n).reverse()}}),Xn(["filter","map","takeWhile"],function(t,n){var e=n+1,r=e==P||3==e;gr.prototype[t]=function(t){var n=this.clone();return n.__iteratees__.push({iteratee:Do(t,3),type:e}),n.__filtered__=n.__filtered__||r,n}}),Xn(["head","last"],function(t,n){var e="take"+(n?"Right":"");gr.prototype[t]=function(){return this[e](1).value()[0]}}),Xn(["initial","tail"],function(t,n){var e="drop"+(n?"":"Right");gr.prototype[t]=function(){return this.__filtered__?new gr(this):this[e](1)}}),gr.prototype.compact=function(){return this.filter(Cc)},gr.prototype.find=function(t){return this.filter(t).head()},gr.prototype.findLast=function(t){return this.reverse().find(t)},gr.prototype.invokeMap=xi(function(t,n){return"function"==typeof t?new gr(this):this.map(function(e){return ei(e,t,n)})}),gr.prototype.reject=function(t){return this.filter(aa(Do(t)))},gr.prototype.slice=function(t,n){t=Fa(t);var e=this;return e.__filtered__&&(t>0||n<0)?new gr(e):(t<0?e=e.takeRight(-t):t&&(e=e.drop(t)),n!==o&&(e=(n=Fa(n))<0?e.dropRight(-n):e.take(n-t)),e)},gr.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},gr.prototype.toArray=function(){return this.take(U)},Vr(gr.prototype,function(t,n){var e=/^(?:filter|find|map|reject)|While$/.test(n),r=/^(?:head|last)$/.test(n),i=hr[r?"take"+("last"==n?"Right":""):n],u=r||/^find/.test(n);i&&(hr.prototype[n]=function(){var n=this.__wrapped__,a=r?[1]:arguments,c=n instanceof gr,l=a[0],f=c||ga(n),s=function(t){var n=i.apply(hr,ne([t],a));return r&&h?n[0]:n};f&&e&&"function"==typeof l&&1!=l.length&&(c=f=!1);var h=this.__chain__,d=!!this.__actions__.length,p=u&&!h,v=c&&!d;if(!u&&f){n=v?n:new gr(this);var g=t.apply(n,a);return g.__actions__.push({func:ju,args:[s],thisArg:o}),new vr(g,h)}return p&&v?t.apply(this,a):(g=this.thru(s),p?r?g.value()[0]:g.value():g)})}),Xn(["pop","push","shift","sort","splice","unshift"],function(t){var n=on[t],e=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",r=/^(?:pop|shift)$/.test(t);hr.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var i=this.value();return n.apply(ga(i)?i:[],t)}return this[e](function(e){return n.apply(ga(e)?e:[],t)})}}),Vr(gr.prototype,function(t,n){var e=hr[n];if(e){var r=e.name+"";(rr[r]||(rr[r]=[])).push({name:n,func:e})}}),rr[ho(o,m).name]=[{name:"wrapper",func:o}],gr.prototype.clone=function(){var t=new gr(this.__wrapped__);return t.__actions__=no(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=no(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=no(this.__views__),t},gr.prototype.reverse=function(){if(this.__filtered__){var t=new gr(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},gr.prototype.value=function(){var t=this.__wrapped__.value(),n=this.__dir__,e=ga(t),r=n<0,i=e?t.length:0,o=function(t,n,e){for(var r=-1,i=e.length;++r=this.__values__.length;return{done:t,value:t?o:this.__values__[this.__index__++]}},hr.prototype.plant=function(t){for(var n,e=this;e instanceof pr;){var r=su(e);r.__index__=0,r.__values__=o,n?i.__wrapped__=r:n=r;var i=r;e=e.__wrapped__}return i.__wrapped__=t,n},hr.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof gr){var n=t;return this.__actions__.length&&(n=new gr(this)),(n=n.reverse()).__actions__.push({func:ju,args:[Nu],thisArg:o}),new vr(n,this.__chain__)}return this.thru(Nu)},hr.prototype.toJSON=hr.prototype.valueOf=hr.prototype.value=function(){return Fi(this.__wrapped__,this.__actions__)},hr.prototype.first=hr.prototype.head,zn&&(hr.prototype[zn]=function(){return this}),hr}();Rn._=Re,(i=function(){return Re}.call(n,e,n,r))===o||(r.exports=i)}).call(this)}).call(this,e(21),e(22)(t))},function(t,n){t.exports="2.1.5"},function(t,n,e){var r=e(3),i=e(12);t.exports={write:function(t){var n={options:{directed:t.isDirected(),multigraph:t.isMultigraph(),compound:t.isCompound()},nodes:function(t){return r.map(t.nodes(),function(n){var e=t.node(n),i=t.parent(n),o={v:n};return r.isUndefined(e)||(o.value=e),r.isUndefined(i)||(o.parent=i),o})}(t),edges:function(t){return r.map(t.edges(),function(n){var e=t.edge(n),i={v:n.v,w:n.w};return r.isUndefined(n.name)||(i.name=n.name),r.isUndefined(e)||(i.value=e),i})}(t)};r.isUndefined(t.graph())||(n.value=r.clone(t.graph()));return n},read:function(t){var n=new i(t.options).setGraph(t.value);return r.each(t.nodes,function(t){n.setNode(t.v,t.value),t.parent&&n.setParent(t.v,t.parent)}),r.each(t.edges,function(t){n.setEdge({v:t.v,w:t.w,name:t.name},t.value)}),n}}},function(t,n,e){t.exports={components:e(52),dijkstra:e(23),dijkstraAll:e(53),findCycles:e(54),floydWarshall:e(55),isAcyclic:e(56),postorder:e(57),preorder:e(58),prim:e(59),tarjan:e(25),topsort:e(26)}},function(t,n,e){var r=e(3);t.exports=function(t){var n,e={},i=[];function o(i){r.has(e,i)||(e[i]=!0,n.push(i),r.each(t.successors(i),o),r.each(t.predecessors(i),o))}return r.each(t.nodes(),function(t){n=[],o(t),n.length&&i.push(n)}),i}},function(t,n,e){var r=e(23),i=e(3);t.exports=function(t,n,e){return i.transform(t.nodes(),function(i,o){i[o]=r(t,o,n,e)},{})}},function(t,n,e){var r=e(3),i=e(25);t.exports=function(t){return r.filter(i(t),function(n){return n.length>1||1===n.length&&t.hasEdge(n[0],n[0])})}},function(t,n,e){var r=e(3);t.exports=function(t,n,e){return function(t,n,e){var r={},i=t.nodes();return i.forEach(function(t){r[t]={},r[t][t]={distance:0},i.forEach(function(n){t!==n&&(r[t][n]={distance:Number.POSITIVE_INFINITY})}),e(t).forEach(function(e){var i=e.v===t?e.w:e.v,o=n(e);r[t][i]={distance:o,predecessor:t}})}),i.forEach(function(t){var n=r[t];i.forEach(function(e){var o=r[e];i.forEach(function(e){var r=o[t],i=n[e],u=o[e],a=r.distance+i.distance;a0;){if(e=c.removeMin(),r.has(a,e))u.setEdge(e,a[e]);else{if(f)throw new Error("Input graph is not connected: "+t);f=!0}t.nodeEdges(e).forEach(l)}return u}},function(t,n,e){t.exports={graphlib:e(5),layout:e(61),debug:e(83),util:{time:e(1).time,notime:e(1).notime},version:e(84)}},function(t,n,e){"use strict";var r=e(0),i=e(62),o=e(65),u=e(66),a=e(1).normalizeRanks,c=e(68),l=e(1).removeEmptyRanks,f=e(69),s=e(70),h=e(71),d=e(72),p=e(81),v=e(1),g=e(5).Graph;t.exports=function(t,n){var e=n&&n.debugTiming?v.time:v.notime;e("layout",function(){var n=e(" buildLayoutGraph",function(){return function(t){var n=new g({multigraph:!0,compound:!0}),e=N(t.graph());return n.setGraph(r.merge({},m,k(e,y),r.pick(e,_))),r.forEach(t.nodes(),function(e){var i=N(t.node(e));n.setNode(e,r.defaults(k(i,b),w)),n.setParent(e,t.parent(e))}),r.forEach(t.edges(),function(e){var i=N(t.edge(e));n.setEdge(e,r.merge({},E,k(i,x),r.pick(i,M)))}),n}(t)});e(" runLayout",function(){!function(t,n){n(" makeSpaceForEdgeLabels",function(){!function(t){var n=t.graph();n.ranksep/=2,r.forEach(t.edges(),function(e){var r=t.edge(e);r.minlen*=2,"c"!==r.labelpos.toLowerCase()&&("TB"===n.rankdir||"BT"===n.rankdir?r.width+=r.labeloffset:r.height+=r.labeloffset)})}(t)}),n(" removeSelfEdges",function(){!function(t){r.forEach(t.edges(),function(n){if(n.v===n.w){var e=t.node(n.v);e.selfEdges||(e.selfEdges=[]),e.selfEdges.push({e:n,label:t.edge(n)}),t.removeEdge(n)}})}(t)}),n(" acyclic",function(){i.run(t)}),n(" nestingGraph.run",function(){f.run(t)}),n(" rank",function(){u(v.asNonCompoundGraph(t))}),n(" injectEdgeLabelProxies",function(){!function(t){r.forEach(t.edges(),function(n){var e=t.edge(n);if(e.width&&e.height){var r=t.node(n.v),i=t.node(n.w),o={rank:(i.rank-r.rank)/2+r.rank,e:n};v.addDummyNode(t,"edge-proxy",o,"_ep")}})}(t)}),n(" removeEmptyRanks",function(){l(t)}),n(" nestingGraph.cleanup",function(){f.cleanup(t)}),n(" normalizeRanks",function(){a(t)}),n(" assignRankMinMax",function(){!function(t){var n=0;r.forEach(t.nodes(),function(e){var i=t.node(e);i.borderTop&&(i.minRank=t.node(i.borderTop).rank,i.maxRank=t.node(i.borderBottom).rank,n=r.max(n,i.maxRank))}),t.graph().maxRank=n}(t)}),n(" removeEdgeLabelProxies",function(){!function(t){r.forEach(t.nodes(),function(n){var e=t.node(n);"edge-proxy"===e.dummy&&(t.edge(e.e).labelRank=e.rank,t.removeNode(n))})}(t)}),n(" normalize.run",function(){o.run(t)}),n(" parentDummyChains",function(){c(t)}),n(" addBorderSegments",function(){s(t)}),n(" order",function(){d(t)}),n(" insertSelfEdges",function(){!function(t){var n=v.buildLayerMatrix(t);r.forEach(n,function(n){var e=0;r.forEach(n,function(n,i){var o=t.node(n);o.order=i+e,r.forEach(o.selfEdges,function(n){v.addDummyNode(t,"selfedge",{width:n.label.width,height:n.label.height,rank:o.rank,order:i+ ++e,e:n.e,label:n.label},"_se")}),delete o.selfEdges})})}(t)}),n(" adjustCoordinateSystem",function(){h.adjust(t)}),n(" position",function(){p(t)}),n(" positionSelfEdges",function(){!function(t){r.forEach(t.nodes(),function(n){var e=t.node(n);if("selfedge"===e.dummy){var r=t.node(e.e.v),i=r.x+r.width/2,o=r.y,u=e.x-i,a=r.height/2;t.setEdge(e.e,e.label),t.removeNode(n),e.label.points=[{x:i+2*u/3,y:o-a},{x:i+5*u/6,y:o-a},{x:i+u,y:o},{x:i+5*u/6,y:o+a},{x:i+2*u/3,y:o+a}],e.label.x=e.x,e.label.y=e.y}})}(t)}),n(" removeBorderNodes",function(){!function(t){r.forEach(t.nodes(),function(n){if(t.children(n).length){var e=t.node(n),i=t.node(e.borderTop),o=t.node(e.borderBottom),u=t.node(r.last(e.borderLeft)),a=t.node(r.last(e.borderRight));e.width=Math.abs(a.x-u.x),e.height=Math.abs(o.y-i.y),e.x=u.x+e.width/2,e.y=i.y+e.height/2}}),r.forEach(t.nodes(),function(n){"border"===t.node(n).dummy&&t.removeNode(n)})}(t)}),n(" normalize.undo",function(){o.undo(t)}),n(" fixupEdgeLabelCoords",function(){!function(t){r.forEach(t.edges(),function(n){var e=t.edge(n);if(r.has(e,"x"))switch("l"!==e.labelpos&&"r"!==e.labelpos||(e.width-=e.labeloffset),e.labelpos){case"l":e.x-=e.width/2+e.labeloffset;break;case"r":e.x+=e.width/2+e.labeloffset}})}(t)}),n(" undoCoordinateSystem",function(){h.undo(t)}),n(" translateGraph",function(){!function(t){var n=Number.POSITIVE_INFINITY,e=0,i=Number.POSITIVE_INFINITY,o=0,u=t.graph(),a=u.marginx||0,c=u.marginy||0;function l(t){var r=t.x,u=t.y,a=t.width,c=t.height;n=Math.min(n,r-a/2),e=Math.max(e,r+a/2),i=Math.min(i,u-c/2),o=Math.max(o,u+c/2)}r.forEach(t.nodes(),function(n){l(t.node(n))}),r.forEach(t.edges(),function(n){var e=t.edge(n);r.has(e,"x")&&l(e)}),n-=a,i-=c,r.forEach(t.nodes(),function(e){var r=t.node(e);r.x-=n,r.y-=i}),r.forEach(t.edges(),function(e){var o=t.edge(e);r.forEach(o.points,function(t){t.x-=n,t.y-=i}),r.has(o,"x")&&(o.x-=n),r.has(o,"y")&&(o.y-=i)}),u.width=e-n+a,u.height=o-i+c}(t)}),n(" assignNodeIntersects",function(){!function(t){r.forEach(t.edges(),function(n){var e,r,i=t.edge(n),o=t.node(n.v),u=t.node(n.w);i.points?(e=i.points[0],r=i.points[i.points.length-1]):(i.points=[],e=u,r=o),i.points.unshift(v.intersectRect(o,e)),i.points.push(v.intersectRect(u,r))})}(t)}),n(" reversePoints",function(){!function(t){r.forEach(t.edges(),function(n){var e=t.edge(n);e.reversed&&e.points.reverse()})}(t)}),n(" acyclic.undo",function(){i.undo(t)})}(n,e)}),e(" updateInputGraph",function(){!function(t,n){r.forEach(t.nodes(),function(e){var r=t.node(e),i=n.node(e);r&&(r.x=i.x,r.y=i.y,n.children(e).length&&(r.width=i.width,r.height=i.height))}),r.forEach(t.edges(),function(e){var i=t.edge(e),o=n.edge(e);i.points=o.points,r.has(o,"x")&&(i.x=o.x,i.y=o.y)}),t.graph().width=n.graph().width,t.graph().height=n.graph().height}(t,n)})})};var y=["nodesep","edgesep","ranksep","marginx","marginy"],m={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},_=["acyclicer","ranker","rankdir","align"],b=["width","height"],w={width:0,height:0},x=["minlen","weight","width","height","labeloffset"],E={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},M=["labelpos"];function k(t,n){return r.mapValues(r.pick(t,n),Number)}function N(t){var n={};return r.forEach(t,function(t,e){n[e.toLowerCase()]=t}),n}},function(t,n,e){"use strict";var r=e(0),i=e(63);t.exports={run:function(t){var n="greedy"===t.graph().acyclicer?i(t,function(t){return function(n){return t.edge(n).weight}}(t)):function(t){var n=[],e={},i={};return r.forEach(t.nodes(),function o(u){r.has(i,u)||(i[u]=!0,e[u]=!0,r.forEach(t.outEdges(u),function(t){r.has(e,t.w)?n.push(t):o(t.w)}),delete e[u])}),n}(t);r.forEach(n,function(n){var e=t.edge(n);t.removeEdge(n),e.forwardName=n.name,e.reversed=!0,t.setEdge(n.w,n.v,e,r.uniqueId("rev"))})},undo:function(t){r.forEach(t.edges(),function(n){var e=t.edge(n);if(e.reversed){t.removeEdge(n);var r=e.forwardName;delete e.reversed,delete e.forwardName,t.setEdge(n.w,n.v,e,r)}})}}},function(t,n,e){var r=e(0),i=e(5).Graph,o=e(64);t.exports=function(t,n){if(t.nodeCount()<=1)return[];var e=function(t,n){var e=new i,u=0,a=0;r.forEach(t.nodes(),function(t){e.setNode(t,{v:t,in:0,out:0})}),r.forEach(t.edges(),function(t){var r=e.edge(t.v,t.w)||0,i=n(t),o=r+i;e.setEdge(t.v,t.w,o),a=Math.max(a,e.node(t.v).out+=i),u=Math.max(u,e.node(t.w).in+=i)});var l=r.range(a+u+3).map(function(){return new o}),f=u+1;return r.forEach(e.nodes(),function(t){c(l,f,e.node(t))}),{graph:e,buckets:l,zeroIdx:f}}(t,n||u),l=function(t,n,e){var r,i=[],o=n[n.length-1],u=n[0];for(;t.nodeCount();){for(;r=u.dequeue();)a(t,n,e,r);for(;r=o.dequeue();)a(t,n,e,r);if(t.nodeCount())for(var c=n.length-2;c>0;--c)if(r=n[c].dequeue()){i=i.concat(a(t,n,e,r,!0));break}}return i}(e.graph,e.buckets,e.zeroIdx);return r.flatten(r.map(l,function(n){return t.outEdges(n.v,n.w)}),!0)};var u=r.constant(1);function a(t,n,e,i,o){var u=o?[]:void 0;return r.forEach(t.inEdges(i.v),function(r){var i=t.edge(r),a=t.node(r.v);o&&u.push({v:r.v,w:r.w}),a.out-=i,c(n,e,a)}),r.forEach(t.outEdges(i.v),function(r){var i=t.edge(r),o=r.w,u=t.node(o);u.in-=i,c(n,e,u)}),t.removeNode(i.v),u}function c(t,n,e){e.out?e.in?t[e.out-e.in+n].enqueue(e):t[t.length-1].enqueue(e):t[0].enqueue(e)}},function(t,n){function e(){var t={};t._next=t._prev=t,this._sentinel=t}function r(t){t._prev._next=t._next,t._next._prev=t._prev,delete t._next,delete t._prev}function i(t,n){if("_next"!==t&&"_prev"!==t)return n}t.exports=e,e.prototype.dequeue=function(){var t=this._sentinel,n=t._prev;if(n!==t)return r(n),n},e.prototype.enqueue=function(t){var n=this._sentinel;t._prev&&t._next&&r(t),t._next=n._next,n._next._prev=t,n._next=t,t._prev=n},e.prototype.toString=function(){for(var t=[],n=this._sentinel,e=n._prev;e!==n;)t.push(JSON.stringify(e,i)),e=e._prev;return"["+t.join(", ")+"]"}},function(t,n,e){"use strict";var r=e(0),i=e(1);t.exports={run:function(t){t.graph().dummyChains=[],r.forEach(t.edges(),function(n){!function(t,n){var e,r,o,u=n.v,a=t.node(u).rank,c=n.w,l=t.node(c).rank,f=n.name,s=t.edge(n),h=s.labelRank;if(l===a+1)return;for(t.removeEdge(n),o=0,++a;ac.lim&&(l=c,f=!0);var s=r.filter(n.edges(),function(n){return f===y(t,t.node(n.v),l)&&f!==y(t,t.node(n.w),l)});return r.minBy(s,function(t){return o(n,t)})}function g(t,n,e,i){var o=e.v,u=e.w;t.removeEdge(o,u),t.setEdge(i.v,i.w,{}),d(t),s(t,n),function(t,n){var e=r.find(t.nodes(),function(t){return!n.node(t).parent}),i=a(t,e);i=i.slice(1),r.forEach(i,function(e){var r=t.node(e).parent,i=n.edge(e,r),o=!1;i||(i=n.edge(r,e),o=!0),n.node(e).rank=n.node(r).rank+(o?i.minlen:-i.minlen)})}(t,n)}function y(t,n,e){return e.low<=n.lim&&n.lim<=e.lim}t.exports=f,f.initLowLimValues=d,f.initCutValues=s,f.calcCutValue=h,f.leaveEdge=p,f.enterEdge=v,f.exchangeEdges=g},function(t,n,e){var r=e(0);t.exports=function(t){var n=function(t){var n={},e=0;return r.forEach(t.children(),function i(o){var u=e;r.forEach(t.children(o),i),n[o]={low:u,lim:e++}}),n}(t);r.forEach(t.graph().dummyChains,function(e){for(var r=t.node(e),i=r.edgeObj,o=function(t,n,e,r){var i,o,u=[],a=[],c=Math.min(n[e].low,n[r].low),l=Math.max(n[e].lim,n[r].lim);i=e;do{i=t.parent(i),u.push(i)}while(i&&(n[i].low>c||l>n[i].lim));o=i,i=r;for(;(i=t.parent(i))!==o;)a.push(i);return{path:u.concat(a.reverse()),lca:o}}(t,n,i.v,i.w),u=o.path,a=o.lca,c=0,l=u[c],f=!0;e!==i.w;){if(r=t.node(e),f){for(;(l=u[c])!==a&&t.node(l).maxRank=2),a=f.buildLayerMatrix(t);var g=o(t,a);g0;)n%2&&(e+=c[n+1]),c[n=n-1>>1]+=t.weight;l+=t.weight*e})),l}t.exports=function(t,n){for(var e=0,r=1;r=t.barycenter)&&function(t,n){var e=0,r=0;t.weight&&(e+=t.barycenter*t.weight,r+=t.weight),n.weight&&(e+=n.barycenter*n.weight,r+=n.weight),t.vs=n.vs.concat(t.vs),t.barycenter=e/r,t.weight=r,t.i=Math.min(n.i,t.i),n.merged=!0}(t,n)}}function i(n){return function(e){e.in.push(n),0==--e.indegree&&t.push(e)}}for(;t.length;){var o=t.pop();n.push(o),r.forEach(o.in.reverse(),e(o)),r.forEach(o.out,i(o))}return r.chain(n).filter(function(t){return!t.merged}).map(function(t){return r.pick(t,["vs","i","barycenter","weight"])}).value()}(r.filter(e,function(t){return!t.indegree}))}},function(t,n,e){var r=e(0),i=e(1);function o(t,n,e){for(var i;n.length&&(i=r.last(n)).i<=e;)n.pop(),t.push(i.vs),e++;return e}t.exports=function(t,n){var e=i.partition(t,function(t){return r.has(t,"barycenter")}),u=e.lhs,a=r.sortBy(e.rhs,function(t){return-t.i}),c=[],l=0,f=0,s=0;u.sort(function(t){return function(n,e){return n.barycentere.barycenter?1:t?e.i-n.i:n.i-e.i}}(!!n)),s=o(c,a,s),r.forEach(u,function(t){s+=t.vs.length,c.push(t.vs),l+=t.barycenter*t.weight,f+=t.weight,s=o(c,a,s)});var h={vs:r.flatten(c,!0)};f&&(h.barycenter=l/f,h.weight=f);return h}},function(t,n,e){var r=e(0),i=e(5).Graph;t.exports=function(t,n,e){var o=function(t){var n;for(;t.hasNode(n=r.uniqueId("_root")););return n}(t),u=new i({compound:!0}).setGraph({root:o}).setDefaultNodeLabel(function(n){return t.node(n)});return r.forEach(t.nodes(),function(i){var a=t.node(i),c=t.parent(i);(a.rank===n||a.minRank<=n&&n<=a.maxRank)&&(u.setNode(i),u.setParent(i,c||o),r.forEach(t[e](i),function(n){var e=n.v===i?n.w:n.v,o=u.edge(e,i),a=r.isUndefined(o)?0:o.weight;u.setEdge(e,i,{weight:t.edge(n).weight+a})}),r.has(a,"minRank")&&u.setNode(i,{borderLeft:a.borderLeft[n],borderRight:a.borderRight[n]}))}),u}},function(t,n,e){var r=e(0);t.exports=function(t,n,e){var i,o={};r.forEach(e,function(e){for(var r,u,a=t.parent(e);a;){if((r=t.parent(a))?(u=o[r],o[r]=a):(u=i,i=a),u&&u!==a)return void n.setEdge(u,a);a=r}})}},function(t,n,e){"use strict";var r=e(0),i=e(1),o=e(82).positionX;t.exports=function(t){(function(t){var n=i.buildLayerMatrix(t),e=t.graph().ranksep,o=0;r.forEach(n,function(n){var i=r.max(r.map(n,function(n){return t.node(n).height}));r.forEach(n,function(n){t.node(n).y=o+i/2}),o+=i+e})})(t=i.asNonCompoundGraph(t)),r.forEach(o(t),function(n,e){t.node(e).x=n})}},function(t,n,e){"use strict";var r=e(0),i=e(5).Graph,o=e(1);function u(t,n){var e={};return r.reduce(n,function(n,i){var o=0,u=0,a=n.length,l=r.last(i);return r.forEach(i,function(n,f){var s=function(t,n){if(t.node(n).dummy)return r.find(t.predecessors(n),function(n){return t.node(n).dummy})}(t,n),h=s?t.node(s).order:a;(s||n===l)&&(r.forEach(i.slice(u,f+1),function(n){r.forEach(t.predecessors(n),function(r){var i=t.node(r),u=i.order;!(ua)&&c(e,n,l)})})}return r.reduce(n,function(n,e){var o,u=-1,a=0;return r.forEach(e,function(r,c){if("border"===t.node(r).dummy){var l=t.predecessors(r);l.length&&(o=t.node(l[0]).order,i(e,a,c,u,o),a=c,u=o)}i(e,a,e.length,o,n.length)}),e}),e}function c(t,n,e){if(n>e){var r=n;n=e,e=r}var i=t[n];i||(t[n]=i={}),i[e]=!0}function l(t,n,e){if(n>e){var i=n;n=e,e=i}return r.has(t[n],e)}function f(t,n,e,i){var o={},u={},a={};return r.forEach(n,function(t){r.forEach(t,function(t,n){o[t]=t,u[t]=t,a[t]=n})}),r.forEach(n,function(t){var n=-1;r.forEach(t,function(t){var c=i(t);if(c.length)for(var f=((c=r.sortBy(c,function(t){return a[t]})).length-1)/2,s=Math.floor(f),h=Math.ceil(f);s<=h;++s){var d=c[s];u[t]===t&&n0}t.exports=function(t,n,r,i){var o,u,a,c,l,f,s,h,d,p,v,g,y;if(o=n.y-t.y,a=t.x-n.x,l=n.x*t.y-t.x*n.y,d=o*r.x+a*r.y+l,p=o*i.x+a*i.y+l,0!==d&&0!==p&&e(d,p))return;if(u=i.y-r.y,c=r.x-i.x,f=i.x*r.y-r.x*i.y,s=u*t.x+c*t.y+f,h=u*n.x+c*n.y+f,0!==s&&0!==h&&e(s,h))return;if(0==(v=o*c-u*a))return;return g=Math.abs(v/2),{x:(y=a*f-c*l)<0?(y-g)/v:(y+g)/v,y:(y=u*l-o*f)<0?(y-g)/v:(y+g)/v}}},function(t,n,e){var r=e(10),i=e(8),o=e(28).layout;t.exports=function(){var t=e(88),n=e(92),i=e(93),l=e(94),f=e(95),s=e(96),h=e(97),d=e(98),p=e(99),v=function(e,v){!function(t){t.nodes().forEach(function(n){var e=t.node(n);r.has(e,"label")||t.children(n).length||(e.label=n),r.has(e,"paddingX")&&r.defaults(e,{paddingLeft:e.paddingX,paddingRight:e.paddingX}),r.has(e,"paddingY")&&r.defaults(e,{paddingTop:e.paddingY,paddingBottom:e.paddingY}),r.has(e,"padding")&&r.defaults(e,{paddingLeft:e.padding,paddingRight:e.padding,paddingTop:e.padding,paddingBottom:e.padding}),r.defaults(e,u),r.each(["paddingLeft","paddingRight","paddingTop","paddingBottom"],function(t){e[t]=Number(e[t])}),r.has(e,"width")&&(e._prevWidth=e.width),r.has(e,"height")&&(e._prevHeight=e.height)}),t.edges().forEach(function(n){var e=t.edge(n);r.has(e,"label")||(e.label=""),r.defaults(e,a)})}(v),e.selectAll("*").remove();var g=c(e,"output"),y=c(g,"clusters"),m=c(g,"edgePaths"),_=i(c(g,"edgeLabels"),v),b=t(c(g,"nodes"),v,d);o(v),f(b,v),s(_,v),l(m,v,p);var w=n(y,v);h(w,v),function(t){r.each(t.nodes(),function(n){var e=t.node(n);r.has(e,"_prevWidth")?e.width=e._prevWidth:delete e.width,r.has(e,"_prevHeight")?e.height=e._prevHeight:delete e.height,delete e._prevWidth,delete e._prevHeight})}(v)};return v.createNodes=function(n){return arguments.length?(t=n,v):t},v.createClusters=function(t){return arguments.length?(n=t,v):n},v.createEdgeLabels=function(t){return arguments.length?(i=t,v):i},v.createEdgePaths=function(t){return arguments.length?(l=t,v):l},v.shapes=function(t){return arguments.length?(d=t,v):d},v.arrows=function(t){return arguments.length?(p=t,v):p},v};var u={paddingLeft:10,paddingRight:10,paddingTop:10,paddingBottom:10,rx:0,ry:0,shape:"rect"},a={arrowhead:"normal",curve:i.curveLinear};function c(t,n){var e=t.select("g."+n);return e.empty()&&(e=t.append("g").attr("class",n)),e}},function(t,n,e){"use strict";var r=e(10),i=e(14),o=e(4),u=e(8);t.exports=function(t,n,e){var a=n.nodes().filter(function(t){return!o.isSubgraph(n,t)}),c=t.selectAll("g.node").data(a,function(t){return t}).classed("update",!0);return c.selectAll("*").remove(),c.enter().append("g").attr("class","node").style("opacity",0),(c=t.selectAll("g.node")).each(function(t){var a=n.node(t),c=u.select(this);o.applyClass(c,a.class,(c.classed("update")?"update ":"")+"node");var l=c.append("g").attr("class","label"),f=i(l,a),s=e[a.shape],h=r.pick(f.node().getBBox(),"width","height");a.elem=this,a.id&&c.attr("id",a.id),a.labelId&&l.attr("id",a.labelId),r.has(a,"width")&&(h.width=a.width),r.has(a,"height")&&(h.height=a.height),h.width+=a.paddingLeft+a.paddingRight,h.height+=a.paddingTop+a.paddingBottom,l.attr("transform","translate("+(a.paddingLeft-a.paddingRight)/2+","+(a.paddingTop-a.paddingBottom)/2+")");var d=s(u.select(this),h,a);o.applyStyle(d,a.style);var p=d.node().getBBox();a.width=p.width,a.height=p.height}),o.applyTransition(c.exit(),n).style("opacity",0).remove(),c}},function(t,n,e){var r=e(4);t.exports=function(t,n){for(var e=t.append("text"),i=function(t){for(var n,e="",r=!1,i=0;in?1:t>=n?0:NaN},i=function(t){return 1===t.length&&(t=function(t){return function(n,e){return r(t(n),e)}}(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)>0?i=o:r=o+1}return r}}};var o=i(r),u=o.right,a=o.left,c=u,l=function(t,n){null==n&&(n=f);for(var e=0,r=t.length-1,i=t[0],o=new Array(r<0?0:r);et?1:n>=t?0:NaN},d=function(t){return null===t?NaN:+t},p=function(t,n){var e,r,i=t.length,o=0,u=-1,a=0,c=0;if(null==n)for(;++u1)return c/(o-1)},v=function(t,n){var e=p(t,n);return e?Math.sqrt(e):e},g=function(t,n){var e,r,i,o=t.length,u=-1;if(null==n){for(;++u=e)for(r=i=e;++ue&&(r=e),i=e)for(r=i=e;++ue&&(r=e),i0)return[t];if((r=n0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++a=0?(o>=E?10:o>=M?5:o>=k?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=E?10:o>=M?5:o>=k?2:1)}function T(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=E?i*=10:o>=M?i*=5:o>=k&&(i*=2),ns;)h.pop(),--d;var p,v=new Array(d+1);for(i=0;i<=d;++i)(p=v[i]=[]).x0=i>0?h[i-1]:f,p.x1=i=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}},O=function(t,n,e){return t=_.call(t,d).sort(r),Math.ceil((e-n)/(2*(P(t,.75)-P(t,.25))*Math.pow(t.length,-1/3)))},I=function(t,n,e){return Math.ceil((e-n)/(3.5*v(t)*Math.pow(t.length,-1/3)))},R=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o=e)for(r=e;++or&&(r=e)}else for(;++o=e)for(r=e;++or&&(r=e);return r},D=function(t,n){var e,r=t.length,i=r,o=-1,u=0;if(null==n)for(;++o=0;)for(n=(r=t[i]).length;--n>=0;)e[--u]=r[n];return e},z=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o=e)for(r=e;++oe&&(r=e)}else for(;++o=e)for(r=e;++oe&&(r=e);return r},j=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},F=function(t,n){if(e=t.length){var e,i,o=0,u=0,a=t[u];for(null==n&&(n=r);++o=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),pt.hasOwnProperty(n)?{space:pt[n],local:t}:t};var gt=function(t){var n=vt(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===dt&&n.documentElement.namespaceURI===dt?n.createElement(t):n.createElementNS(e,t)}})(n)};function yt(){}var mt=function(t){return null==t?yt:function(){return this.querySelector(t)}};function _t(){return[]}var bt=function(t){return null==t?_t:function(){return this.querySelectorAll(t)}},wt=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var xt=document.documentElement;if(!xt.matches){var Et=xt.webkitMatchesSelector||xt.msMatchesSelector||xt.mozMatchesSelector||xt.oMatchesSelector;wt=function(t){return function(){return Et.call(this,t)}}}}var Mt=wt,kt=function(t){return new Array(t.length)};function Nt(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}Nt.prototype={constructor:Nt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var St="$";function Tt(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var Pt=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function Ot(t,n){return t.style.getPropertyValue(n)||Pt(t).getComputedStyle(t,null).getPropertyValue(n)}function It(t){return t.trim().split(/^|\s+/)}function Rt(t){return t.classList||new Dt(t)}function Dt(t){this._node=t,this._names=It(t.getAttribute("class")||"")}function Lt(t,n){for(var e=Rt(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function zt(){this.textContent=""}function jt(){this.innerHTML=""}function Ft(){this.nextSibling&&this.parentNode.appendChild(this)}function qt(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function Bt(){return null}function Ht(){var t=this.parentNode;t&&t.removeChild(this)}function Yt(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function $t(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var Vt={},Wt=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(Vt={mouseenter:"mouseover",mouseleave:"mouseout"}));function Xt(t,n,e){return t=Gt(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function Gt(t,n,e){return function(r){var i=Wt;Wt=r;try{t.call(this,this.__data__,n,e)}finally{Wt=i}}}function Qt(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=At);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):Ot(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=It(t+"");if(arguments.length<2){for(var r=Rt(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?Zt:Qt,null==e&&(e=!1),r=0;r>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=xn.exec(t))?Pn(parseInt(n[1],16)):(n=En.exec(t))?new Dn(n[1],n[2],n[3],1):(n=Mn.exec(t))?new Dn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=kn.exec(t))?On(n[1],n[2],n[3],n[4]):(n=Nn.exec(t))?On(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Sn.exec(t))?Un(n[1],n[2]/100,n[3]/100,1):(n=Tn.exec(t))?Un(n[1],n[2]/100,n[3]/100,n[4]):Cn.hasOwnProperty(t)?Pn(Cn[t]):"transparent"===t?new Dn(NaN,NaN,NaN,0):null}function Pn(t){return new Dn(t>>16&255,t>>8&255,255&t,1)}function On(t,n,e,r){return r<=0&&(t=n=e=NaN),new Dn(t,n,e,r)}function In(t){return t instanceof yn||(t=An(t)),t?new Dn((t=t.rgb()).r,t.g,t.b,t.opacity):new Dn}function Rn(t,n,e,r){return 1===arguments.length?In(t):new Dn(t,n,e,null==r?1:r)}function Dn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ln(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Un(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new jn(t,n,e,r)}function zn(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof jn)return new jn(t.h,t.s,t.l,t.opacity);if(t instanceof yn||(t=An(t)),!t)return new jn;if(t instanceof jn)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new jn(u,a,c,t.opacity)}(t):new jn(t,n,e,null==r?1:r)}function jn(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Fn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}vn(yn,An,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),vn(Dn,Rn,gn(yn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Dn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Dn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+Ln(this.r)+Ln(this.g)+Ln(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),vn(jn,zn,gn(yn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new jn(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new jn(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new Dn(Fn(t>=240?t-240:t+120,i,r),Fn(t,i,r),Fn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var qn=Math.PI/180,Bn=180/Math.PI,Hn=.96422,Yn=1,$n=.82521,Vn=4/29,Wn=6/29,Xn=3*Wn*Wn,Gn=Wn*Wn*Wn;function Qn(t){if(t instanceof Kn)return new Kn(t.l,t.a,t.b,t.opacity);if(t instanceof oe){if(isNaN(t.h))return new Kn(t.l,0,0,t.opacity);var n=t.h*qn;return new Kn(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof Dn||(t=In(t));var e,r,i=ee(t.r),o=ee(t.g),u=ee(t.b),a=Jn((.2225045*i+.7168786*o+.0606169*u)/Yn);return i===o&&o===u?e=r=a:(e=Jn((.4360747*i+.3850649*o+.1430804*u)/Hn),r=Jn((.0139322*i+.0971045*o+.7141733*u)/$n)),new Kn(116*a-16,500*(e-a),200*(a-r),t.opacity)}function Zn(t,n,e,r){return 1===arguments.length?Qn(t):new Kn(t,n,e,null==r?1:r)}function Kn(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Jn(t){return t>Gn?Math.pow(t,1/3):t/Xn+Vn}function te(t){return t>Wn?t*t*t:Xn*(t-Vn)}function ne(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function ee(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function re(t){if(t instanceof oe)return new oe(t.h,t.c,t.l,t.opacity);if(t instanceof Kn||(t=Qn(t)),0===t.a&&0===t.b)return new oe(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*Bn;return new oe(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function ie(t,n,e,r){return 1===arguments.length?re(t):new oe(t,n,e,null==r?1:r)}function oe(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}vn(Kn,Zn,gn(yn,{brighter:function(t){return new Kn(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Kn(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new Dn(ne(3.1338561*(n=Hn*te(n))-1.6168667*(t=Yn*te(t))-.4906146*(e=$n*te(e))),ne(-.9787684*n+1.9161415*t+.033454*e),ne(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),vn(oe,ie,gn(yn,{brighter:function(t){return new oe(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new oe(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return Qn(this).rgb()}}));var ue=-.29227,ae=-.90649,ce=1.97294,le=ce*ae,fe=1.78277*ce,se=1.78277*ue- -.14861*ae;function he(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof de)return new de(t.h,t.s,t.l,t.opacity);t instanceof Dn||(t=In(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(se*r+le*n-fe*e)/(se+le-fe),o=r-i,u=(ce*(e-i)-ue*o)/ae,a=Math.sqrt(u*u+o*o)/(ce*i*(1-i)),c=a?Math.atan2(u,o)*Bn-120:NaN;return new de(c<0?c+360:c,a,i,t.opacity)}(t):new de(t,n,e,null==r?1:r)}function de(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function pe(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}vn(de,he,gn(yn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new de(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new de(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*qn,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new Dn(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(ue*r+ae*i)),255*(n+e*(ce*r)),this.opacity)}}));var ve=function(t){return function(){return t}};function ge(t,n){return function(e){return t+e*n}}function ye(t,n){var e=n-t;return e?ge(t,e>180||e<-180?e-360*Math.round(e/360):e):ve(isNaN(t)?n:t)}function me(t){return 1==(t=+t)?_e:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):ve(isNaN(n)?e:n)}}function _e(t,n){var e=n-t;return e?ge(t,e):ve(isNaN(t)?n:t)}var be=function t(n){var e=me(n);function r(t,n){var r=e((t=Rn(t)).r,(n=Rn(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=_e(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function we(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:xe(e,r)})),o=Me.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:xe(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:xe(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:xe(t,e)},{i:a-2,x:xe(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e=0&&n._call.call(null,t),n=n._next;--Be}()}finally{Be=0,function(){var t,n,e=Fe,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Fe=n);qe=t,rr(r)}(),We=0}}function er(){var t=Ge.now(),n=t-Ve;n>$e&&(Xe-=n,Ve=t)}function rr(t){Be||(He&&(He=clearTimeout(He)),t-We>24?(t<1/0&&(He=setTimeout(nr,t-Ge.now()-Xe)),Ye&&(Ye=clearInterval(Ye))):(Ye||(Ve=Ge.now(),Ye=setInterval(er,$e)),Be=1,Qe(nr)))}Je.prototype=tr.prototype={constructor:Je,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Ze():+e)+(null==n?0:+n),this._next||qe===this||(qe?qe._next=this:Fe=this,qe=this),this._call=t,this._time=e,rr()},stop:function(){this._call&&(this._call=null,this._time=1/0,rr())}};var ir=function(t,n,e){var r=new Je;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},or=ht("start","end","interrupt"),ur=[],ar=0,cr=1,lr=2,fr=3,sr=4,hr=5,dr=6,pr=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(c){var l,f,s,h;if(e.state!==cr)return a();for(l in i)if((h=i[l]).name===e.name){if(h.state===fr)return ir(o);h.state===sr?(h.state=dr,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[l]):+lar)throw new Error("too late; already scheduled");return e}function gr(t,n){var e=yr(t,n);if(e.state>lr)throw new Error("too late; already started");return e}function yr(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}var mr=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>lr&&e.state=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?vr:gr;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}(e,t,n))},attr:function(t,n){var e=vt(t),r="transform"===e?Le:br;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}})(e,r,_r(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}:function(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}})(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=vt(t);return this.tween(e,(r.local?function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}:function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?De:br;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=Ot(this,t),u=(this.style.removeProperty(t),Ot(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}(t,r)).on("end.style."+t,function(t){return function(){this.style.removeProperty(t)}}(t)):this.styleTween(t,"function"==typeof n?function(t,n,e){var r,i,o;return function(){var u=Ot(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=Ot(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}(t,r,_r(this,"style."+t,n)):function(t,n,e){var r,i;return function(){var o=Ot(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(_r(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=yr(this.node(),e).tween,o=0,u=i.length;o0&&(e=i-d),x<0?s=h-p:x>0&&(o=u-p),b=Rr,D.attr("cursor",Fr.selection),z());break;default:return}Or()},!0).on("keyup.brush",function(){switch(Wt.keyCode){case 16:A&&(g=y=A=!1,z());break;case 18:b===Lr&&(w<0?l=f:w>0&&(e=i),x<0?s=h:x>0&&(o=u),b=Dr,z());break;case 32:b===Rr&&(Wt.altKey?(w&&(l=f-d*w,e=i+d*w),x&&(s=h-p*x,o=u+p*x),b=Lr):(w<0?l=f:w>0&&(e=i),x<0?s=h:x>0&&(o=u),b=Dr),D.attr("cursor",Fr[_]),z());break;default:return}Or()},!0).on("mousemove.brush",U,!0).on("mouseup.brush",j,!0);hn(Wt.view)}Pr(),mr(m),a.call(m),I.start()}function U(){var t=fn(m);!A||g||y||(Math.abs(t[0]-O[0])>Math.abs(t[1]-O[1])?y=!0:g=!0),O=t,v=!0,Or(),z()}function z(){var t;switch(d=O[0]-P[0],p=O[1]-P[1],b){case Rr:case Ir:w&&(d=Math.max(N-e,Math.min(T-l,d)),i=e+d,f=l+d),x&&(p=Math.max(S-o,Math.min(C-s,p)),u=o+p,h=s+p);break;case Dr:w<0?(d=Math.max(N-e,Math.min(T-e,d)),i=e+d,f=l):w>0&&(d=Math.max(N-l,Math.min(T-l,d)),i=e,f=l+d),x<0?(p=Math.max(S-o,Math.min(C-o,p)),u=o+p,h=s):x>0&&(p=Math.max(S-s,Math.min(C-s,p)),u=o,h=s+p);break;case Lr:w&&(i=Math.max(N,Math.min(T,e-d*w)),f=Math.max(N,Math.min(T,l+d*w))),x&&(u=Math.max(S,Math.min(C,o-p*x)),h=Math.max(S,Math.min(C,s+p*x)))}fn?1:t>=n?0:NaN};var ei=function(t){return 1===t.length&&(t=function(t){return function(n,e){return ni(t(n),e)}}(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}(ni);ei.right,ei.left;var ri=Array.prototype,ii=(ri.slice,ri.map,function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r1e-6)if(Math.abs(f*a-c*l)>1e-6&&i){var h=e-o,d=r-u,p=a*a+c*c,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(s),m=i*Math.tan((pi-Math.acos((p+s-v)/(2*g*y)))/2),_=m/y,b=m/g;Math.abs(_-1)>1e-6&&(this._+="L"+(t+_*l)+","+(n+_*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>l*d)+","+(this._x1=t+b*a)+","+(this._y1=n+b*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,l=n+a,f=1^o,s=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+l:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-l)>1e-6)&&(this._+="L"+c+","+l),e&&(s<0&&(s=s%vi+vi),s>gi?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=l):s>1e-6&&(this._+="A"+e+","+e+",0,"+ +(s>=pi)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var _i=mi;function bi(t){return t.source}function wi(t){return t.target}function xi(t){return t.radius}function Ei(t){return t.startAngle}function Mi(t){return t.endAngle}var ki=function(){var t=bi,n=wi,e=xi,r=Ei,i=Mi,o=null;function u(){var u,a=hi.call(arguments),c=t.apply(this,a),l=n.apply(this,a),f=+e.apply(this,(a[0]=c,a)),s=r.apply(this,a)-ci,h=i.apply(this,a)-ci,d=f*oi(s),p=f*ui(s),v=+e.apply(this,(a[0]=l,a)),g=r.apply(this,a)-ci,y=i.apply(this,a)-ci;if(o||(o=u=_i()),o.moveTo(d,p),o.arc(0,0,f,s,h),s===g&&h===y||(o.quadraticCurveTo(0,0,v*oi(g),v*ui(g)),o.arc(0,0,v,g,y)),o.quadraticCurveTo(0,0,d,p),o.closePath(),u)return o=null,u+""||null}return u.radius=function(t){return arguments.length?(e="function"==typeof t?t:di(+t),u):e},u.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:di(+t),u):r},u.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:di(+t),u):i},u.source=function(n){return arguments.length?(t=n,u):t},u.target=function(t){return arguments.length?(n=t,u):n},u.context=function(t){return arguments.length?(o=null==t?null:t,u):o},u};function Ni(){}function Si(t,n){var e=new Ni;if(t instanceof Ni)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i=r.length)return null!=t&&e.sort(t),null!=n?n(e):e;for(var c,l,f,s=-1,h=e.length,d=r[i++],p=Ti(),v=u();++sr.length)return e;var u,a=i[o-1];return null!=n&&o>=r.length?u=e.entries():(u=[],e.each(function(n,e){u.push({key:e,values:t(n,o)})})),null!=a?u.sort(function(t,n){return a(t.key,n.key)}):u}(o(t,0,Oi,Ii),0)},key:function(t){return r.push(t),e},sortKeys:function(t){return i[r.length-1]=t,e},sortValues:function(n){return t=n,e},rollup:function(t){return n=t,e}}};function Ai(){return{}}function Pi(t,n,e){t[n]=e}function Oi(){return Ti()}function Ii(t,n,e){t.set(n,e)}function Ri(){}var Di=Ti.prototype;function Li(t,n){var e=new Ri;if(t instanceof Ri)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=Xi.exec(t))?ro(parseInt(n[1],16)):(n=Gi.exec(t))?new ao(n[1],n[2],n[3],1):(n=Qi.exec(t))?new ao(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Zi.exec(t))?io(n[1],n[2],n[3],n[4]):(n=Ki.exec(t))?io(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Ji.exec(t))?co(n[1],n[2]/100,n[3]/100,1):(n=to.exec(t))?co(n[1],n[2]/100,n[3]/100,n[4]):no.hasOwnProperty(t)?ro(no[t]):"transparent"===t?new ao(NaN,NaN,NaN,0):null}function ro(t){return new ao(t>>16&255,t>>8&255,255&t,1)}function io(t,n,e,r){return r<=0&&(t=n=e=NaN),new ao(t,n,e,r)}function oo(t){return t instanceof Hi||(t=eo(t)),t?new ao((t=t.rgb()).r,t.g,t.b,t.opacity):new ao}function uo(t,n,e,r){return 1===arguments.length?oo(t):new ao(t,n,e,null==r?1:r)}function ao(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function co(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new fo(t,n,e,r)}function lo(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof fo)return new fo(t.h,t.s,t.l,t.opacity);if(t instanceof Hi||(t=eo(t)),!t)return new fo;if(t instanceof fo)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new fo(u,a,c,t.opacity)}(t):new fo(t,n,e,null==r?1:r)}function fo(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function so(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}qi(Hi,eo,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+""}}),qi(ao,uo,Bi(Hi,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new ao(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new ao(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),qi(fo,lo,Bi(Hi,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new fo(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new fo(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new ao(so(t>=240?t-240:t+120,i,r),so(t,i,r),so(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var ho=Math.PI/180,po=180/Math.PI,vo=.95047,go=1,yo=1.08883,mo=4/29,_o=6/29,bo=3*_o*_o,wo=_o*_o*_o;function xo(t){if(t instanceof Mo)return new Mo(t.l,t.a,t.b,t.opacity);if(t instanceof Ao){var n=t.h*ho;return new Mo(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof ao||(t=oo(t));var e=To(t.r),r=To(t.g),i=To(t.b),o=ko((.4124564*e+.3575761*r+.1804375*i)/vo),u=ko((.2126729*e+.7151522*r+.072175*i)/go);return new Mo(116*u-16,500*(o-u),200*(u-ko((.0193339*e+.119192*r+.9503041*i)/yo)),t.opacity)}function Eo(t,n,e,r){return 1===arguments.length?xo(t):new Mo(t,n,e,null==r?1:r)}function Mo(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function ko(t){return t>wo?Math.pow(t,1/3):t/bo+mo}function No(t){return t>_o?t*t*t:bo*(t-mo)}function So(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function To(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Co(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof Ao)return new Ao(t.h,t.c,t.l,t.opacity);t instanceof Mo||(t=xo(t));var n=Math.atan2(t.b,t.a)*po;return new Ao(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}(t):new Ao(t,n,e,null==r?1:r)}function Ao(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}qi(Mo,Eo,Bi(Hi,{brighter:function(t){return new Mo(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Mo(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=go*No(t),new ao(So(3.2404542*(n=vo*No(n))-1.5371385*t-.4985314*(e=yo*No(e))),So(-.969266*n+1.8760108*t+.041556*e),So(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),qi(Ao,Co,Bi(Hi,{brighter:function(t){return new Ao(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Ao(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return xo(this).rgb()}}));var Po=-.29227,Oo=-.90649,Io=1.97294,Ro=Io*Oo,Do=1.78277*Io,Lo=1.78277*Po- -.14861*Oo;function Uo(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof zo)return new zo(t.h,t.s,t.l,t.opacity);t instanceof ao||(t=oo(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Lo*r+Ro*n-Do*e)/(Lo+Ro-Do),o=r-i,u=(Io*(e-i)-Po*o)/Oo,a=Math.sqrt(u*u+o*o)/(Io*i*(1-i)),c=a?Math.atan2(u,o)*po-120:NaN;return new zo(c<0?c+360:c,a,i,t.opacity)}(t):new zo(t,n,e,null==r?1:r)}function zo(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}qi(zo,Uo,Bi(Hi,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new zo(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new zo(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*ho,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new ao(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(Po*r+Oo*i)),255*(n+e*(Io*r)),this.opacity)}}));var jo={value:function(){}};function Fo(){for(var t,n=0,e=arguments.length,r={};n=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Ko.hasOwnProperty(n)?{space:Ko[n],local:t}:t};var tu=function(t){var n=Jo(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===Zo&&n.documentElement.namespaceURI===Zo?n.createElement(t):n.createElementNS(e,t)}})(n)};function nu(){}var eu=function(t){return null==t?nu:function(){return this.querySelector(t)}};function ru(){return[]}var iu=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var ou=document.documentElement;if(!ou.matches){var uu=ou.webkitMatchesSelector||ou.msMatchesSelector||ou.mozMatchesSelector||ou.oMatchesSelector;iu=function(t){return function(){return uu.call(this,t)}}}}var au=iu,cu=function(t){return new Array(t.length)};function lu(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}lu.prototype={constructor:lu,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var fu="$";function su(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var pu=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function vu(t){return t.trim().split(/^|\s+/)}function gu(t){return t.classList||new yu(t)}function yu(t){this._node=t,this._names=vu(t.getAttribute("class")||"")}function mu(t,n){for(var e=gu(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function bu(){this.textContent=""}function wu(){this.innerHTML=""}function xu(){this.nextSibling&&this.parentNode.appendChild(this)}function Eu(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function Mu(){return null}function ku(){var t=this.parentNode;t&&t.removeChild(this)}function Nu(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function Su(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var Tu={},Cu=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(Tu={mouseenter:"mouseover",mouseleave:"mouseout"}));function Au(t,n,e){return t=Pu(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function Pu(t,n,e){return function(r){var i=Cu;Cu=r;try{t.call(this,this.__data__,n,e)}finally{Cu=i}}}function Ou(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=du);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):function(t,n){return t.style.getPropertyValue(n)||pu(t).getComputedStyle(t,null).getPropertyValue(n)}(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=vu(t+"");if(arguments.length<2){for(var r=gu(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?Iu:Ou,null==e&&(e=!1),r=0;rs}c.mouse("drag")}function v(){ju(Cu.view).on("mousemove.drag mouseup.drag",null),Gu(Cu.view,e),Wu(),c.mouse("end")}function g(){if(i.apply(this,arguments)){var t,n,e=Cu.changedTouches,r=o.apply(this,arguments),u=e.length;for(t=0;t=o?c=!0:(r=t.charCodeAt(u++))===ua?l=!0:r===aa&&(l=!0,t.charCodeAt(u)===ua&&++u),t.slice(i+1,n-1).replace(/""/g,'"')}for(;u=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(g+m)/2))?g=u:m=u,i=d,!(d=d[s=f<<1|l]))return i[s]=p,t;if(a=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===a&&e===c)return p.next=d,i?i[s]=p:t._root=p,t;do{i=i?i[s]=new Array(4):t._root=new Array(4),(l=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(g+m)/2))?g=u:m=u}while((s=f<<1|l)==(h=(c>=u)<<1|a>=o));return i[h]=d,i[s]=p,t}var sc=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i};function hc(t){return t[0]}function dc(t){return t[1]}function pc(t,n,e){var r=new vc(null==n?hc:n,null==e?dc:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function vc(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function gc(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var yc=pc.prototype=vc.prototype;function mc(t){return t.x+t.vx}function _c(t){return t.y+t.vy}yc.copy=function(){var t,n,e=new vc(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=gc(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=gc(n));return e},yc.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return fc(this.cover(n,e),n,e,t)},yc.addAll=function(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,l=1/0,f=-1/0,s=-1/0;for(e=0;ef&&(f=r),is&&(s=i));for(ft||t>i||r>n||n>o))return this;var u,a,c=i-e,l=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{(u=new Array(4))[a]=l,l=u}while(o=r+(c*=2),t>(i=e+c)||n>o);break;case 1:do{(u=new Array(4))[a]=l,l=u}while(o=r+(c*=2),(e=i-c)>t||n>o);break;case 2:do{(u=new Array(4))[a]=l,l=u}while(r=o-(c*=2),t>(i=e+c)||r>n);break;case 3:do{(u=new Array(4))[a]=l,l=u}while(r=o-(c*=2),(e=i-c)>t||r>n)}this._root&&this._root.length&&(this._root=l)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},yc.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},yc.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},yc.find=function(t,n,e){var r,i,o,u,a,c,l,f=this._x0,s=this._y0,h=this._x1,d=this._y1,p=[],v=this._root;for(v&&p.push(new sc(v,f,s,h,d)),null==e?e=1/0:(f=t-e,s=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>d||(u=c.x1)=y)<<1|t>=g)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-l],p[p.length-1-l]=c)}else{var m=t-+this._x.call(null,v.data),_=n-+this._y.call(null,v.data),b=m*m+_*_;if(b=(a=(p+g)/2))?p=a:g=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=d,!(d=d[s=f<<1|l]))return this;if(!d.length)break;(n[s+1&3]||n[s+2&3]||n[s+3&3])&&(e=n,h=s)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[s]=i:delete n[s],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},yc.removeAll=function(t){for(var n=0,e=t.length;nc+d||il+d||oa.index){var p=c-u.x-u.vx,v=l-u.y-u.vy,g=p*p+v*v;gt.r&&(t.r=t[n].r)}function a(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&n._call.call(null,t),n=n._next;--zc}()}finally{zc=0,function(){var t,n,e=Dc,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Dc=n);Lc=t,Jc(r)}(),Hc=0}}function Kc(){var t=$c.now(),n=t-Bc;n>qc&&(Yc-=n,Bc=t)}function Jc(t){zc||(jc&&(jc=clearTimeout(jc)),t-Hc>24?(t<1/0&&(jc=setTimeout(Zc,t-$c.now()-Yc)),Fc&&(Fc=clearInterval(Fc))):(Fc||(Bc=$c.now(),Fc=setInterval(Kc,qc)),zc=1,Vc(Zc)))}Gc.prototype=Qc.prototype={constructor:Gc,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Wc():+e)+(null==n?0:+n),this._next||Lc===this||(Lc?Lc._next=this:Dc=this,Lc=this),this._call=t,this._time=e,Jc()},stop:function(){this._call&&(this._call=null,this._time=1/0,Jc())}};function tl(t){return t.x}function nl(t){return t.y}var el,rl=10,il=Math.PI*(3-Math.sqrt(5)),ol=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,u=.6,a=Ec(),c=Qc(f),l=Uc("tick","end");function f(){s(),l.call("tick",n),e1?(null==e?a.remove(t):a.set(t,d(e)),n):a.get(t)},find:function(n,e,r){var i,o,u,a,c,l=0,f=t.length;for(null==r?r=1/0:r*=r,l=0;l1?(l.on(t,e),n):l.on(t)}}},ul=function(){var t,n,e,r,i=cc(-30),o=1,u=1/0,a=.81;function c(r){var i,o=t.length,u=pc(t,tl,nl).visitAfter(f);for(e=r,i=0;i=u)){(t.data!==n||t.next)&&(0===f&&(d+=(f=lc())*f),0===s&&(d+=(s=lc())*s),d1?r[0]+r.slice(2):r,+t.slice(e+1)]},sl=function(t){return(t=fl(Math.abs(t)))?t[1]:NaN},hl=function(t,n){var e=fl(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},dl={"":function(t,n){t=t.toPrecision(n);t:for(var e,r=t.length,i=1,o=-1;i0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return hl(100*t,n)},r:hl,s:function(t,n){var e=fl(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(el=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+fl(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},pl=/^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;function vl(t){return new gl(t)}function gl(t){if(!(n=pl.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],l=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,f="g"):dl[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=l,this.type=f}vl.prototype=gl.prototype,gl.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var yl,ml,_l,bl=function(t){return t},wl=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],xl=function(t){var n=t.grouping&&t.thousands?function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}}(t.grouping,t.thousands):bl,e=t.currency,r=t.decimal,i=t.numerals?function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}}(t.numerals):bl,o=t.percent||"%";function u(t){var u=(t=vl(t)).fill,a=t.align,c=t.sign,l=t.symbol,f=t.zero,s=t.width,h=t.comma,d=t.precision,p=t.type,v="$"===l?e[0]:"#"===l&&/[boxX]/.test(p)?"0"+p.toLowerCase():"",g="$"===l?e[1]:/[%p]/.test(p)?o:"",y=dl[p],m=!p||/[defgprs%]/.test(p);function _(t){var e,o,l,_=v,b=g;if("c"===p)b=y(t)+b,t="";else{var w=(t=+t)<0;if(t=y(Math.abs(t),d),w&&0==+t&&(w=!1),_=(w?"("===c?c:"-":"-"===c||"("===c?"":c)+_,b=("s"===p?wl[8+el/3]:"")+b+(w&&"("===c?")":""),m)for(e=-1,o=t.length;++e(l=t.charCodeAt(e))||l>57){b=(46===l?r+t.slice(e+1):t.slice(e))+b,t=t.slice(0,e);break}}h&&!f&&(t=n(t,1/0));var x=_.length+t.length+b.length,E=x>1)+_+t+b+E.slice(x);break;default:t=E+_+t+b}return i(t)}return d=null==d?p?6:12:/[gprs]/.test(p)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),_.toString=function(){return t+""},_}return{format:u,formatPrefix:function(t,n){var e=u(((t=vl(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(sl(n)/3))),i=Math.pow(10,-r),o=wl[8+r/3];return function(t){return e(i*t)+o}}}};function El(t){return yl=xl(t),ml=yl.format,_l=yl.formatPrefix,yl}El({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var Ml=function(t){return Math.max(0,-sl(Math.abs(t)))},kl=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(sl(n)/3)))-sl(Math.abs(t)))},Nl=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,sl(n)-sl(t))+1},Sl=function(){return new Tl};function Tl(){this.reset()}Tl.prototype={constructor:Tl,reset:function(){this.s=this.t=0},add:function(t){Al(Cl,t,this.t),Al(this,Cl.s,this.s),this.s?this.t+=Cl.t:this.s=Cl.t},valueOf:function(){return this.s}};var Cl=new Tl;function Al(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}var Pl=1e-6,Ol=Math.PI,Il=Ol/2,Rl=Ol/4,Dl=2*Ol,Ll=180/Ol,Ul=Ol/180,zl=Math.abs,jl=Math.atan,Fl=Math.atan2,ql=Math.cos,Bl=Math.ceil,Hl=Math.exp,Yl=(Math.floor,Math.log),$l=Math.pow,Vl=Math.sin,Wl=Math.sign||function(t){return t>0?1:t<0?-1:0},Xl=Math.sqrt,Gl=Math.tan;function Ql(t){return t>1?0:t<-1?Ol:Math.acos(t)}function Zl(t){return t>1?Il:t<-1?-Il:Math.asin(t)}function Kl(t){return(t=Vl(t/2))*t}function Jl(){}function tf(t,n){t&&ef.hasOwnProperty(t.type)&&ef[t.type](t,n)}var nf={Feature:function(t,n){tf(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r=0?1:-1,i=r*e,o=ql(n),u=Vl(n),a=ff*u,c=lf*o+a*ql(i),l=a*r*Vl(i);hf.add(Fl(l,c)),cf=t,lf=o,ff=u}var _f=function(t){return df.reset(),sf(t,pf),2*df};function bf(t){return[Fl(t[1],t[0]),Zl(t[2])]}function wf(t){var n=t[0],e=t[1],r=ql(e);return[r*ql(n),r*Vl(n),Vl(e)]}function xf(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Ef(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Mf(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function kf(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function Nf(t){var n=Xl(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var Sf,Tf,Cf,Af,Pf,Of,If,Rf,Df,Lf,Uf=Sl(),zf={point:jf,lineStart:qf,lineEnd:Bf,polygonStart:function(){zf.point=Hf,zf.lineStart=Yf,zf.lineEnd=$f,Uf.reset(),pf.polygonStart()},polygonEnd:function(){pf.polygonEnd(),zf.point=jf,zf.lineStart=qf,zf.lineEnd=Bf,hf<0?(Sf=-(Cf=180),Tf=-(Af=90)):Uf>Pl?Af=90:Uf<-Pl&&(Tf=-90),Lf[0]=Sf,Lf[1]=Cf}};function jf(t,n){Df.push(Lf=[Sf=t,Cf=t]),nAf&&(Af=n)}function Ff(t,n){var e=wf([t*Ul,n*Ul]);if(Rf){var r=Ef(Rf,e),i=Ef([r[1],-r[0],0],r);Nf(i),i=bf(i);var o,u=t-Pf,a=u>0?1:-1,c=i[0]*Ll*a,l=zl(u)>180;l^(a*PfAf&&(Af=o):l^(a*Pf<(c=(c+360)%360-180)&&cAf&&(Af=n)),l?tVf(Sf,Cf)&&(Cf=t):Vf(t,Cf)>Vf(Sf,Cf)&&(Sf=t):Cf>=Sf?(tCf&&(Cf=t)):t>Pf?Vf(Sf,t)>Vf(Sf,Cf)&&(Cf=t):Vf(t,Cf)>Vf(Sf,Cf)&&(Sf=t)}else Df.push(Lf=[Sf=t,Cf=t]);nAf&&(Af=n),Rf=e,Pf=t}function qf(){zf.point=Ff}function Bf(){Lf[0]=Sf,Lf[1]=Cf,zf.point=jf,Rf=null}function Hf(t,n){if(Rf){var e=t-Pf;Uf.add(zl(e)>180?e+(e>0?360:-360):e)}else Of=t,If=n;pf.point(t,n),Ff(t,n)}function Yf(){pf.lineStart()}function $f(){Hf(Of,If),pf.lineEnd(),zl(Uf)>Pl&&(Sf=-(Cf=180)),Lf[0]=Sf,Lf[1]=Cf,Rf=null}function Vf(t,n){return(n-=t)<0?n+360:n}function Wf(t,n){return t[0]-n[0]}function Xf(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:nVf(r[0],r[1])&&(r[1]=i[1]),Vf(i[0],r[1])>Vf(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(a=Vf(r[1],i[0]))>u&&(u=a,Sf=i[0],Cf=r[1])}return Df=Lf=null,Sf===1/0||Tf===1/0?[[NaN,NaN],[NaN,NaN]]:[[Sf,Tf],[Cf,Af]]},hs={sphere:Jl,point:ds,lineStart:vs,lineEnd:ms,polygonStart:function(){hs.lineStart=_s,hs.lineEnd=bs},polygonEnd:function(){hs.lineStart=vs,hs.lineEnd=ms}};function ds(t,n){t*=Ul;var e=ql(n*=Ul);ps(e*ql(t),e*Vl(t),Vl(n))}function ps(t,n,e){Zf+=(t-Zf)/++Gf,Kf+=(n-Kf)/Gf,Jf+=(e-Jf)/Gf}function vs(){hs.point=gs}function gs(t,n){t*=Ul;var e=ql(n*=Ul);cs=e*ql(t),ls=e*Vl(t),fs=Vl(n),hs.point=ys,ps(cs,ls,fs)}function ys(t,n){t*=Ul;var e=ql(n*=Ul),r=e*ql(t),i=e*Vl(t),o=Vl(n),u=Fl(Xl((u=ls*o-fs*i)*u+(u=fs*r-cs*o)*u+(u=cs*i-ls*r)*u),cs*r+ls*i+fs*o);Qf+=u,ts+=u*(cs+(cs=r)),ns+=u*(ls+(ls=i)),es+=u*(fs+(fs=o)),ps(cs,ls,fs)}function ms(){hs.point=ds}function _s(){hs.point=ws}function bs(){xs(us,as),hs.point=ds}function ws(t,n){us=t,as=n,t*=Ul,n*=Ul,hs.point=xs;var e=ql(n);cs=e*ql(t),ls=e*Vl(t),fs=Vl(n),ps(cs,ls,fs)}function xs(t,n){t*=Ul;var e=ql(n*=Ul),r=e*ql(t),i=e*Vl(t),o=Vl(n),u=ls*o-fs*i,a=fs*r-cs*o,c=cs*i-ls*r,l=Xl(u*u+a*a+c*c),f=Zl(l),s=l&&-f/l;rs+=s*u,is+=s*a,os+=s*c,Qf+=f,ts+=f*(cs+(cs=r)),ns+=f*(ls+(ls=i)),es+=f*(fs+(fs=o)),ps(cs,ls,fs)}var Es=function(t){Gf=Qf=Zf=Kf=Jf=ts=ns=es=rs=is=os=0,sf(t,hs);var n=rs,e=is,r=os,i=n*n+e*e+r*r;return i<1e-12&&(n=ts,e=ns,r=es,QfOl?t-Dl:t<-Ol?t+Dl:t,n]}function Ss(t,n,e){return(t%=Dl)?n||e?ks(Cs(t),As(n,e)):Cs(t):n||e?As(n,e):Ns}function Ts(t){return function(n,e){return[(n+=t)>Ol?n-Dl:n<-Ol?n+Dl:n,e]}}function Cs(t){var n=Ts(t);return n.invert=Ts(-t),n}function As(t,n){var e=ql(t),r=Vl(t),i=ql(n),o=Vl(n);function u(t,n){var u=ql(n),a=ql(t)*u,c=Vl(t)*u,l=Vl(n),f=l*e+a*r;return[Fl(c*i-f*o,a*e-l*r),Zl(f*i+c*o)]}return u.invert=function(t,n){var u=ql(n),a=ql(t)*u,c=Vl(t)*u,l=Vl(n),f=l*i-c*o;return[Fl(c*i+l*o,a*e+f*r),Zl(f*e-a*r)]},u}Ns.invert=Ns;var Ps=function(t){function n(n){return(n=t(n[0]*Ul,n[1]*Ul))[0]*=Ll,n[1]*=Ll,n}return t=Ss(t[0]*Ul,t[1]*Ul,t.length>2?t[2]*Ul:0),n.invert=function(n){return(n=t.invert(n[0]*Ul,n[1]*Ul))[0]*=Ll,n[1]*=Ll,n},n};function Os(t,n,e,r,i,o){if(e){var u=ql(n),a=Vl(n),c=r*e;null==i?(i=n+r*Dl,o=n-c/2):(i=Is(u,i),o=Is(u,o),(r>0?io)&&(i+=r*Dl));for(var l,f=i;r>0?f>o:f1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},Ls=function(t,n){return zl(t[0]-n[0])=0;--o)i.point((f=l[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}l=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}};function js(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r=0?1:-1,M=E*x,k=M>Ol,N=p*b;if(Fs.add(Fl(N*E*Vl(M),v*w+N*ql(M))),o+=k?x+E*Dl:x,k^h>=e^m>=e){var S=Ef(wf(s),wf(y));Nf(S);var T=Ef(i,S);Nf(T);var C=(k^x>=0?-1:1)*Zl(T[2]);(r>C||r===C&&(S[0]||S[1]))&&(u+=k^x>=0?1:-1)}}return(o<-Pl||on?1:t>=n?0:NaN};var Hs=function(t){return 1===t.length&&(t=function(t){return function(n,e){return Bs(t(n),e)}}(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}(Bs);Hs.right,Hs.left;var Ys=Array.prototype,$s=(Ys.slice,Ys.map,function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r=0;)for(n=(r=t[i]).length;--n>=0;)e[--u]=r[n];return e};var Ws=function(t,n,e,r){return function(i){var o,u,a,c=n(i),l=Ds(),f=n(l),s=!1,h={point:d,lineStart:v,lineEnd:g,polygonStart:function(){h.point=y,h.lineStart=m,h.lineEnd=_,u=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=v,h.lineEnd=g,u=Vs(u);var t=qs(o,r);u.length?(s||(i.polygonStart(),s=!0),zs(u,Gs,t,e,i)):t&&(s||(i.polygonStart(),s=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),s&&(i.polygonEnd(),s=!1),u=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){c.point(t,n)}function v(){h.point=p,c.lineStart()}function g(){h.point=d,c.lineEnd()}function y(t,n){a.push([t,n]),f.point(t,n)}function m(){f.lineStart(),a=[]}function _(){y(a[0][0],a[0][1]),f.lineEnd();var t,n,e,r,c=f.clean(),h=l.result(),d=h.length;if(a.pop(),o.push(a),a=null,d)if(1&c){if((n=(e=h[0]).length-1)>0){for(s||(i.polygonStart(),s=!0),i.lineStart(),t=0;t1&&2&c&&h.push(h.pop().concat(h.shift())),u.push(h.filter(Xs))}return h}};function Xs(t){return t.length>1}function Gs(t,n){return((t=t.x)[0]<0?t[1]-Il-Pl:Il-t[1])-((n=n.x)[0]<0?n[1]-Il-Pl:Il-n[1])}var Qs=Ws(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?Ol:-Ol,c=zl(o-e);zl(c-Ol)0?Il:-Il),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=Ol&&(zl(e-i)Pl?jl((Vl(n)*(o=ql(r))*Vl(e)-Vl(r)*(i=ql(n))*Vl(t))/(i*o*u)):(n+r)/2}(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*Il,r.point(-Ol,i),r.point(0,i),r.point(Ol,i),r.point(Ol,0),r.point(Ol,-i),r.point(0,-i),r.point(-Ol,-i),r.point(-Ol,0),r.point(-Ol,i);else if(zl(t[0]-n[0])>Pl){var o=t[0]0,i=zl(n)>Pl;function o(t,e){return ql(t)*ql(e)>n}function u(t,e,r){var i=[1,0,0],o=Ef(wf(t),wf(e)),u=xf(o,o),a=o[0],c=u-a*a;if(!c)return!r&&t;var l=n*u/c,f=-n*a/c,s=Ef(i,o),h=kf(i,l);Mf(h,kf(o,f));var d=s,p=xf(h,d),v=xf(d,d),g=p*p-v*(xf(h,h)-1);if(!(g<0)){var y=Xl(g),m=kf(d,(-p-y)/v);if(Mf(m,h),m=bf(m),!r)return m;var _,b=t[0],w=e[0],x=t[1],E=e[1];w0^m[1]<(zl(m[0]-b)Ol^(b<=m[0]&&m[0]<=w)){var N=kf(d,(-p+y)/v);return Mf(N,h),[m,bf(N)]}}}function a(n,e){var i=r?t:Ol-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return Ws(o,function(t){var n,e,c,l,f;return{lineStart:function(){l=c=!1,f=1},point:function(s,h){var d,p=[s,h],v=o(s,h),g=r?v?0:a(s,h):v?a(s+(s<0?Ol:-Ol),h):0;if(!n&&(l=c=v)&&t.lineStart(),v!==c&&(!(d=u(n,p))||Ls(n,d)||Ls(p,d))&&(p[0]+=Pl,p[1]+=Pl,v=o(p[0],p[1])),v!==c)f=0,v?(t.lineStart(),d=u(p,n),t.point(d[0],d[1])):(d=u(n,p),t.point(d[0],d[1]),t.lineEnd()),n=d;else if(i&&n&&r^v){var y;g&e||!(y=u(p,n,!0))||(f=0,r?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&Ls(n,p)||t.point(p[0],p[1]),n=p,c=v,e=g},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return f|(l&&c)<<1}}},function(n,r,i,o){Os(o,t,e,i,n,r)},r?[0,-t]:[-Ol,t-Ol])},Ks=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],l=0,f=1,s=n[0]-a,h=n[1]-c;if(u=e-a,s||!(u>0)){if(u/=s,s<0){if(u0){if(u>f)return;u>l&&(l=u)}if(u=i-a,s||!(u<0)){if(u/=s,s<0){if(u>f)return;u>l&&(l=u)}else if(s>0){if(u0)){if(u/=h,h<0){if(u0){if(u>f)return;u>l&&(l=u)}if(u=o-c,h||!(u<0)){if(u/=h,h<0){if(u>f)return;u>l&&(l=u)}else if(h>0){if(u0&&(t[0]=a+l*s,t[1]=c+l*h),f<1&&(n[0]=a+f*s,n[1]=c+f*h),!0}}}}},Js=1e9,th=-Js;function nh(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,l){var f=0,s=0;if(null==i||(f=u(i,a))!==(s=u(o,a))||c(i,o)<0^a>0)do{l.point(0===f||3===f?t:e,f>1?r:n)}while((f=(f+a+4)%4)!==s);else l.point(o[0],o[1])}function u(r,i){return zl(r[0]-t)0?0:3:zl(r[0]-e)0?2:1:zl(r[1]-n)0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){var c,l,f,s,h,d,p,v,g,y,m,_=u,b=Ds(),w={point:x,lineStart:function(){w.point=E,l&&l.push(f=[]);y=!0,g=!1,p=v=NaN},lineEnd:function(){c&&(E(s,h),d&&g&&b.rejoin(),c.push(b.result()));w.point=x,g&&_.lineEnd()},polygonStart:function(){_=b,c=[],l=[],m=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=l.length;er&&(h-o)*(r-u)>(d-u)*(t-o)&&++n:d<=r&&(h-o)*(r-u)<(d-u)*(t-o)&&--n;return n}(),e=m&&n,i=(c=Vs(c)).length;(e||i)&&(u.polygonStart(),e&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),i&&zs(c,a,n,o,u),u.polygonEnd());_=u,c=l=f=null}};function x(t,n){i(t,n)&&_.point(t,n)}function E(o,u){var a=i(o,u);if(l&&f.push([o,u]),y)s=o,h=u,d=a,y=!1,a&&(_.lineStart(),_.point(o,u));else if(a&&g)_.point(o,u);else{var c=[p=Math.max(th,Math.min(Js,p)),v=Math.max(th,Math.min(Js,v))],b=[o=Math.max(th,Math.min(Js,o)),u=Math.max(th,Math.min(Js,u))];Ks(c,b,t,n,e,r)?(g||(_.lineStart(),_.point(c[0],c[1])),_.point(b[0],b[1]),a||_.lineEnd(),m=!1):a&&(_.lineStart(),_.point(o,u),m=!1)}p=o,v=u,g=a}return w}}var eh,rh,ih,oh=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=nh(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},uh=Sl(),ah={sphere:Jl,point:Jl,lineStart:function(){ah.point=lh,ah.lineEnd=ch},lineEnd:Jl,polygonStart:Jl,polygonEnd:Jl};function ch(){ah.point=ah.lineEnd=Jl}function lh(t,n){eh=t*=Ul,rh=Vl(n*=Ul),ih=ql(n),ah.point=fh}function fh(t,n){t*=Ul;var e=Vl(n*=Ul),r=ql(n),i=zl(t-eh),o=ql(i),u=r*Vl(i),a=ih*e-rh*r*o,c=rh*e+ih*r*o;uh.add(Fl(Xl(u*u+a*a),c)),eh=t,rh=e,ih=r}var sh=function(t){return uh.reset(),sf(t,ah),+uh},hh=[null,null],dh={type:"LineString",coordinates:hh},ph=function(t,n){return hh[0]=t,hh[1]=n,sh(dh)},vh={Feature:function(t,n){return yh(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++rPl}).map(c)).concat($s(Bl(o/d)*d,i,d).filter(function(t){return zl(t%v)>Pl}).map(l))}return y.lines=function(){return m().map(function(t){return{type:"LineString",coordinates:t}})},y.outline=function(){return{type:"Polygon",coordinates:[f(r).concat(s(u).slice(1),f(e).reverse().slice(1),s(a).reverse().slice(1))]}},y.extent=function(t){return arguments.length?y.extentMajor(t).extentMinor(t):y.extentMinor()},y.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],u=+t[1][1],r>e&&(t=r,r=e,e=t),a>u&&(t=a,a=u,u=t),y.precision(g)):[[r,a],[e,u]]},y.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),y.precision(g)):[[n,o],[t,i]]},y.step=function(t){return arguments.length?y.stepMajor(t).stepMinor(t):y.stepMinor()},y.stepMajor=function(t){return arguments.length?(p=+t[0],v=+t[1],y):[p,v]},y.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],y):[h,d]},y.precision=function(h){return arguments.length?(g=+h,c=Mh(o,i,90),l=kh(n,t,g),f=Mh(a,u,90),s=kh(r,e,g),y):g},y.extentMajor([[-180,-90+Pl],[180,90-Pl]]).extentMinor([[-180,-80-Pl],[180,80+Pl]])}function Sh(){return Nh()()}var Th,Ch,Ah,Ph,Oh=function(t,n){var e=t[0]*Ul,r=t[1]*Ul,i=n[0]*Ul,o=n[1]*Ul,u=ql(r),a=Vl(r),c=ql(o),l=Vl(o),f=u*ql(e),s=u*Vl(e),h=c*ql(i),d=c*Vl(i),p=2*Zl(Xl(Kl(o-r)+u*c*Kl(i-e))),v=Vl(p),g=p?function(t){var n=Vl(t*=p)/v,e=Vl(p-t)/v,r=e*f+n*h,i=e*s+n*d,o=e*a+n*l;return[Fl(i,r)*Ll,Fl(o,Xl(r*r+i*i))*Ll]}:function(){return[e*Ll,r*Ll]};return g.distance=p,g},Ih=function(t){return t},Rh=Sl(),Dh=Sl(),Lh={point:Jl,lineStart:Jl,lineEnd:Jl,polygonStart:function(){Lh.lineStart=Uh,Lh.lineEnd=Fh},polygonEnd:function(){Lh.lineStart=Lh.lineEnd=Lh.point=Jl,Rh.add(zl(Dh)),Dh.reset()},result:function(){var t=Rh/2;return Rh.reset(),t}};function Uh(){Lh.point=zh}function zh(t,n){Lh.point=jh,Th=Ah=t,Ch=Ph=n}function jh(t,n){Dh.add(Ph*t-Ah*n),Ah=t,Ph=n}function Fh(){jh(Th,Ch)}var qh=Lh,Bh=1/0,Hh=Bh,Yh=-Bh,$h=Yh;var Vh,Wh,Xh,Gh,Qh={point:function(t,n){tYh&&(Yh=t);n$h&&($h=n)},lineStart:Jl,lineEnd:Jl,polygonStart:Jl,polygonEnd:Jl,result:function(){var t=[[Bh,Hh],[Yh,$h]];return Yh=$h=-(Hh=Bh=1/0),t}},Zh=0,Kh=0,Jh=0,td=0,nd=0,ed=0,rd=0,id=0,od=0,ud={point:ad,lineStart:cd,lineEnd:sd,polygonStart:function(){ud.lineStart=hd,ud.lineEnd=dd},polygonEnd:function(){ud.point=ad,ud.lineStart=cd,ud.lineEnd=sd},result:function(){var t=od?[rd/od,id/od]:ed?[td/ed,nd/ed]:Jh?[Zh/Jh,Kh/Jh]:[NaN,NaN];return Zh=Kh=Jh=td=nd=ed=rd=id=od=0,t}};function ad(t,n){Zh+=t,Kh+=n,++Jh}function cd(){ud.point=ld}function ld(t,n){ud.point=fd,ad(Xh=t,Gh=n)}function fd(t,n){var e=t-Xh,r=n-Gh,i=Xl(e*e+r*r);td+=i*(Xh+t)/2,nd+=i*(Gh+n)/2,ed+=i,ad(Xh=t,Gh=n)}function sd(){ud.point=ad}function hd(){ud.point=pd}function dd(){vd(Vh,Wh)}function pd(t,n){ud.point=vd,ad(Vh=Xh=t,Wh=Gh=n)}function vd(t,n){var e=t-Xh,r=n-Gh,i=Xl(e*e+r*r);td+=i*(Xh+t)/2,nd+=i*(Gh+n)/2,ed+=i,rd+=(i=Gh*t-Xh*n)*(Xh+t),id+=i*(Gh+n),od+=3*i,ad(Xh=t,Gh=n)}var gd=ud;function yd(t){this._context=t}yd.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,Dl)}},result:Jl};var md,_d,bd,wd,xd,Ed=Sl(),Md={point:Jl,lineStart:function(){Md.point=kd},lineEnd:function(){md&&Nd(_d,bd),Md.point=Jl},polygonStart:function(){md=!0},polygonEnd:function(){md=null},result:function(){var t=+Ed;return Ed.reset(),t}};function kd(t,n){Md.point=Nd,_d=wd=t,bd=xd=n}function Nd(t,n){wd-=t,xd-=n,Ed.add(Xl(wd*wd+xd*xd)),wd=t,xd=n}var Sd=Md;function Td(){this._string=[]}function Cd(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}Td.prototype={_radius:4.5,_circle:Cd(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=Cd(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}};var Ad=function(t,n){var e,r,i=4.5;function o(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),sf(t,e(r))),r.result()}return o.area=function(t){return sf(t,e(qh)),qh.result()},o.measure=function(t){return sf(t,e(Sd)),Sd.result()},o.bounds=function(t){return sf(t,e(Qh)),Qh.result()},o.centroid=function(t){return sf(t,e(gd)),gd.result()},o.projection=function(n){return arguments.length?(e=null==n?(t=null,Ih):(t=n).stream,o):t},o.context=function(t){return arguments.length?(r=null==t?(n=null,new Td):new yd(n=t),"function"!=typeof i&&r.pointRadius(i),o):n},o.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),o):i},o.projection(t).context(n)},Pd=function(t){return{stream:Od(t)}};function Od(t){return function(n){var e=new Id;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Id(){}function Rd(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),sf(e,t.stream(Qh)),n(Qh.result()),null!=r&&t.clipExtent(r),t}function Dd(t,n,e){return Rd(t,function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),u=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,a=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([u,a])},e)}function Ld(t,n,e){return Dd(t,[[0,0],n],e)}function Ud(t,n,e){return Rd(t,function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,u=-i*e[0][1];t.scale(150*i).translate([o,u])},e)}function zd(t,n,e){return Rd(t,function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],u=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,u])},e)}Id.prototype={constructor:Id,point:function(t,n){this.stream.point(t,n)},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()}};var jd=16,Fd=ql(30*Ul),qd=function(t,n){return+n?function(t,n){function e(r,i,o,u,a,c,l,f,s,h,d,p,v,g){var y=l-r,m=f-i,_=y*y+m*m;if(_>4*n&&v--){var b=u+h,w=a+d,x=c+p,E=Xl(b*b+w*w+x*x),M=Zl(x/=E),k=zl(zl(x)-1)n||zl((y*C+m*A)/_-.5)>.3||u*h+a*d+c*p2?t[2]%360*Ul:0,T()):[g*Ll,y*Ll,m*Ll]},k.precision=function(t){return arguments.length?(M=qd(S,E=t*t),C()):Xl(E)},k.fitExtent=function(t,n){return Dd(k,t,n)},k.fitSize=function(t,n){return Ld(k,t,n)},k.fitWidth=function(t,n){return Ud(k,t,n)},k.fitHeight=function(t,n){return zd(k,t,n)},function(){return n=t.apply(this,arguments),k.invert=n.invert&&N,T()}}function $d(t){var n=0,e=Ol/3,r=Yd(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*Ul,e=t[1]*Ul):[n*Ll,e*Ll]},i}function Vd(t,n){var e=Vl(t),r=(e+Vl(n))/2;if(zl(r)=.12&&i<.234&&r>=-.425&&r<-.214?a:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:u).invert(t)},f.stream=function(e){return t&&n===e?t:t=function(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i0?n<-Il+Pl&&(n=-Il+Pl):n>Il-Pl&&(n=Il-Pl);var e=i/$l(op(n),r);return[e*Vl(r*t),i-e*ql(r*t)]}return o.invert=function(t,n){var e=i-n,o=Wl(r)*Xl(t*t+e*e);return[Fl(t,zl(e))/r*Wl(e),2*jl($l(i/o,1/r))-Il]},o}var ap=function(){return $d(up).scale(109.5).parallels([30,30])};function cp(t,n){return[t,n]}cp.invert=cp;var lp=function(){return Hd(cp).scale(152.63)};function fp(t,n){var e=ql(t),r=t===n?Vl(t):(e-ql(n))/(n-t),i=e/r+t;if(zl(r)Pl&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]};var yp=function(){return Hd(gp).scale(175.295)};function mp(t,n){return[ql(n)*Vl(t),Vl(n)]}mp.invert=Zd(Zl);var _p=function(){return Hd(mp).scale(249.5).clipAngle(90+Pl)};function bp(t,n){var e=ql(n),r=1+ql(t)*e;return[e*Vl(t)/r,Vl(n)/r]}bp.invert=Zd(function(t){return 2*jl(t)});var wp=function(){return Hd(bp).scale(250).clipAngle(142)};function xp(t,n){return[Yl(Gl((Il+n)/2)),-t]}xp.invert=function(t,n){return[-n,2*jl(Hl(t))-Il]};var Ep=function(){var t=ip(xp),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)};function Mp(t,n){return t.parent===n.parent?1:2}function kp(t,n){return t+n.x}function Np(t,n){return Math.max(t,n.y)}var Sp=function(){var t=Mp,n=1,e=1,r=!1;function i(i){var o,u=0;i.eachAfter(function(n){var e=n.children;e?(n.x=function(t){return t.reduce(kp,0)/t.length}(e),n.y=function(t){return 1+t.reduce(Np,0)}(e)):(n.x=o?u+=t(n,o):0,n.y=0,o=n)});var a=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),l=a.x-t(a,c)/2,f=c.x+t(c,a)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-l)/(f-l)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i};function Tp(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function Cp(t,n){var e,r,i,o,u,a=new Ip(t),c=+t.value&&(a.value=t.value),l=[a];for(null==n&&(n=Ap);e=l.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)l.push(r=e.children[o]=new Ip(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(Op)}function Ap(t){return t.children}function Pp(t){t.data=t.data.data}function Op(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function Ip(t){this.data=t,this.depth=this.height=0,this.parent=null}Ip.prototype=Cp.prototype={constructor:Ip,count:function(){return this.eachAfter(Tp)},each:function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return Cp(this).eachBefore(Pp)}};var Rp=Array.prototype.slice;var Dp=function(t){for(var n,e,r=0,i=(t=function(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}(Rp.call(t))).length,o=[];r0&&e*e>r*r+i*i}function jp(t,n){for(var e=0;ee*e+r*r}function $p(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function Vp(t){this._=t,this.next=null,this.previous=null}function Wp(t){if(!(i=t.length))return 0;var n,e,r,i,o,u,a,c,l,f,s;if((n=t[0]).x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;Hp(e,n,r=t[2]),n=new Vp(n),e=new Vp(e),r=new Vp(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a0)throw new Error("cycle");return o}return e.id=function(n){return arguments.length?(t=Gp(n),e):t},e.parentId=function(t){return arguments.length?(n=Gp(t),e):n},e};function hv(t,n){return t.parent===n.parent?1:2}function dv(t){var n=t.children;return n?n[0]:t.t}function pv(t){var n=t.children;return n?n[n.length-1]:t.t}function vv(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function gv(t,n,e){return t.a.parent===n.parent?t.a:e}function yv(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}yv.prototype=Object.create(Ip.prototype);var mv=function(){var t=hv,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,u=new yv(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new yv(r[i],i)),e.parent=n;return(u.parent=new yv(null,0)).children=[u],u}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(u),r)i.eachBefore(a);else{var l=i,f=i,s=i;i.eachBefore(function(t){t.xf.x&&(f=t),t.depth>s.depth&&(s=t)});var h=l===f?1:t(l,f)/2,d=h-l.x,p=n/(f.x+h+d),v=e/(s.depth||1);i.eachBefore(function(t){t.x=(t.x+d)*p,t.y=t.depth*v})}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,u=n,a=e,c=o.parent.children[0],l=o.m,f=u.m,s=a.m,h=c.m;a=pv(a),o=dv(o),a&&o;)c=dv(c),(u=pv(u)).a=n,(i=a.z+s-o.z-l+t(a._,o._))>0&&(vv(gv(a,n,r),n,i),l+=i,f+=i),s+=a.m,l+=o.m,h+=c.m,f+=u.m;a&&!pv(u)&&(u.t=a,u.m+=s-f),o&&!dv(c)&&(c.t=o,c.m+=l-h,r=n)}return r}(n,i,n.parent.A||r[0])}function u(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function a(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},_v=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,l=t.value&&(i-e)/t.value;++ah&&(h=a),g=f*f*v,(d=Math.max(h/g,g/s))>p){f-=a;break}p=d}y.push(u={value:f,dice:c1?n:1)},e}(bv),Ev=function(){var t=xv,n=!1,e=1,r=1,i=[0],o=Qp,u=Qp,a=Qp,c=Qp,l=Qp;function f(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(s),i=[0],n&&t.eachBefore(rv),t}function s(n){var e=i[n.depth],r=n.x0+e,f=n.y0+e,s=n.x1-e,h=n.y1-e;s=e-1){var f=a[n];return f.x0=i,f.y0=o,f.x1=u,void(f.y1=c)}var s=l[n],h=r/2+s,d=n+1,p=e-1;for(;d>>1;l[v]c-o){var m=(i*y+u*g)/r;t(n,d,g,i,o,m,c),t(d,e,y,m,o,u,c)}else{var _=(o*y+c*g)/r;t(n,d,g,i,o,u,_),t(d,e,y,i,_,u,c)}}(0,c,t.value,n,e,r,i)},kv=function(t,n,e,r,i){(1&t.depth?_v:iv)(t,n,e,r,i)},Nv=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,l,f,s=-1,h=u.length,d=t.value;++s1?n:1)},e}(bv),Sv=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t};function Tv(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Cv(){}var Av="\\s*([+-]?\\d+)\\s*",Pv="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",Ov="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",Iv=/^#([0-9a-f]{3})$/,Rv=/^#([0-9a-f]{6})$/,Dv=new RegExp("^rgb\\("+[Av,Av,Av]+"\\)$"),Lv=new RegExp("^rgb\\("+[Ov,Ov,Ov]+"\\)$"),Uv=new RegExp("^rgba\\("+[Av,Av,Av,Pv]+"\\)$"),zv=new RegExp("^rgba\\("+[Ov,Ov,Ov,Pv]+"\\)$"),jv=new RegExp("^hsl\\("+[Pv,Ov,Ov]+"\\)$"),Fv=new RegExp("^hsla\\("+[Pv,Ov,Ov,Pv]+"\\)$"),qv={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,rebeccapurple:6697881,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};function Bv(t){var n;return t=(t+"").trim().toLowerCase(),(n=Iv.exec(t))?new Wv((n=parseInt(n[1],16))>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=Rv.exec(t))?Hv(parseInt(n[1],16)):(n=Dv.exec(t))?new Wv(n[1],n[2],n[3],1):(n=Lv.exec(t))?new Wv(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Uv.exec(t))?Yv(n[1],n[2],n[3],n[4]):(n=zv.exec(t))?Yv(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=jv.exec(t))?Gv(n[1],n[2]/100,n[3]/100,1):(n=Fv.exec(t))?Gv(n[1],n[2]/100,n[3]/100,n[4]):qv.hasOwnProperty(t)?Hv(qv[t]):"transparent"===t?new Wv(NaN,NaN,NaN,0):null}function Hv(t){return new Wv(t>>16&255,t>>8&255,255&t,1)}function Yv(t,n,e,r){return r<=0&&(t=n=e=NaN),new Wv(t,n,e,r)}function $v(t){return t instanceof Cv||(t=Bv(t)),t?new Wv((t=t.rgb()).r,t.g,t.b,t.opacity):new Wv}function Vv(t,n,e,r){return 1===arguments.length?$v(t):new Wv(t,n,e,null==r?1:r)}function Wv(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Xv(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Gv(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Zv(t,n,e,r)}function Qv(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof Zv)return new Zv(t.h,t.s,t.l,t.opacity);if(t instanceof Cv||(t=Bv(t)),!t)return new Zv;if(t instanceof Zv)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new Zv(u,a,c,t.opacity)}(t):new Zv(t,n,e,null==r?1:r)}function Zv(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Kv(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Sv(Cv,Bv,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),Sv(Wv,Vv,Tv(Cv,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Wv(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Wv(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+Xv(this.r)+Xv(this.g)+Xv(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),Sv(Zv,Qv,Tv(Cv,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Zv(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Zv(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new Wv(Kv(t>=240?t-240:t+120,i,r),Kv(t,i,r),Kv(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Jv=Math.PI/180,tg=180/Math.PI,ng=.96422,eg=1,rg=.82521,ig=4/29,og=6/29,ug=3*og*og,ag=og*og*og;function cg(t){if(t instanceof fg)return new fg(t.l,t.a,t.b,t.opacity);if(t instanceof yg){if(isNaN(t.h))return new fg(t.l,0,0,t.opacity);var n=t.h*Jv;return new fg(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof Wv||(t=$v(t));var e,r,i=pg(t.r),o=pg(t.g),u=pg(t.b),a=sg((.2225045*i+.7168786*o+.0606169*u)/eg);return i===o&&o===u?e=r=a:(e=sg((.4360747*i+.3850649*o+.1430804*u)/ng),r=sg((.0139322*i+.0971045*o+.7141733*u)/rg)),new fg(116*a-16,500*(e-a),200*(a-r),t.opacity)}function lg(t,n,e,r){return 1===arguments.length?cg(t):new fg(t,n,e,null==r?1:r)}function fg(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function sg(t){return t>ag?Math.pow(t,1/3):t/ug+ig}function hg(t){return t>og?t*t*t:ug*(t-ig)}function dg(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function pg(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function vg(t){if(t instanceof yg)return new yg(t.h,t.c,t.l,t.opacity);if(t instanceof fg||(t=cg(t)),0===t.a&&0===t.b)return new yg(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*tg;return new yg(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function gg(t,n,e,r){return 1===arguments.length?vg(t):new yg(t,n,e,null==r?1:r)}function yg(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}Sv(fg,lg,Tv(Cv,{brighter:function(t){return new fg(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new fg(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new Wv(dg(3.1338561*(n=ng*hg(n))-1.6168667*(t=eg*hg(t))-.4906146*(e=rg*hg(e))),dg(-.9787684*n+1.9161415*t+.033454*e),dg(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Sv(yg,gg,Tv(Cv,{brighter:function(t){return new yg(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new yg(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return cg(this).rgb()}}));var mg=-.29227,_g=-.90649,bg=1.97294,wg=bg*_g,xg=1.78277*bg,Eg=1.78277*mg- -.14861*_g;function Mg(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof kg)return new kg(t.h,t.s,t.l,t.opacity);t instanceof Wv||(t=$v(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Eg*r+wg*n-xg*e)/(Eg+wg-xg),o=r-i,u=(bg*(e-i)-mg*o)/_g,a=Math.sqrt(u*u+o*o)/(bg*i*(1-i)),c=a?Math.atan2(u,o)*tg-120:NaN;return new kg(c<0?c+360:c,a,i,t.opacity)}(t):new kg(t,n,e,null==r?1:r)}function kg(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Ng(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}Sv(kg,Mg,Tv(Cv,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new kg(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new kg(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Jv,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new Wv(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(mg*r+_g*i)),255*(n+e*(bg*r)),this.opacity)}}));var Sg=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r180||e<-180?e-360*Math.round(e/360):e):Cg(isNaN(t)?n:t)}function Og(t){return 1==(t=+t)?Ig:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):Cg(isNaN(n)?e:n)}}function Ig(t,n){var e=n-t;return e?Ag(t,e):Cg(isNaN(t)?n:t)}var Rg=function t(n){var e=Og(n);function r(t,n){var r=e((t=Vv(t)).r,(n=Vv(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=Ig(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function Dg(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;eo&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:Fg(e,r)})),o=Hg.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Fg(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Fg(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:Fg(t,e)},{i:a-2,x:Fg(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e1e-6)if(Math.abs(f*a-c*l)>1e-6&&i){var h=e-o,d=r-u,p=a*a+c*c,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(s),m=i*Math.tan((yy-Math.acos((p+s-v)/(2*g*y)))/2),_=m/y,b=m/g;Math.abs(_-1)>1e-6&&(this._+="L"+(t+_*l)+","+(n+_*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>l*d)+","+(this._x1=t+b*a)+","+(this._y1=n+b*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,l=n+a,f=1^o,s=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+l:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-l)>1e-6)&&(this._+="L"+c+","+l),e&&(s<0&&(s=s%my+my),s>_y?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=l):s>1e-6&&(this._+="A"+e+","+e+",0,"+ +(s>=yy)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var xy=wy,Ey=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e1&&ky(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}var Ty=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n=0;--n)l.push(t[r[o[n]][2]]);for(n=+a;na!=l>a&&u<(c-e)*(a-r)/(l-r)+e&&(f=!f),c=e,l=r;return f},Ay=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(g+m)/2))?g=u:m=u,i=d,!(d=d[s=f<<1|l]))return i[s]=p,t;if(a=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===a&&e===c)return p.next=d,i?i[s]=p:t._root=p,t;do{i=i?i[s]=new Array(4):t._root=new Array(4),(l=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(g+m)/2))?g=u:m=u}while((s=f<<1|l)==(h=(c>=u)<<1|a>=o));return i[h]=d,i[s]=p,t}var Oy=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i};function Iy(t){return t[0]}function Ry(t){return t[1]}function Dy(t,n,e){var r=new Ly(null==n?Iy:n,null==e?Ry:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ly(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Uy(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var zy=Dy.prototype=Ly.prototype;zy.copy=function(){var t,n,e=new Ly(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Uy(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=Uy(n));return e},zy.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Py(this.cover(n,e),n,e,t)},zy.addAll=function(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,l=1/0,f=-1/0,s=-1/0;for(e=0;ef&&(f=r),is&&(s=i));for(ft||t>i||r>n||n>o))return this;var u,a,c=i-e,l=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{(u=new Array(4))[a]=l,l=u}while(o=r+(c*=2),t>(i=e+c)||n>o);break;case 1:do{(u=new Array(4))[a]=l,l=u}while(o=r+(c*=2),(e=i-c)>t||n>o);break;case 2:do{(u=new Array(4))[a]=l,l=u}while(r=o-(c*=2),t>(i=e+c)||r>n);break;case 3:do{(u=new Array(4))[a]=l,l=u}while(r=o-(c*=2),(e=i-c)>t||r>n)}this._root&&this._root.length&&(this._root=l)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},zy.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},zy.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},zy.find=function(t,n,e){var r,i,o,u,a,c,l,f=this._x0,s=this._y0,h=this._x1,d=this._y1,p=[],v=this._root;for(v&&p.push(new Oy(v,f,s,h,d)),null==e?e=1/0:(f=t-e,s=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>d||(u=c.x1)=y)<<1|t>=g)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-l],p[p.length-1-l]=c)}else{var m=t-+this._x.call(null,v.data),_=n-+this._y.call(null,v.data),b=m*m+_*_;if(b=(a=(p+g)/2))?p=a:g=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=d,!(d=d[s=f<<1|l]))return this;if(!d.length)break;(n[s+1&3]||n[s+2&3]||n[s+3&3])&&(e=n,h=s)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[s]=i:delete n[s],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},zy.removeAll=function(t){for(var n=0,e=t.length;n=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(n){}t._active=NaN,$y(t)}function $y(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function Vy(t){if(null==t)t=1/0;else if(!((t=+t)>=1))throw new Error("invalid concurrency");return new qy(t)}qy.prototype=Vy.prototype={constructor:qy,defer:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("defer after await");if(null!=this._error)return this;var n=jy.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),By(this),this},abort:function(){return null==this._error&&Yy(this,new Error("abort")),this},await:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=function(n,e){t.apply(null,[n].concat(e))},$y(this),this},awaitAll:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=t,$y(this),this}};var Wy=function(){return Math.random()},Xy=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(Wy),Gy=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(Wy),Qy=function t(n){function e(){var t=Gy.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(Wy),Zy=function t(n){function e(t){return function(){for(var e=0,r=0;r=200&&r<300||304===r){if(i)try{n=i.call(e,c)}catch(t){return void u.call("error",e,t)}else n=c;u.call("load",e,n)}else u.call("error",e,t)}if("undefined"==typeof XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(t)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=c.ontimeout=h:c.onreadystatechange=function(t){c.readyState>3&&h(t)},c.onprogress=function(t){u.call("progress",e,t)},e={header:function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?a.get(t):(null==n?a.remove(t):a.set(t,n+""),e)},mimeType:function(t){return arguments.length?(r=null==t?null:t+"",e):r},responseType:function(t){return arguments.length?(o=t,e):o},timeout:function(t){return arguments.length?(s=+t,e):s},user:function(t){return arguments.length<1?l:(l=null==t?null:t+"",e)},password:function(t){return arguments.length<1?f:(f=null==t?null:t+"",e)},response:function(t){return i=t,e},get:function(t,n){return e.send("GET",t,n)},post:function(t,n){return e.send("POST",t,n)},send:function(n,i,h){return c.open(n,t,!0,l,f),null==r||a.has("accept")||a.set("accept",r+",*/*"),c.setRequestHeader&&a.each(function(t,n){c.setRequestHeader(n,t)}),null!=r&&c.overrideMimeType&&c.overrideMimeType(r),null!=o&&(c.responseType=o),s>0&&(c.timeout=s),null==h&&"function"==typeof i&&(h=i,i=null),null!=h&&1===h.length&&(h=function(t){return function(n,e){t(null==n?e:null)}}(h)),null!=h&&e.on("error",h).on("load",function(t){h(null,t)}),u.call("beforesend",e,c),c.send(null==i?null:i),e},abort:function(){return c.abort(),e},on:function(){var t=u.on.apply(u,arguments);return t===u?e:t}},null!=n){if("function"!=typeof n)throw new Error("invalid callback: "+n);return e.get(n)}return e};var rm=function(t,n){return function(e,r){var i=em(e).mimeType(t).response(n);if(null!=r){if("function"!=typeof r)throw new Error("invalid callback: "+r);return i.get(r)}return i}},im=rm("text/html",function(t){return document.createRange().createContextualFragment(t.responseText)}),om=rm("application/json",function(t){return JSON.parse(t.responseText)}),um=rm("text/plain",function(t){return t.responseText}),am=rm("application/xml",function(t){var n=t.responseXML;if(!n)throw new Error("parse error");return n}),cm=e(7),lm=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=em(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(function(t,n){return function(e){return t(e.responseText,n)}}(n,r=t)):r},o.row(r),i?o.get(i):o}};var fm=lm("text/csv",cm.c),sm=lm("text/tab-separated-values",cm.h),hm=function(t,n){return tn?1:t>=n?0:NaN},dm=function(t){return 1===t.length&&(t=function(t){return function(n,e){return hm(t(n),e)}}(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r>>1;t(n[o],e)>0?i=o:r=o+1}return r}}};var pm=dm(hm),vm=pm.right,gm=(pm.left,vm);var ym=function(t){return null===t?NaN:+t},mm=Array.prototype,_m=(mm.slice,mm.map,function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r0)return[t];if((r=n0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++a=0?(o>=bm?10:o>=wm?5:o>=xm?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=bm?10:o>=wm?5:o>=xm?2:1)}function km(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=bm?i*=10:o>=wm?i*=5:o>=xm&&(i*=2),n=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}};function Sm(){}function Tm(t,n){var e=new Sm;if(t instanceof Sm)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=Vm.exec(t))?n_(parseInt(n[1],16)):(n=Wm.exec(t))?new o_(n[1],n[2],n[3],1):(n=Xm.exec(t))?new o_(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Gm.exec(t))?e_(n[1],n[2],n[3],n[4]):(n=Qm.exec(t))?e_(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Zm.exec(t))?a_(n[1],n[2]/100,n[3]/100,1):(n=Km.exec(t))?a_(n[1],n[2]/100,n[3]/100,n[4]):Jm.hasOwnProperty(t)?n_(Jm[t]):"transparent"===t?new o_(NaN,NaN,NaN,0):null}function n_(t){return new o_(t>>16&255,t>>8&255,255&t,1)}function e_(t,n,e,r){return r<=0&&(t=n=e=NaN),new o_(t,n,e,r)}function r_(t){return t instanceof Bm||(t=t_(t)),t?new o_((t=t.rgb()).r,t.g,t.b,t.opacity):new o_}function i_(t,n,e,r){return 1===arguments.length?r_(t):new o_(t,n,e,null==r?1:r)}function o_(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function u_(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function a_(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new l_(t,n,e,r)}function c_(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof l_)return new l_(t.h,t.s,t.l,t.opacity);if(t instanceof Bm||(t=t_(t)),!t)return new l_;if(t instanceof l_)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new l_(u,a,c,t.opacity)}(t):new l_(t,n,e,null==r?1:r)}function l_(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function f_(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Fm(Bm,t_,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),Fm(o_,i_,qm(Bm,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new o_(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new o_(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+u_(this.r)+u_(this.g)+u_(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),Fm(l_,c_,qm(Bm,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new l_(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new l_(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new o_(f_(t>=240?t-240:t+120,i,r),f_(t,i,r),f_(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var s_=Math.PI/180,h_=180/Math.PI,d_=.96422,p_=1,v_=.82521,g_=4/29,y_=6/29,m_=3*y_*y_,__=y_*y_*y_;function b_(t){if(t instanceof x_)return new x_(t.l,t.a,t.b,t.opacity);if(t instanceof C_){if(isNaN(t.h))return new x_(t.l,0,0,t.opacity);var n=t.h*s_;return new x_(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof o_||(t=r_(t));var e,r,i=N_(t.r),o=N_(t.g),u=N_(t.b),a=E_((.2225045*i+.7168786*o+.0606169*u)/p_);return i===o&&o===u?e=r=a:(e=E_((.4360747*i+.3850649*o+.1430804*u)/d_),r=E_((.0139322*i+.0971045*o+.7141733*u)/v_)),new x_(116*a-16,500*(e-a),200*(a-r),t.opacity)}function w_(t,n,e,r){return 1===arguments.length?b_(t):new x_(t,n,e,null==r?1:r)}function x_(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function E_(t){return t>__?Math.pow(t,1/3):t/m_+g_}function M_(t){return t>y_?t*t*t:m_*(t-g_)}function k_(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function N_(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function S_(t){if(t instanceof C_)return new C_(t.h,t.c,t.l,t.opacity);if(t instanceof x_||(t=b_(t)),0===t.a&&0===t.b)return new C_(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*h_;return new C_(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function T_(t,n,e,r){return 1===arguments.length?S_(t):new C_(t,n,e,null==r?1:r)}function C_(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}Fm(x_,w_,qm(Bm,{brighter:function(t){return new x_(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new x_(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new o_(k_(3.1338561*(n=d_*M_(n))-1.6168667*(t=p_*M_(t))-.4906146*(e=v_*M_(e))),k_(-.9787684*n+1.9161415*t+.033454*e),k_(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Fm(C_,T_,qm(Bm,{brighter:function(t){return new C_(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new C_(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return b_(this).rgb()}}));var A_=-.29227,P_=-.90649,O_=1.97294,I_=O_*P_,R_=1.78277*O_,D_=1.78277*A_- -.14861*P_;function L_(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof U_)return new U_(t.h,t.s,t.l,t.opacity);t instanceof o_||(t=r_(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(D_*r+I_*n-R_*e)/(D_+I_-R_),o=r-i,u=(O_*(e-i)-A_*o)/P_,a=Math.sqrt(u*u+o*o)/(O_*i*(1-i)),c=a?Math.atan2(u,o)*h_-120:NaN;return new U_(c<0?c+360:c,a,i,t.opacity)}(t):new U_(t,n,e,null==r?1:r)}function U_(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function z_(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}Fm(U_,L_,qm(Bm,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new U_(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new U_(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*s_,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new o_(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(A_*r+P_*i)),255*(n+e*(O_*r)),this.opacity)}}));var j_=function(t){return function(){return t}};function F_(t,n){return function(e){return t+e*n}}function q_(t,n){var e=n-t;return e?F_(t,e>180||e<-180?e-360*Math.round(e/360):e):j_(isNaN(t)?n:t)}function B_(t){return 1==(t=+t)?H_:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):j_(isNaN(n)?e:n)}}function H_(t,n){var e=n-t;return e?F_(t,e):j_(isNaN(t)?n:t)}var Y_=function t(n){var e=B_(n);function r(t,n){var r=e((t=i_(t)).r,(n=i_(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=H_(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function $_(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:V_(e,r)})),o=X_.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:V_(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:V_(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:V_(t,e)},{i:a-2,x:V_(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e2?pb:db,r=i=null,f}function f(n){return(r||(r=e(o,u,c?function(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}(t):t,a)))(+n)}return f.invert=function(t){return(i||(i=e(u,o,hb,c?function(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}(n):n)))(+t)},f.domain=function(t){return arguments.length?(o=Rm.call(t,fb),l()):o.slice()},f.range=function(t){return arguments.length?(u=Dm.call(t),l()):u.slice()},f.rangeRound=function(t){return u=Dm.call(t),a=tb,l()},f.clamp=function(t){return arguments.length?(c=!!t,l()):c},f.interpolate=function(t){return arguments.length?(a=t,l()):a},l()}var yb=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},mb=function(t){return(t=yb(Math.abs(t)))?t[1]:NaN},_b=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function bb(t){return new wb(t)}function wb(t){if(!(n=_b.exec(t)))throw new Error("invalid format: "+t);var n;this.fill=n[1]||" ",this.align=n[2]||">",this.sign=n[3]||"-",this.symbol=n[4]||"",this.zero=!!n[5],this.width=n[6]&&+n[6],this.comma=!!n[7],this.precision=n[8]&&+n[8].slice(1),this.trim=!!n[9],this.type=n[10]||""}bb.prototype=wb.prototype,wb.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var xb,Eb,Mb,kb,Nb=function(t){t:for(var n,e=t.length,r=1,i=-1;r0){if(!+t[r])break t;i=0}}return i>0?t.slice(0,i)+t.slice(n+1):t},Sb=function(t,n){var e=yb(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},Tb={"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return Sb(100*t,n)},r:Sb,s:function(t,n){var e=yb(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(xb=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+yb(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},Cb=function(t){return t},Ab=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],Pb=function(t){var n=t.grouping&&t.thousands?function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}}(t.grouping,t.thousands):Cb,e=t.currency,r=t.decimal,i=t.numerals?function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}}(t.numerals):Cb,o=t.percent||"%";function u(t){var u=(t=bb(t)).fill,a=t.align,c=t.sign,l=t.symbol,f=t.zero,s=t.width,h=t.comma,d=t.precision,p=t.trim,v=t.type;"n"===v?(h=!0,v="g"):Tb[v]||(null==d&&(d=12),p=!0,v="g"),(f||"0"===u&&"="===a)&&(f=!0,u="0",a="=");var g="$"===l?e[0]:"#"===l&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",y="$"===l?e[1]:/[%p]/.test(v)?o:"",m=Tb[v],_=/[defgprs%]/.test(v);function b(t){var e,o,l,b=g,w=y;if("c"===v)w=m(t)+w,t="";else{var x=(t=+t)<0;if(t=m(Math.abs(t),d),p&&(t=Nb(t)),x&&0==+t&&(x=!1),b=(x?"("===c?c:"-":"-"===c||"("===c?"":c)+b,w=("s"===v?Ab[8+xb/3]:"")+w+(x&&"("===c?")":""),_)for(e=-1,o=t.length;++e(l=t.charCodeAt(e))||l>57){w=(46===l?r+t.slice(e+1):t.slice(e))+w,t=t.slice(0,e);break}}h&&!f&&(t=n(t,1/0));var E=b.length+t.length+w.length,M=E>1)+b+t+w+M.slice(E);break;default:t=M+b+t+w}return i(t)}return d=null==d?6:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),b.toString=function(){return t+""},b}return{format:u,formatPrefix:function(t,n){var e=u(((t=bb(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(mb(n)/3))),i=Math.pow(10,-r),o=Ab[8+r/3];return function(t){return e(i*t)+o}}}};!function(t){Eb=Pb(t),Mb=Eb.format,kb=Eb.formatPrefix}({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var Ob=function(t,n,e){var r,i=t[0],o=t[t.length-1],u=km(i,o,null==n?10:n);switch((e=bb(null==e?",f":e)).type){case"s":var a=Math.max(Math.abs(i),Math.abs(o));return null!=e.precision||isNaN(r=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(mb(n)/3)))-mb(Math.abs(t)))}(u,a))||(e.precision=r),kb(e,a);case"":case"e":case"g":case"p":case"r":null!=e.precision||isNaN(r=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,mb(n)-mb(t))+1}(u,Math.max(Math.abs(i),Math.abs(o))))||(e.precision=r-("e"===e.type));break;case"f":case"%":null!=e.precision||isNaN(r=function(t){return Math.max(0,-mb(Math.abs(t)))}(u))||(e.precision=r-2*("%"===e.type))}return Mb(e)};function Ib(t){var n=t.domain;return t.ticks=function(t){var e=n();return Em(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return Ob(n(),t,e)},t.nice=function(e){null==e&&(e=10);var r,i=n(),o=0,u=i.length-1,a=i[o],c=i[u];return c0?r=Mm(a=Math.floor(a/r)*r,c=Math.ceil(c/r)*r,e):r<0&&(r=Mm(a=Math.ceil(a*r)/r,c=Math.floor(c*r)/r,e)),r>0?(i[o]=Math.floor(a/r)*r,i[u]=Math.ceil(c/r)*r,n(i)):r<0&&(i[o]=Math.ceil(a*r)/r,i[u]=Math.floor(c*r)/r,n(i)),t},t}function Rb(){var t=gb(hb,V_);return t.copy=function(){return vb(t,Rb())},Ib(t)}function Db(){var t=[0,1];function n(t){return+t}return n.invert=n,n.domain=n.range=function(e){return arguments.length?(t=Rm.call(e,fb),n):t.slice()},n.copy=function(){return Db().domain(t)},Ib(n)}var Lb=function(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],u=t[i];return u0){for(;hc)break;v.push(s)}}else for(;h=1;--f)if(!((s=l*f)c)break;v.push(s)}}else v=Em(h,d,Math.min(d-h,p)).map(i);return o?v.reverse():v},t.tickFormat=function(n,o){if(null==o&&(o=10===e?".0e":","),"function"!=typeof o&&(o=Mb(o)),n===1/0)return o;null==n&&(n=10);var u=Math.max(1,e*n/t.ticks().length);return function(t){var n=t/i(Math.round(r(t)));return n*e0?e[i-1]:t[0],i=e?[r[e-1],n]:[r[u-1],r[u]]},o.copy=function(){return Xb().domain([t,n]).range(i)},Ib(o)}function Gb(){var t=[.5],n=[0,1],e=1;function r(r){if(r<=r)return n[gm(t,r,0,e)]}return r.domain=function(i){return arguments.length?(t=Dm.call(i),e=Math.min(t.length,n.length-1),r):t.slice()},r.range=function(i){return arguments.length?(n=Dm.call(i),e=Math.min(t.length,n.length-1),r):n.slice()},r.invertExtent=function(e){var r=n.indexOf(e);return[t[r-1],t[r]]},r.copy=function(){return Gb().domain(t).range(n)},r}var Qb=new Date,Zb=new Date;function Kb(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n0))return a;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(u=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return Qb.setTime(+n),Zb.setTime(+r),t(Qb),t(Zb),Math.floor(e(Qb,Zb))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var Jb=Kb(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});Jb.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Kb(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):Jb:null};var tw=Jb,nw=(Jb.range,6e4),ew=6048e5,rw=Kb(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),iw=rw,ow=(rw.range,Kb(function(t){t.setTime(Math.floor(t/nw)*nw)},function(t,n){t.setTime(+t+n*nw)},function(t,n){return(n-t)/nw},function(t){return t.getMinutes()})),uw=ow,aw=(ow.range,Kb(function(t){var n=t.getTimezoneOffset()*nw%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()})),cw=aw,lw=(aw.range,Kb(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*nw)/864e5},function(t){return t.getDate()-1})),fw=lw;lw.range;function sw(t){return Kb(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*nw)/ew})}var hw=sw(0),dw=sw(1),pw=sw(2),vw=sw(3),gw=sw(4),yw=sw(5),mw=sw(6),_w=(hw.range,dw.range,pw.range,vw.range,gw.range,yw.range,mw.range,Kb(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()})),bw=_w,ww=(_w.range,Kb(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()}));ww.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Kb(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var xw=ww,Ew=(ww.range,Kb(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*nw)},function(t,n){return(n-t)/nw},function(t){return t.getUTCMinutes()})),Mw=Ew,kw=(Ew.range,Kb(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()})),Nw=kw,Sw=(kw.range,Kb(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1})),Tw=Sw;Sw.range;function Cw(t){return Kb(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/ew})}var Aw=Cw(0),Pw=Cw(1),Ow=Cw(2),Iw=Cw(3),Rw=Cw(4),Dw=Cw(5),Lw=Cw(6),Uw=(Aw.range,Pw.range,Ow.range,Iw.range,Rw.range,Dw.range,Lw.range,Kb(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()})),zw=Uw,jw=(Uw.range,Kb(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()}));jw.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Kb(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Fw=jw;jw.range;function qw(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Bw(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Hw(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}var Yw,$w,Vw,Ww,Xw={"-":"",_:" ",0:"0"},Gw=/^\s*\d+/,Qw=/^%/,Zw=/[\\^$*+?|[\]().{}]/g;function Kw(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o68?1900:2e3),e+r[0].length):-1}function lx(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function fx(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function sx(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function hx(t,n,e){var r=Gw.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function dx(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function px(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function vx(t,n,e){var r=Gw.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function gx(t,n,e){var r=Gw.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function yx(t,n,e){var r=Gw.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function mx(t,n,e){var r=Qw.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function _x(t,n,e){var r=Gw.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function bx(t,n,e){var r=Gw.exec(n.slice(e));return r?(t.Q=1e3*+r[0],e+r[0].length):-1}function wx(t,n){return Kw(t.getDate(),n,2)}function xx(t,n){return Kw(t.getHours(),n,2)}function Ex(t,n){return Kw(t.getHours()%12||12,n,2)}function Mx(t,n){return Kw(1+fw.count(xw(t),t),n,3)}function kx(t,n){return Kw(t.getMilliseconds(),n,3)}function Nx(t,n){return kx(t,n)+"000"}function Sx(t,n){return Kw(t.getMonth()+1,n,2)}function Tx(t,n){return Kw(t.getMinutes(),n,2)}function Cx(t,n){return Kw(t.getSeconds(),n,2)}function Ax(t){var n=t.getDay();return 0===n?7:n}function Px(t,n){return Kw(hw.count(xw(t),t),n,2)}function Ox(t,n){var e=t.getDay();return t=e>=4||0===e?gw(t):gw.ceil(t),Kw(gw.count(xw(t),t)+(4===xw(t).getDay()),n,2)}function Ix(t){return t.getDay()}function Rx(t,n){return Kw(dw.count(xw(t),t),n,2)}function Dx(t,n){return Kw(t.getFullYear()%100,n,2)}function Lx(t,n){return Kw(t.getFullYear()%1e4,n,4)}function Ux(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Kw(n/60|0,"0",2)+Kw(n%60,"0",2)}function zx(t,n){return Kw(t.getUTCDate(),n,2)}function jx(t,n){return Kw(t.getUTCHours(),n,2)}function Fx(t,n){return Kw(t.getUTCHours()%12||12,n,2)}function qx(t,n){return Kw(1+Tw.count(Fw(t),t),n,3)}function Bx(t,n){return Kw(t.getUTCMilliseconds(),n,3)}function Hx(t,n){return Bx(t,n)+"000"}function Yx(t,n){return Kw(t.getUTCMonth()+1,n,2)}function $x(t,n){return Kw(t.getUTCMinutes(),n,2)}function Vx(t,n){return Kw(t.getUTCSeconds(),n,2)}function Wx(t){var n=t.getUTCDay();return 0===n?7:n}function Xx(t,n){return Kw(Aw.count(Fw(t),t),n,2)}function Gx(t,n){var e=t.getUTCDay();return t=e>=4||0===e?Rw(t):Rw.ceil(t),Kw(Rw.count(Fw(t),t)+(4===Fw(t).getUTCDay()),n,2)}function Qx(t){return t.getUTCDay()}function Zx(t,n){return Kw(Pw.count(Fw(t),t),n,2)}function Kx(t,n){return Kw(t.getUTCFullYear()%100,n,2)}function Jx(t,n){return Kw(t.getUTCFullYear()%1e4,n,4)}function tE(){return"+0000"}function nE(){return"%"}function eE(t){return+t}function rE(t){return Math.floor(+t/1e3)}!function(t){Yw=function(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,u=t.shortDays,a=t.months,c=t.shortMonths,l=tx(i),f=nx(i),s=tx(o),h=nx(o),d=tx(u),p=nx(u),v=tx(a),g=nx(a),y=tx(c),m=nx(c),_={a:function(t){return u[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return a[t.getMonth()]},c:null,d:wx,e:wx,f:Nx,H:xx,I:Ex,j:Mx,L:kx,m:Sx,M:Tx,p:function(t){return i[+(t.getHours()>=12)]},Q:eE,s:rE,S:Cx,u:Ax,U:Px,V:Ox,w:Ix,W:Rx,x:null,X:null,y:Dx,Y:Lx,Z:Ux,"%":nE},b={a:function(t){return u[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return a[t.getUTCMonth()]},c:null,d:zx,e:zx,f:Hx,H:jx,I:Fx,j:qx,L:Bx,m:Yx,M:$x,p:function(t){return i[+(t.getUTCHours()>=12)]},Q:eE,s:rE,S:Vx,u:Wx,U:Xx,V:Gx,w:Qx,W:Zx,x:null,X:null,y:Kx,Y:Jx,Z:tE,"%":nE},w={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=s.exec(n.slice(e));return r?(t.w=h[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=y.exec(n.slice(e));return r?(t.m=m[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=g[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,e,r){return M(t,n,e,r)},d:sx,e:sx,f:yx,H:dx,I:dx,j:hx,L:gx,m:fx,M:px,p:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.p=f[r[0].toLowerCase()],e+r[0].length):-1},Q:_x,s:bx,S:vx,u:rx,U:ix,V:ox,w:ex,W:ux,x:function(t,n,r){return M(t,e,n,r)},X:function(t,n,e){return M(t,r,n,e)},y:cx,Y:ax,Z:lx,"%":mx};function x(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,l=t.length;for(e instanceof Date||(e=new Date(+e));++a53)return null;"w"in o||(o.w=1),"Z"in o?(r=(i=(r=Bw(Hw(o.y))).getUTCDay())>4||0===i?Pw.ceil(r):Pw(r),r=Tw.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(r=(i=(r=n(Hw(o.y))).getDay())>4||0===i?dw.ceil(r):dw(r),r=fw.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?Bw(Hw(o.y)).getUTCDay():n(Hw(o.y)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,Bw(o)):n(o)}}function M(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=w[i in Xw?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return _.x=x(e,_),_.X=x(r,_),_.c=x(n,_),b.x=x(e,b),b.X=x(r,b),b.c=x(n,b),{format:function(t){var n=x(t+="",_);return n.toString=function(){return t},n},parse:function(t){var n=E(t+="",qw);return n.toString=function(){return t},n},utcFormat:function(t){var n=x(t+="",b);return n.toString=function(){return t},n},utcParse:function(t){var n=E(t,Bw);return n.toString=function(){return t},n}}}(t),$w=Yw.format,Yw.parse,Vw=Yw.utcFormat,Ww=Yw.utcParse}({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});Date.prototype.toISOString||Vw("%Y-%m-%dT%H:%M:%S.%LZ");+new Date("2000-01-01T00:00:00.000Z")||Ww("%Y-%m-%dT%H:%M:%S.%LZ");var iE=1e3,oE=60*iE,uE=60*oE,aE=24*uE,cE=7*aE,lE=30*aE,fE=365*aE;function sE(t){return new Date(t)}function hE(t){return t instanceof Date?+t:+new Date(+t)}function dE(t,n,e,r,i,o,u,a,c){var l=gb(hb,V_),f=l.invert,s=l.domain,h=c(".%L"),d=c(":%S"),p=c("%I:%M"),v=c("%I %p"),g=c("%a %d"),y=c("%b %d"),m=c("%B"),_=c("%Y"),b=[[u,1,iE],[u,5,5*iE],[u,15,15*iE],[u,30,30*iE],[o,1,oE],[o,5,5*oE],[o,15,15*oE],[o,30,30*oE],[i,1,uE],[i,3,3*uE],[i,6,6*uE],[i,12,12*uE],[r,1,aE],[r,2,2*aE],[e,1,cE],[n,1,lE],[n,3,3*lE],[t,1,fE]];function w(a){return(u(a)1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return ME.h=360*t-100,ME.s=1.5-1.5*n,ME.l=.8-.9*n,ME+""};function NE(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var SE=NE(gE("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),TE=NE(gE("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),CE=NE(gE("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),AE=NE(gE("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function PE(t){var n=0,e=1,r=!1;function i(i){var o=(i-n)/(e-n);return t(r?Math.max(0,Math.min(1,o)):o)}return i.domain=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.clamp=function(t){return arguments.length?(r=!!t,i):r},i.interpolator=function(n){return arguments.length?(t=n,i):t},i.copy=function(){return PE(t).domain([n,e]).clamp(r)},Ib(i)}var OE="http://www.w3.org/1999/xhtml",IE={svg:"http://www.w3.org/2000/svg",xhtml:OE,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},RE=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),IE.hasOwnProperty(n)?{space:IE[n],local:t}:t};var DE=function(t){var n=RE(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===OE&&n.documentElement.namespaceURI===OE?n.createElement(t):n.createElementNS(e,t)}})(n)};function LE(){}var UE=function(t){return null==t?LE:function(){return this.querySelector(t)}};function zE(){return[]}var jE=function(t){return null==t?zE:function(){return this.querySelectorAll(t)}},FE=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var qE=document.documentElement;if(!qE.matches){var BE=qE.webkitMatchesSelector||qE.msMatchesSelector||qE.mozMatchesSelector||qE.oMatchesSelector;FE=function(t){return function(){return BE.call(this,t)}}}}var HE=FE,YE=function(t){return new Array(t.length)};function $E(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}$E.prototype={constructor:$E,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var VE="$";function WE(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var QE=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function ZE(t,n){return t.style.getPropertyValue(n)||QE(t).getComputedStyle(t,null).getPropertyValue(n)}function KE(t){return t.trim().split(/^|\s+/)}function JE(t){return t.classList||new tM(t)}function tM(t){this._node=t,this._names=KE(t.getAttribute("class")||"")}function nM(t,n){for(var e=JE(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function rM(){this.textContent=""}function iM(){this.innerHTML=""}function oM(){this.nextSibling&&this.parentNode.appendChild(this)}function uM(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function aM(){return null}function cM(){var t=this.parentNode;t&&t.removeChild(this)}function lM(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function fM(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var sM={},hM=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(sM={mouseenter:"mouseover",mouseleave:"mouseout"}));function dM(t,n,e){return t=pM(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function pM(t,n,e){return function(r){var i=hM;hM=r;try{t.call(this,this.__data__,n,e)}finally{hM=i}}}function vM(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=GE);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):ZE(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=KE(t+"");if(arguments.length<2){for(var r=JE(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?gM:vM,null==e&&(e=!1),r=0;r1e-6)if(Math.abs(f*a-c*l)>1e-6&&i){var h=e-o,d=r-u,p=a*a+c*c,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(s),m=i*Math.tan((RM-Math.acos((p+s-v)/(2*g*y)))/2),_=m/y,b=m/g;Math.abs(_-1)>1e-6&&(this._+="L"+(t+_*l)+","+(n+_*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>l*d)+","+(this._x1=t+b*a)+","+(this._y1=n+b*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,l=n+a,f=1^o,s=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+l:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-l)>1e-6)&&(this._+="L"+c+","+l),e&&(s<0&&(s=s%DM+DM),s>LM?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=l):s>1e-6&&(this._+="A"+e+","+e+",0,"+ +(s>=RM)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var jM=zM,FM=function(t){return function(){return t}},qM=Math.abs,BM=Math.atan2,HM=Math.cos,YM=Math.max,$M=Math.min,VM=Math.sin,WM=Math.sqrt,XM=1e-12,GM=Math.PI,QM=GM/2,ZM=2*GM;function KM(t){return t>=1?QM:t<=-1?-QM:Math.asin(t)}function JM(t){return t.innerRadius}function tk(t){return t.outerRadius}function nk(t){return t.startAngle}function ek(t){return t.endAngle}function rk(t){return t&&t.padAngle}function ik(t,n,e,r,i,o,u){var a=t-e,c=n-r,l=(u?o:-o)/WM(a*a+c*c),f=l*c,s=-l*a,h=t+f,d=n+s,p=e+f,v=r+s,g=(h+p)/2,y=(d+v)/2,m=p-h,_=v-d,b=m*m+_*_,w=i-o,x=h*v-p*d,E=(_<0?-1:1)*WM(YM(0,w*w*b-x*x)),M=(x*_-m*E)/b,k=(-x*m-_*E)/b,N=(x*_+m*E)/b,S=(-x*m+_*E)/b,T=M-g,C=k-y,A=N-g,P=S-y;return T*T+C*C>A*A+P*P&&(M=N,k=S),{cx:M,cy:k,x01:-f,y01:-s,x11:M*(i/w-1),y11:k*(i/w-1)}}var ok=function(){var t=JM,n=tk,e=FM(0),r=null,i=nk,o=ek,u=rk,a=null;function c(){var c,l,f=+t.apply(this,arguments),s=+n.apply(this,arguments),h=i.apply(this,arguments)-QM,d=o.apply(this,arguments)-QM,p=qM(d-h),v=d>h;if(a||(a=c=jM()),sXM)if(p>ZM-XM)a.moveTo(s*HM(h),s*VM(h)),a.arc(0,0,s,h,d,!v),f>XM&&(a.moveTo(f*HM(d),f*VM(d)),a.arc(0,0,f,d,h,v));else{var g,y,m=h,_=d,b=h,w=d,x=p,E=p,M=u.apply(this,arguments)/2,k=M>XM&&(r?+r.apply(this,arguments):WM(f*f+s*s)),N=$M(qM(s-f)/2,+e.apply(this,arguments)),S=N,T=N;if(k>XM){var C=KM(k/f*VM(M)),A=KM(k/s*VM(M));(x-=2*C)>XM?(b+=C*=v?1:-1,w-=C):(x=0,b=w=(h+d)/2),(E-=2*A)>XM?(m+=A*=v?1:-1,_-=A):(E=0,m=_=(h+d)/2)}var P=s*HM(m),O=s*VM(m),I=f*HM(w),R=f*VM(w);if(N>XM){var D=s*HM(_),L=s*VM(_),U=f*HM(b),z=f*VM(b);if(pXM?function(t,n,e,r,i,o,u,a){var c=e-t,l=r-n,f=u-i,s=a-o,h=(f*(n-o)-s*(t-i))/(s*c-f*l);return[t+h*c,n+h*l]}(P,O,U,z,D,L,I,R):[I,R],F=P-j[0],q=O-j[1],B=D-j[0],H=L-j[1],Y=1/VM(function(t){return t>1?0:t<-1?GM:Math.acos(t)}((F*B+q*H)/(WM(F*F+q*q)*WM(B*B+H*H)))/2),$=WM(j[0]*j[0]+j[1]*j[1]);S=$M(N,(f-$)/(Y-1)),T=$M(N,(s-$)/(Y+1))}}E>XM?T>XM?(g=ik(U,z,P,O,s,T,v),y=ik(D,L,I,R,s,T,v),a.moveTo(g.cx+g.x01,g.cy+g.y01),TXM&&x>XM?S>XM?(g=ik(I,R,D,L,f,-S,v),y=ik(P,O,U,z,f,-S,v),a.lineTo(g.cx+g.x01,g.cy+g.y01),S=f;--s)a.point(g[s],y[s]);a.lineEnd(),a.areaEnd()}v&&(g[l]=+t(h,l,c),y[l]=+e(h,l,c),a.point(n?+n(h,l,c):g[l],r?+r(h,l,c):y[l]))}if(d)return a=null,d+""||null}function l(){return fk().defined(i).curve(u).context(o)}return c.x=function(e){return arguments.length?(t="function"==typeof e?e:FM(+e),n=null,c):t},c.x0=function(n){return arguments.length?(t="function"==typeof n?n:FM(+n),c):t},c.x1=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:FM(+t),c):n},c.y=function(t){return arguments.length?(e="function"==typeof t?t:FM(+t),r=null,c):e},c.y0=function(t){return arguments.length?(e="function"==typeof t?t:FM(+t),c):e},c.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:FM(+t),c):r},c.lineX0=c.lineY0=function(){return l().x(t).y(e)},c.lineY1=function(){return l().x(t).y(r)},c.lineX1=function(){return l().x(n).y(e)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:FM(!!t),c):i},c.curve=function(t){return arguments.length?(u=t,null!=o&&(a=u(o)),c):u},c.context=function(t){return arguments.length?(null==t?o=a=null:a=u(o=t),c):o},c},hk=function(t,n){return nt?1:n>=t?0:NaN},dk=function(t){return t},pk=function(){var t=dk,n=hk,e=null,r=FM(0),i=FM(ZM),o=FM(0);function u(u){var a,c,l,f,s,h=u.length,d=0,p=new Array(h),v=new Array(h),g=+r.apply(this,arguments),y=Math.min(ZM,Math.max(-ZM,i.apply(this,arguments)-g)),m=Math.min(Math.abs(y)/h,o.apply(this,arguments)),_=m*(y<0?-1:1);for(a=0;a0&&(d+=s);for(null!=n?p.sort(function(t,e){return n(v[t],v[e])}):null!=e&&p.sort(function(t,n){return e(u[t],u[n])}),a=0,l=d?(y-h*_)/d:0;a0?s*l:0)+_,v[c]={data:u[c],index:a,value:s,startAngle:g,endAngle:f,padAngle:m};return v}return u.value=function(n){return arguments.length?(t="function"==typeof n?n:FM(+n),u):t},u.sortValues=function(t){return arguments.length?(n=t,e=null,u):n},u.sort=function(t){return arguments.length?(e=t,n=null,u):e},u.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:FM(+t),u):r},u.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:FM(+t),u):i},u.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:FM(+t),u):o},u},vk=yk(ak);function gk(t){this._curve=t}function yk(t){function n(n){return new gk(t(n))}return n._curve=t,n}function mk(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(yk(t)):n()._curve},t}gk.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var _k=function(){return mk(fk().curve(vk))},bk=function(){var t=sk().curve(vk),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return mk(e())},delete t.lineX0,t.lineEndAngle=function(){return mk(r())},delete t.lineX1,t.lineInnerRadius=function(){return mk(i())},delete t.lineY0,t.lineOuterRadius=function(){return mk(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(yk(t)):n()._curve},t},wk=function(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]},xk=Array.prototype.slice;function Ek(t){return t.source}function Mk(t){return t.target}function kk(t){var n=Ek,e=Mk,r=ck,i=lk,o=null;function u(){var u,a=xk.call(arguments),c=n.apply(this,a),l=e.apply(this,a);if(o||(o=u=jM()),t(o,+r.apply(this,(a[0]=c,a)),+i.apply(this,a),+r.apply(this,(a[0]=l,a)),+i.apply(this,a)),u)return o=null,u+""||null}return u.source=function(t){return arguments.length?(n=t,u):n},u.target=function(t){return arguments.length?(e=t,u):e},u.x=function(t){return arguments.length?(r="function"==typeof t?t:FM(+t),u):r},u.y=function(t){return arguments.length?(i="function"==typeof t?t:FM(+t),u):i},u.context=function(t){return arguments.length?(o=null==t?null:t,u):o},u}function Nk(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function Sk(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function Tk(t,n,e,r,i){var o=wk(n,e),u=wk(n,e=(e+i)/2),a=wk(r,e),c=wk(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(u[0],u[1],a[0],a[1],c[0],c[1])}function Ck(){return kk(Nk)}function Ak(){return kk(Sk)}function Pk(){var t=kk(Tk);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t}var Ok={draw:function(t,n){var e=Math.sqrt(n/GM);t.moveTo(e,0),t.arc(0,0,e,0,ZM)}},Ik={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Rk=Math.sqrt(1/3),Dk=2*Rk,Lk={draw:function(t,n){var e=Math.sqrt(n/Dk),r=e*Rk;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},Uk=Math.sin(GM/10)/Math.sin(7*GM/10),zk=Math.sin(ZM/10)*Uk,jk=-Math.cos(ZM/10)*Uk,Fk={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=zk*e,i=jk*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=ZM*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},qk={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Bk=Math.sqrt(3),Hk={draw:function(t,n){var e=-Math.sqrt(n/(3*Bk));t.moveTo(0,2*e),t.lineTo(-Bk*e,-e),t.lineTo(Bk*e,-e),t.closePath()}},Yk=Math.sqrt(3)/2,$k=1/Math.sqrt(12),Vk=3*($k/2+1),Wk={draw:function(t,n){var e=Math.sqrt(n/Vk),r=e/2,i=e*$k,o=r,u=e*$k+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(-.5*r-Yk*i,Yk*r+-.5*i),t.lineTo(-.5*o-Yk*u,Yk*o+-.5*u),t.lineTo(-.5*a-Yk*c,Yk*a+-.5*c),t.lineTo(-.5*r+Yk*i,-.5*i-Yk*r),t.lineTo(-.5*o+Yk*u,-.5*u-Yk*o),t.lineTo(-.5*a+Yk*c,-.5*c-Yk*a),t.closePath()}},Xk=[Ok,Ik,Lk,qk,Fk,Hk,Wk],Gk=function(){var t=FM(Ok),n=FM(64),e=null;function r(){var r;if(e||(e=r=jM()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),r)return e=null,r+""||null}return r.type=function(n){return arguments.length?(t="function"==typeof n?n:FM(n),r):t},r.size=function(t){return arguments.length?(n="function"==typeof t?t:FM(+t),r):n},r.context=function(t){return arguments.length?(e=null==t?null:t,r):e},r},Qk=function(){};function Zk(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Kk(t){this._context=t}Kk.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Zk(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Zk(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var Jk=function(t){return new Kk(t)};function tN(t){this._context=t}tN.prototype={areaStart:Qk,areaEnd:Qk,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Zk(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var nN=function(t){return new tN(t)};function eN(t){this._context=t}eN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Zk(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};var rN=function(t){return new eN(t)};function iN(t,n){this._basis=new Kk(t),this._beta=n}iN.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var oN=function t(n){function e(t){return 1===n?new Kk(t):new iN(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function uN(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function aN(t,n){this._context=t,this._k=(1-n)/6}aN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:uN(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:uN(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var cN=function t(n){function e(t){return new aN(t,n)}return e.tension=function(n){return t(+n)},e}(0);function lN(t,n){this._context=t,this._k=(1-n)/6}lN.prototype={areaStart:Qk,areaEnd:Qk,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:uN(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var fN=function t(n){function e(t){return new lN(t,n)}return e.tension=function(n){return t(+n)},e}(0);function sN(t,n){this._context=t,this._k=(1-n)/6}sN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:uN(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var hN=function t(n){function e(t){return new sN(t,n)}return e.tension=function(n){return t(+n)},e}(0);function dN(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>XM){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>XM){var l=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*l+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*l+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function pN(t,n){this._context=t,this._alpha=n}pN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:dN(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var vN=function t(n){function e(t){return n?new pN(t,n):new aN(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function gN(t,n){this._context=t,this._alpha=n}gN.prototype={areaStart:Qk,areaEnd:Qk,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:dN(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var yN=function t(n){function e(t){return n?new gN(t,n):new lN(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function mN(t,n){this._context=t,this._alpha=n}mN.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:dN(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var _N=function t(n){function e(t){return n?new mN(t,n):new sN(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function bN(t){this._context=t}bN.prototype={areaStart:Qk,areaEnd:Qk,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};var wN=function(t){return new bN(t)};function xN(t){return t<0?-1:1}function EN(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(xN(o)+xN(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function MN(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function kN(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function NN(t){this._context=t}function SN(t){this._context=new TN(t)}function TN(t){this._context=t}function CN(t){return new NN(t)}function AN(t){return new SN(t)}function PN(t){this._context=t}function ON(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var DN=function(t){return new RN(t,.5)};function LN(t){return new RN(t,0)}function UN(t){return new RN(t,1)}var zN=function(t,n){if((i=t.length)>1)for(var e,r,i,o=1,u=t[n[0]],a=u.length;o=0;)e[n]=n;return e};function FN(t,n){return t[n]}var qN=function(){var t=FM([]),n=jN,e=zN,r=FN;function i(i){var o,u,a=t.apply(this,arguments),c=i.length,l=a.length,f=new Array(l);for(o=0;o0){for(var e,r,i,o=0,u=t[0].length;o1)for(var e,r,i,o,u,a,c=0,l=t[n[0]].length;c=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=u,r[0]=u+=i):r[0]=o},YN=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u0))return a;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(u=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return ZN.setTime(+n),KN.setTime(+r),t(ZN),t(KN),Math.floor(e(ZN,KN))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var tS=JN(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});tS.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?JN(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):tS:null};var nS=tS,eS=tS.range,rS=6e4,iS=6048e5,oS=JN(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),uS=oS,aS=oS.range,cS=JN(function(t){t.setTime(Math.floor(t/rS)*rS)},function(t,n){t.setTime(+t+n*rS)},function(t,n){return(n-t)/rS},function(t){return t.getMinutes()}),lS=cS,fS=cS.range,sS=JN(function(t){var n=t.getTimezoneOffset()*rS%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),hS=sS,dS=sS.range,pS=JN(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*rS)/864e5},function(t){return t.getDate()-1}),vS=pS,gS=pS.range;function yS(t){return JN(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*rS)/iS})}var mS=yS(0),_S=yS(1),bS=yS(2),wS=yS(3),xS=yS(4),ES=yS(5),MS=yS(6),kS=mS.range,NS=_S.range,SS=bS.range,TS=wS.range,CS=xS.range,AS=ES.range,PS=MS.range,OS=JN(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),IS=OS,RS=OS.range,DS=JN(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});DS.every=function(t){return isFinite(t=Math.floor(t))&&t>0?JN(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var LS=DS,US=DS.range,zS=JN(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*rS)},function(t,n){return(n-t)/rS},function(t){return t.getUTCMinutes()}),jS=zS,FS=zS.range,qS=JN(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),BS=qS,HS=qS.range,YS=JN(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),$S=YS,VS=YS.range;function WS(t){return JN(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/iS})}var XS=WS(0),GS=WS(1),QS=WS(2),ZS=WS(3),KS=WS(4),JS=WS(5),tT=WS(6),nT=XS.range,eT=GS.range,rT=QS.range,iT=ZS.range,oT=KS.range,uT=JS.range,aT=tT.range,cT=JN(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),lT=cT,fT=cT.range,sT=JN(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});sT.every=function(t){return isFinite(t=Math.floor(t))&&t>0?JN(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var hT=sT,dT=sT.range,pT=new Date,vT=new Date;function gT(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n0))return a;do{a.push(u=new Date(+e)),n(e,o),t(e)}while(u=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return pT.setTime(+n),vT.setTime(+r),t(pT),t(vT),Math.floor(e(pT,vT))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var yT=gT(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});yT.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?gT(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):yT:null};yT.range;var mT=6e4,_T=6048e5,bT=gT(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),wT=(bT.range,gT(function(t){t.setTime(Math.floor(t/mT)*mT)},function(t,n){t.setTime(+t+n*mT)},function(t,n){return(n-t)/mT},function(t){return t.getMinutes()})),xT=(wT.range,gT(function(t){var n=t.getTimezoneOffset()*mT%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()})),ET=(xT.range,gT(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*mT)/864e5},function(t){return t.getDate()-1})),MT=ET;ET.range;function kT(t){return gT(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*mT)/_T})}var NT=kT(0),ST=kT(1),TT=kT(2),CT=kT(3),AT=kT(4),PT=kT(5),OT=kT(6),IT=(NT.range,ST.range,TT.range,CT.range,AT.range,PT.range,OT.range,gT(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()})),RT=(IT.range,gT(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()}));RT.every=function(t){return isFinite(t=Math.floor(t))&&t>0?gT(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var DT=RT,LT=(RT.range,gT(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*mT)},function(t,n){return(n-t)/mT},function(t){return t.getUTCMinutes()})),UT=(LT.range,gT(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()})),zT=(UT.range,gT(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1})),jT=zT;zT.range;function FT(t){return gT(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/_T})}var qT=FT(0),BT=FT(1),HT=FT(2),YT=FT(3),$T=FT(4),VT=FT(5),WT=FT(6),XT=(qT.range,BT.range,HT.range,YT.range,$T.range,VT.range,WT.range,gT(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()})),GT=(XT.range,gT(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()}));GT.every=function(t){return isFinite(t=Math.floor(t))&&t>0?gT(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var QT=GT;GT.range;function ZT(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function KT(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function JT(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function tC(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,u=t.shortDays,a=t.months,c=t.shortMonths,l=hC(i),f=dC(i),s=hC(o),h=dC(o),d=hC(u),p=dC(u),v=hC(a),g=dC(a),y=hC(c),m=dC(c),_={a:function(t){return u[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return a[t.getMonth()]},c:null,d:IC,e:IC,f:zC,H:RC,I:DC,j:LC,L:UC,m:jC,M:FC,p:function(t){return i[+(t.getHours()>=12)]},Q:pA,s:vA,S:qC,u:BC,U:HC,V:YC,w:$C,W:VC,x:null,X:null,y:WC,Y:XC,Z:GC,"%":dA},b={a:function(t){return u[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return a[t.getUTCMonth()]},c:null,d:QC,e:QC,f:nA,H:ZC,I:KC,j:JC,L:tA,m:eA,M:rA,p:function(t){return i[+(t.getUTCHours()>=12)]},Q:pA,s:vA,S:iA,u:oA,U:uA,V:aA,w:cA,W:lA,x:null,X:null,y:fA,Y:sA,Z:hA,"%":dA},w={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=s.exec(n.slice(e));return r?(t.w=h[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=y.exec(n.slice(e));return r?(t.m=m[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=g[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,e,r){return M(t,n,e,r)},d:EC,e:EC,f:CC,H:kC,I:kC,j:MC,L:TC,m:xC,M:NC,p:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.p=f[r[0].toLowerCase()],e+r[0].length):-1},Q:PC,s:OC,S:SC,u:vC,U:gC,V:yC,w:pC,W:mC,x:function(t,n,r){return M(t,e,n,r)},X:function(t,n,e){return M(t,r,n,e)},y:bC,Y:_C,Z:wC,"%":AC};function x(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,l=t.length;for(e instanceof Date||(e=new Date(+e));++a53)return null;"w"in o||(o.w=1),"Z"in o?(r=(i=(r=KT(JT(o.y))).getUTCDay())>4||0===i?BT.ceil(r):BT(r),r=jT.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(r=(i=(r=n(JT(o.y))).getDay())>4||0===i?ST.ceil(r):ST(r),r=MT.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?KT(JT(o.y)).getUTCDay():n(JT(o.y)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,KT(o)):n(o)}}function M(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=w[i in uC?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return _.x=x(e,_),_.X=x(r,_),_.c=x(n,_),b.x=x(e,b),b.X=x(r,b),b.c=x(n,b),{format:function(t){var n=x(t+="",_);return n.toString=function(){return t},n},parse:function(t){var n=E(t+="",ZT);return n.toString=function(){return t},n},utcFormat:function(t){var n=x(t+="",b);return n.toString=function(){return t},n},utcParse:function(t){var n=E(t,KT);return n.toString=function(){return t},n}}}var nC,eC,rC,iC,oC,uC={"-":"",_:" ",0:"0"},aC=/^\s*\d+/,cC=/^%/,lC=/[\\^$*+?|[\]().{}]/g;function fC(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o68?1900:2e3),e+r[0].length):-1}function wC(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function xC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function EC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function MC(t,n,e){var r=aC.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function kC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function NC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function SC(t,n,e){var r=aC.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function TC(t,n,e){var r=aC.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function CC(t,n,e){var r=aC.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function AC(t,n,e){var r=cC.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function PC(t,n,e){var r=aC.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function OC(t,n,e){var r=aC.exec(n.slice(e));return r?(t.Q=1e3*+r[0],e+r[0].length):-1}function IC(t,n){return fC(t.getDate(),n,2)}function RC(t,n){return fC(t.getHours(),n,2)}function DC(t,n){return fC(t.getHours()%12||12,n,2)}function LC(t,n){return fC(1+MT.count(DT(t),t),n,3)}function UC(t,n){return fC(t.getMilliseconds(),n,3)}function zC(t,n){return UC(t,n)+"000"}function jC(t,n){return fC(t.getMonth()+1,n,2)}function FC(t,n){return fC(t.getMinutes(),n,2)}function qC(t,n){return fC(t.getSeconds(),n,2)}function BC(t){var n=t.getDay();return 0===n?7:n}function HC(t,n){return fC(NT.count(DT(t),t),n,2)}function YC(t,n){var e=t.getDay();return t=e>=4||0===e?AT(t):AT.ceil(t),fC(AT.count(DT(t),t)+(4===DT(t).getDay()),n,2)}function $C(t){return t.getDay()}function VC(t,n){return fC(ST.count(DT(t),t),n,2)}function WC(t,n){return fC(t.getFullYear()%100,n,2)}function XC(t,n){return fC(t.getFullYear()%1e4,n,4)}function GC(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+fC(n/60|0,"0",2)+fC(n%60,"0",2)}function QC(t,n){return fC(t.getUTCDate(),n,2)}function ZC(t,n){return fC(t.getUTCHours(),n,2)}function KC(t,n){return fC(t.getUTCHours()%12||12,n,2)}function JC(t,n){return fC(1+jT.count(QT(t),t),n,3)}function tA(t,n){return fC(t.getUTCMilliseconds(),n,3)}function nA(t,n){return tA(t,n)+"000"}function eA(t,n){return fC(t.getUTCMonth()+1,n,2)}function rA(t,n){return fC(t.getUTCMinutes(),n,2)}function iA(t,n){return fC(t.getUTCSeconds(),n,2)}function oA(t){var n=t.getUTCDay();return 0===n?7:n}function uA(t,n){return fC(qT.count(QT(t),t),n,2)}function aA(t,n){var e=t.getUTCDay();return t=e>=4||0===e?$T(t):$T.ceil(t),fC($T.count(QT(t),t)+(4===QT(t).getUTCDay()),n,2)}function cA(t){return t.getUTCDay()}function lA(t,n){return fC(BT.count(QT(t),t),n,2)}function fA(t,n){return fC(t.getUTCFullYear()%100,n,2)}function sA(t,n){return fC(t.getUTCFullYear()%1e4,n,4)}function hA(){return"+0000"}function dA(){return"%"}function pA(t){return+t}function vA(t){return Math.floor(+t/1e3)}function gA(t){return nC=tC(t),eC=nC.format,rC=nC.parse,iC=nC.utcFormat,oC=nC.utcParse,nC}gA({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var yA=Date.prototype.toISOString?function(t){return t.toISOString()}:iC("%Y-%m-%dT%H:%M:%S.%LZ");var mA,_A,bA=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:oC("%Y-%m-%dT%H:%M:%S.%LZ"),wA=0,xA=0,EA=0,MA=1e3,kA=0,NA=0,SA=0,TA="object"==typeof performance&&performance.now?performance:Date,CA="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function AA(){return NA||(CA(PA),NA=TA.now()+SA)}function PA(){NA=0}function OA(){this._call=this._time=this._next=null}function IA(t,n,e){var r=new OA;return r.restart(t,n,e),r}function RA(){AA(),++wA;for(var t,n=mA;n;)(t=NA-n._time)>=0&&n._call.call(null,t),n=n._next;--wA}function DA(){NA=(kA=TA.now())+SA,wA=xA=0;try{RA()}finally{wA=0,function(){var t,n,e=mA,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:mA=n);_A=t,UA(r)}(),NA=0}}function LA(){var t=TA.now(),n=t-kA;n>MA&&(SA-=n,kA=t)}function UA(t){wA||(xA&&(xA=clearTimeout(xA)),t-NA>24?(t<1/0&&(xA=setTimeout(DA,t-TA.now()-SA)),EA&&(EA=clearInterval(EA))):(EA||(kA=TA.now(),EA=setInterval(LA,MA)),wA=1,CA(DA)))}OA.prototype=IA.prototype={constructor:OA,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?AA():+e)+(null==n?0:+n),this._next||_A===this||(_A?_A._next=this:mA=this,_A=this),this._call=t,this._time=e,UA()},stop:function(){this._call&&(this._call=null,this._time=1/0,UA())}};var zA=function(t,n,e){var r=new OA;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},jA=function(t,n,e){var r=new OA,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?AA():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},FA="http://www.w3.org/1999/xhtml",qA={svg:"http://www.w3.org/2000/svg",xhtml:FA,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},BA=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),qA.hasOwnProperty(n)?{space:qA[n],local:t}:t};var HA=function(t){var n=BA(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===FA&&n.documentElement.namespaceURI===FA?n.createElement(t):n.createElementNS(e,t)}})(n)};function YA(){}var $A=function(t){return null==t?YA:function(){return this.querySelector(t)}};function VA(){return[]}var WA=function(t){return null==t?VA:function(){return this.querySelectorAll(t)}},XA=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var GA=document.documentElement;if(!GA.matches){var QA=GA.webkitMatchesSelector||GA.msMatchesSelector||GA.mozMatchesSelector||GA.oMatchesSelector;XA=function(t){return function(){return QA.call(this,t)}}}}var ZA=XA,KA=function(t){return new Array(t.length)};function JA(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}JA.prototype={constructor:JA,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var tP="$";function nP(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var iP=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function oP(t,n){return t.style.getPropertyValue(n)||iP(t).getComputedStyle(t,null).getPropertyValue(n)}function uP(t){return t.trim().split(/^|\s+/)}function aP(t){return t.classList||new cP(t)}function cP(t){this._node=t,this._names=uP(t.getAttribute("class")||"")}function lP(t,n){for(var e=aP(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function sP(){this.textContent=""}function hP(){this.innerHTML=""}function dP(){this.nextSibling&&this.parentNode.appendChild(this)}function pP(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function vP(){return null}function gP(){var t=this.parentNode;t&&t.removeChild(this)}function yP(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function mP(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var _P={},bP=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(_P={mouseenter:"mouseover",mouseleave:"mouseout"}));function wP(t,n,e){return t=xP(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function xP(t,n,e){return function(r){var i=bP;bP=r;try{t.call(this,this.__data__,n,e)}finally{bP=i}}}function EP(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=rP);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):oP(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=uP(t+"");if(arguments.length<2){for(var r=aP(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?MP:EP,null==e&&(e=!1),r=0;r=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&n._call.call(null,t),n=n._next;--FP}()}finally{FP=0,function(){var t,n,e=UP,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:UP=n);zP=t,nO(r)}(),$P=0}}function tO(){var t=WP.now(),n=t-YP;n>HP&&(VP-=n,YP=t)}function nO(t){FP||(qP&&(qP=clearTimeout(qP)),t-$P>24?(t<1/0&&(qP=setTimeout(JP,t-WP.now()-VP)),BP&&(BP=clearInterval(BP))):(BP||(YP=WP.now(),BP=setInterval(tO,HP)),FP=1,XP(JP)))}ZP.prototype=KP.prototype={constructor:ZP,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?GP():+e)+(null==n?0:+n),this._next||zP===this||(zP?zP._next=this:UP=this,zP=this),this._call=t,this._time=e,nO()},stop:function(){this._call&&(this._call=null,this._time=1/0,nO())}};var eO=function(t,n,e){var r=new ZP;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},rO=jP("start","end","interrupt"),iO=[],oO=0,uO=1,aO=2,cO=3,lO=4,fO=5,sO=6,hO=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(c){var l,f,s,h;if(e.state!==uO)return a();for(l in i)if((h=i[l]).name===e.name){if(h.state===cO)return eO(o);h.state===lO?(h.state=sO,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[l]):+loO)throw new Error("too late; already scheduled");return e}function pO(t,n){var e=vO(t,n);if(e.state>aO)throw new Error("too late; already started");return e}function vO(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}var gO=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>aO&&e.state>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=xO.exec(t))?PO(parseInt(n[1],16)):(n=EO.exec(t))?new DO(n[1],n[2],n[3],1):(n=MO.exec(t))?new DO(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=kO.exec(t))?OO(n[1],n[2],n[3],n[4]):(n=NO.exec(t))?OO(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=SO.exec(t))?UO(n[1],n[2]/100,n[3]/100,1):(n=TO.exec(t))?UO(n[1],n[2]/100,n[3]/100,n[4]):CO.hasOwnProperty(t)?PO(CO[t]):"transparent"===t?new DO(NaN,NaN,NaN,0):null}function PO(t){return new DO(t>>16&255,t>>8&255,255&t,1)}function OO(t,n,e,r){return r<=0&&(t=n=e=NaN),new DO(t,n,e,r)}function IO(t){return t instanceof _O||(t=AO(t)),t?new DO((t=t.rgb()).r,t.g,t.b,t.opacity):new DO}function RO(t,n,e,r){return 1===arguments.length?IO(t):new DO(t,n,e,null==r?1:r)}function DO(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function LO(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function UO(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new jO(t,n,e,r)}function zO(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof jO)return new jO(t.h,t.s,t.l,t.opacity);if(t instanceof _O||(t=AO(t)),!t)return new jO;if(t instanceof jO)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new jO(u,a,c,t.opacity)}(t):new jO(t,n,e,null==r?1:r)}function jO(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function FO(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}yO(_O,AO,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),yO(DO,RO,mO(_O,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new DO(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new DO(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+LO(this.r)+LO(this.g)+LO(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),yO(jO,zO,mO(_O,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new jO(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new jO(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new DO(FO(t>=240?t-240:t+120,i,r),FO(t,i,r),FO(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var qO=Math.PI/180,BO=180/Math.PI,HO=.96422,YO=1,$O=.82521,VO=4/29,WO=6/29,XO=3*WO*WO,GO=WO*WO*WO;function QO(t){if(t instanceof KO)return new KO(t.l,t.a,t.b,t.opacity);if(t instanceof oI){if(isNaN(t.h))return new KO(t.l,0,0,t.opacity);var n=t.h*qO;return new KO(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof DO||(t=IO(t));var e,r,i=eI(t.r),o=eI(t.g),u=eI(t.b),a=JO((.2225045*i+.7168786*o+.0606169*u)/YO);return i===o&&o===u?e=r=a:(e=JO((.4360747*i+.3850649*o+.1430804*u)/HO),r=JO((.0139322*i+.0971045*o+.7141733*u)/$O)),new KO(116*a-16,500*(e-a),200*(a-r),t.opacity)}function ZO(t,n,e,r){return 1===arguments.length?QO(t):new KO(t,n,e,null==r?1:r)}function KO(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function JO(t){return t>GO?Math.pow(t,1/3):t/XO+VO}function tI(t){return t>WO?t*t*t:XO*(t-VO)}function nI(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function eI(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function rI(t){if(t instanceof oI)return new oI(t.h,t.c,t.l,t.opacity);if(t instanceof KO||(t=QO(t)),0===t.a&&0===t.b)return new oI(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*BO;return new oI(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function iI(t,n,e,r){return 1===arguments.length?rI(t):new oI(t,n,e,null==r?1:r)}function oI(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}yO(KO,ZO,mO(_O,{brighter:function(t){return new KO(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new KO(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new DO(nI(3.1338561*(n=HO*tI(n))-1.6168667*(t=YO*tI(t))-.4906146*(e=$O*tI(e))),nI(-.9787684*n+1.9161415*t+.033454*e),nI(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),yO(oI,iI,mO(_O,{brighter:function(t){return new oI(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new oI(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return QO(this).rgb()}}));var uI=-.29227,aI=-.90649,cI=1.97294,lI=cI*aI,fI=1.78277*cI,sI=1.78277*uI- -.14861*aI;function hI(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof dI)return new dI(t.h,t.s,t.l,t.opacity);t instanceof DO||(t=IO(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(sI*r+lI*n-fI*e)/(sI+lI-fI),o=r-i,u=(cI*(e-i)-uI*o)/aI,a=Math.sqrt(u*u+o*o)/(cI*i*(1-i)),c=a?Math.atan2(u,o)*BO-120:NaN;return new dI(c<0?c+360:c,a,i,t.opacity)}(t):new dI(t,n,e,null==r?1:r)}function dI(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function pI(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}yO(dI,hI,mO(_O,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new dI(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new dI(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*qO,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new DO(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(uI*r+aI*i)),255*(n+e*(cI*r)),this.opacity)}}));var vI=function(t){return function(){return t}};function gI(t,n){return function(e){return t+e*n}}function yI(t,n){var e=n-t;return e?gI(t,e>180||e<-180?e-360*Math.round(e/360):e):vI(isNaN(t)?n:t)}function mI(t){return 1==(t=+t)?_I:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):vI(isNaN(n)?e:n)}}function _I(t,n){var e=n-t;return e?gI(t,e):vI(isNaN(t)?n:t)}var bI=function t(n){var e=mI(n);function r(t,n){var r=e((t=RO(t)).r,(n=RO(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=_I(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function wI(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:xI(e,r)})),o=MI.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:xI(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:xI(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:xI(t,e)},{i:a-2,x:xI(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?dO:pO;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}(e,t,n))},attr:function(t,n){var e=BA(t),r="transform"===e?DI:FI;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}})(e,r,jI(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}:function(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}})(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=BA(t);return this.tween(e,(r.local?function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}:function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?RI:FI;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=oP(this,t),u=(this.style.removeProperty(t),oP(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}(t,r)).on("end.style."+t,function(t){return function(){this.style.removeProperty(t)}}(t)):this.styleTween(t,"function"==typeof n?function(t,n,e){var r,i,o;return function(){var u=oP(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=oP(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}(t,r,jI(this,"style."+t,n)):function(t,n,e){var r,i;return function(){var o=oP(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(jI(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=vO(this.node(),e).tween,o=0,u=i.length;ouO&&e.name===n)return new HI([[t]],QI,n,+r);return null},KI=function(t){return function(){return t}};function JI(t){return t[0]}function tR(t){return t[1]}function nR(){this._=null}function eR(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function rR(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function iR(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function oR(t){for(;t.L;)t=t.L;return t}nR.prototype={constructor:nR,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=oR(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(rR(this,e),e=(t=e).U),e.C=!1,r.C=!0,iR(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(iR(this,e),e=(t=e).U),e.C=!1,r.C=!0,rR(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?oR(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,rR(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,iR(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,rR(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,iR(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,rR(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,iR(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var uR=nR;function aR(t,n,e,r){var i=[null,null],o=CR.push(i)-1;return i.left=t,i.right=n,e&&lR(i,t,n,e),r&&lR(i,n,t,r),SR[t.index].halfedges.push(o),SR[n.index].halfedges.push(o),i}function cR(t,n,e){var r=[n,e];return r.left=t,r}function lR(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function fR(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],l=u[1],f=0,s=1,h=a[0]-c,d=a[1]-l;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o0){if(o>s)return;o>f&&(f=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>s)return;o>f&&(f=o)}else if(h>0){if(o0)){if(o/=d,d<0){if(o0){if(o>s)return;o>f&&(f=o)}if(o=i-l,d||!(o<0)){if(o/=d,d<0){if(o>s)return;o>f&&(f=o)}else if(d>0){if(o0||s<1)||(f>0&&(t[0]=[c+f*h,l+f*d]),s<1&&(t[1]=[c+s*h,l+s*d]),!0)}}}}}function sR(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],l=t.left,f=t.right,s=l[0],h=l[1],d=f[0],p=f[1],v=(s+d)/2,g=(h+p)/2;if(p===h){if(v=r)return;if(s>d){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]1)if(s>d){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]=-PR)){var d=c*c+l*l,p=f*f+s*s,v=(s*d-l*p)/h,g=(c*p-f*d)/h,y=gR.pop()||new function(){eR(this),this.x=this.y=this.arc=this.site=this.cy=null};y.arc=t,y.site=i,y.x=v+u,y.y=(y.cy=g+a)+Math.sqrt(v*v+g*g),t.circle=y;for(var m=null,_=TR._;_;)if(y.y<_.y||y.y===_.y&&y.x<=_.x){if(!_.L){m=_.P;break}_=_.L}else{if(!_.R){m=_;break}_=_.R}TR.insert(m,y),m||(vR=y)}}}}function mR(t){var n=t.circle;n&&(n.P||(vR=n.N),TR.remove(n),gR.push(n),eR(n),t.circle=null)}var _R=[];function bR(t){var n=_R.pop()||new function(){eR(this),this.edge=this.site=this.circle=null};return n.site=t,n}function wR(t){mR(t),NR.remove(t),_R.push(t),eR(t)}function xR(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];wR(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)AR)a=a.L;else{if(!((i=o-kR(a,u))>AR)){r>-AR?(n=a.P,e=a):i>-AR?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}!function(t){SR[t.index]={site:t,halfedges:[]}}(t);var c=bR(t);if(NR.insert(n,c),n||e){if(n===e)return mR(n),e=bR(n.site),NR.insert(c,e),c.edge=e.edge=aR(n.site,c.site),yR(n),void yR(e);if(e){mR(n),mR(e);var l=n.site,f=l[0],s=l[1],h=t[0]-f,d=t[1]-s,p=e.site,v=p[0]-f,g=p[1]-s,y=2*(h*g-d*v),m=h*h+d*d,_=v*v+g*g,b=[(g*m-d*_)/y+f,(h*_-v*m)/y+s];lR(e.edge,l,p,b),c.edge=aR(l,t,null,b),e.edge=aR(t,p,null,b),yR(n),yR(e)}else c.edge=aR(n.site,c.site)}}function MR(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-1/0;var a=(e=u.site)[0],c=e[1],l=c-n;if(!l)return a;var f=a-r,s=1/o-1/l,h=f/l;return s?(-h+Math.sqrt(h*h-2*s*(f*f/(-2*l)-c+l/2+i-o/2)))/s+r:(r+a)/2}function kR(t,n){var e=t.N;if(e)return MR(e,n);var r=t.site;return r[1]===n?r[0]:1/0}var NR,SR,TR,CR,AR=1e-6,PR=1e-12;function OR(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function IR(t,n){return n[1]-t[1]||n[0]-t[0]}function RR(t,n){var e,r,i,o=t.sort(IR).pop();for(CR=[],SR=new Array(t.length),NR=new uR,TR=new uR;;)if(i=vR,o&&(!i||o[1]AR||Math.abs(i[0][1]-i[1][1])>AR)||delete CR[o]}(u,a,c,l),function(t,n,e,r){var i,o,u,a,c,l,f,s,h,d,p,v,g=SR.length,y=!0;for(i=0;iAR||Math.abs(v-h)>AR)&&(c.splice(a,0,CR.push(cR(u,d,Math.abs(p-t)AR?[t,Math.abs(s-t)AR?[Math.abs(h-r)AR?[e,Math.abs(s-e)AR?[Math.abs(h-n)=a)return null;var c=t-i.site[0],l=n-i.site[1],f=c*c+l*l;do{i=o.cells[r=u],u=null,i.halfedges.forEach(function(e){var r=o.edges[e],a=r.left;if(a!==i.site&&a||(a=r.right)){var c=t-a[0],l=n-a[1],s=c*c+l*l;s=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}(t+"",r),o=-1,u=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o0)for(var e,r,i=new Array(e),o=0;o=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),HR.hasOwnProperty(n)?{space:HR[n],local:t}:t};var $R=function(t){var n=YR(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===BR&&n.documentElement.namespaceURI===BR?n.createElement(t):n.createElementNS(e,t)}})(n)};function VR(){}var WR=function(t){return null==t?VR:function(){return this.querySelector(t)}};function XR(){return[]}var GR=function(t){return null==t?XR:function(){return this.querySelectorAll(t)}},QR=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var ZR=document.documentElement;if(!ZR.matches){var KR=ZR.webkitMatchesSelector||ZR.msMatchesSelector||ZR.mozMatchesSelector||ZR.oMatchesSelector;QR=function(t){return function(){return KR.call(this,t)}}}}var JR=QR,tD=function(t){return new Array(t.length)};function nD(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}nD.prototype={constructor:nD,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var eD="$";function rD(t,n,e,r,i,o){for(var u,a=0,c=n.length,l=o.length;an?1:t>=n?0:NaN}var uD=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};function aD(t,n){return t.style.getPropertyValue(n)||uD(t).getComputedStyle(t,null).getPropertyValue(n)}function cD(t){return t.trim().split(/^|\s+/)}function lD(t){return t.classList||new fD(t)}function fD(t){this._node=t,this._names=cD(t.getAttribute("class")||"")}function sD(t,n){for(var e=lD(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};function dD(){this.textContent=""}function pD(){this.innerHTML=""}function vD(){this.nextSibling&&this.parentNode.appendChild(this)}function gD(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function yD(){return null}function mD(){var t=this.parentNode;t&&t.removeChild(this)}function _D(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function bD(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}var wD={},xD=null;"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(wD={mouseenter:"mouseover",mouseleave:"mouseout"}));function ED(t,n,e){return t=MD(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function MD(t,n,e){return function(r){var i=xD;xD=r;try{t.call(this,this.__data__,n,e)}finally{xD=i}}}function kD(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=b&&(b=_+1);!(m=g[b])&&++b=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=oD);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):aD(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=cD(t+"");if(arguments.length<2){for(var r=lD(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),u=o.length;if(!(arguments.length<2)){for(a=n?ND:kD,null==e&&(e=!1),r=0;r>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=XD.exec(t))?rL(parseInt(n[1],16)):(n=GD.exec(t))?new aL(n[1],n[2],n[3],1):(n=QD.exec(t))?new aL(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=ZD.exec(t))?iL(n[1],n[2],n[3],n[4]):(n=KD.exec(t))?iL(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=JD.exec(t))?lL(n[1],n[2]/100,n[3]/100,1):(n=tL.exec(t))?lL(n[1],n[2]/100,n[3]/100,n[4]):nL.hasOwnProperty(t)?rL(nL[t]):"transparent"===t?new aL(NaN,NaN,NaN,0):null}function rL(t){return new aL(t>>16&255,t>>8&255,255&t,1)}function iL(t,n,e,r){return r<=0&&(t=n=e=NaN),new aL(t,n,e,r)}function oL(t){return t instanceof VD||(t=eL(t)),t?new aL((t=t.rgb()).r,t.g,t.b,t.opacity):new aL}function uL(t,n,e,r){return 1===arguments.length?oL(t):new aL(t,n,e,null==r?1:r)}function aL(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function cL(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function lL(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new sL(t,n,e,r)}function fL(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof sL)return new sL(t.h,t.s,t.l,t.opacity);if(t instanceof VD||(t=eL(t)),!t)return new sL;if(t instanceof sL)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&c<1?0:u,new sL(u,a,c,t.opacity)}(t):new sL(t,n,e,null==r?1:r)}function sL(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function hL(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}YD(VD,eL,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),YD(aL,uL,$D(VD,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new aL(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new aL(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+cL(this.r)+cL(this.g)+cL(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),YD(sL,fL,$D(VD,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new sL(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new sL(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new aL(hL(t>=240?t-240:t+120,i,r),hL(t,i,r),hL(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var dL=Math.PI/180,pL=180/Math.PI,vL=.96422,gL=1,yL=.82521,mL=4/29,_L=6/29,bL=3*_L*_L,wL=_L*_L*_L;function xL(t){if(t instanceof ML)return new ML(t.l,t.a,t.b,t.opacity);if(t instanceof PL){if(isNaN(t.h))return new ML(t.l,0,0,t.opacity);var n=t.h*dL;return new ML(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof aL||(t=oL(t));var e,r,i=TL(t.r),o=TL(t.g),u=TL(t.b),a=kL((.2225045*i+.7168786*o+.0606169*u)/gL);return i===o&&o===u?e=r=a:(e=kL((.4360747*i+.3850649*o+.1430804*u)/vL),r=kL((.0139322*i+.0971045*o+.7141733*u)/yL)),new ML(116*a-16,500*(e-a),200*(a-r),t.opacity)}function EL(t,n,e,r){return 1===arguments.length?xL(t):new ML(t,n,e,null==r?1:r)}function ML(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function kL(t){return t>wL?Math.pow(t,1/3):t/bL+mL}function NL(t){return t>_L?t*t*t:bL*(t-mL)}function SL(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function TL(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function CL(t){if(t instanceof PL)return new PL(t.h,t.c,t.l,t.opacity);if(t instanceof ML||(t=xL(t)),0===t.a&&0===t.b)return new PL(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*pL;return new PL(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function AL(t,n,e,r){return 1===arguments.length?CL(t):new PL(t,n,e,null==r?1:r)}function PL(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}YD(ML,EL,$D(VD,{brighter:function(t){return new ML(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new ML(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new aL(SL(3.1338561*(n=vL*NL(n))-1.6168667*(t=gL*NL(t))-.4906146*(e=yL*NL(e))),SL(-.9787684*n+1.9161415*t+.033454*e),SL(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),YD(PL,AL,$D(VD,{brighter:function(t){return new PL(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new PL(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return xL(this).rgb()}}));var OL=-.29227,IL=-.90649,RL=1.97294,DL=RL*IL,LL=1.78277*RL,UL=1.78277*OL- -.14861*IL;function zL(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof jL)return new jL(t.h,t.s,t.l,t.opacity);t instanceof aL||(t=oL(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(UL*r+DL*n-LL*e)/(UL+DL-LL),o=r-i,u=(RL*(e-i)-OL*o)/IL,a=Math.sqrt(u*u+o*o)/(RL*i*(1-i)),c=a?Math.atan2(u,o)*pL-120:NaN;return new jL(c<0?c+360:c,a,i,t.opacity)}(t):new jL(t,n,e,null==r?1:r)}function jL(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function FL(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}YD(jL,zL,$D(VD,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new jL(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new jL(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*dL,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new aL(255*(n+e*(-.14861*r+1.78277*i)),255*(n+e*(OL*r+IL*i)),255*(n+e*(RL*r)),this.opacity)}}));var qL=function(t){return function(){return t}};function BL(t,n){return function(e){return t+e*n}}function HL(t,n){var e=n-t;return e?BL(t,e>180||e<-180?e-360*Math.round(e/360):e):qL(isNaN(t)?n:t)}function YL(t){return 1==(t=+t)?$L:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):qL(isNaN(n)?e:n)}}function $L(t,n){var e=n-t;return e?BL(t,e):qL(isNaN(t)?n:t)}var VL=function t(n){var e=YL(n);function r(t,n){var r=e((t=uL(t)).r,(n=uL(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=$L(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function WL(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:XL(e,r)})),o=QL.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:XL(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:XL(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,c),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:XL(t,e)},{i:a-2,x:XL(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,c),o=u=null,function(t){for(var n,e=-1,r=c.length;++e=0&&n._call.call(null,t),n=n._next;--gU}()}finally{gU=0,function(){var t,n,e=pU,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:pU=n);vU=t,PU(r)}(),wU=0}}function AU(){var t=EU.now(),n=t-bU;n>_U&&(xU-=n,bU=t)}function PU(t){gU||(yU&&(yU=clearTimeout(yU)),t-wU>24?(t<1/0&&(yU=setTimeout(CU,t-EU.now()-xU)),mU&&(mU=clearInterval(mU))):(mU||(bU=EU.now(),mU=setInterval(AU,_U)),gU=1,MU(CU)))}SU.prototype=TU.prototype={constructor:SU,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?kU():+e)+(null==n?0:+n),this._next||vU===this||(vU?vU._next=this:pU=this,vU=this),this._call=t,this._time=e,PU()},stop:function(){this._call&&(this._call=null,this._time=1/0,PU())}};var OU=function(t,n,e){var r=new SU;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},IU=qR("start","end","interrupt"),RU=[],DU=0,LU=1,UU=2,zU=3,jU=4,FU=5,qU=6,BU=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(c){var l,f,s,h;if(e.state!==LU)return a();for(l in i)if((h=i[l]).name===e.name){if(h.state===zU)return OU(o);h.state===jU?(h.state=qU,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[l]):+lDU)throw new Error("too late; already scheduled");return e}function YU(t,n){var e=$U(t,n);if(e.state>UU)throw new Error("too late; already started");return e}function $U(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}var VU=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>UU&&e.state=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?HU:YU;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}(e,t,n))},attr:function(t,n){var e=YR(t),r="transform"===e?aU:XU;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var u,a=e(this);if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}})(e,r,WU(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}:function(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}})(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=YR(t);return this.tween(e,(r.local?function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}:function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?uU:XU;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=aD(this,t),u=(this.style.removeProperty(t),aD(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}(t,r)).on("end.style."+t,function(t){return function(){this.style.removeProperty(t)}}(t)):this.styleTween(t,"function"==typeof n?function(t,n,e){var r,i,o;return function(){var u=aD(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=aD(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}(t,r,WU(this,"style."+t,n)):function(t,n,e){var r,i;return function(){var o=aD(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(WU(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=$U(this.node(),e).tween,o=0,u=i.length;or?(r+i)/2:Math.min(0,r)||Math.max(0,i),u>o?(o+u)/2:Math.min(0,o)||Math.max(0,u))}var vz=function(){var t,n,e=lz,r=fz,i=pz,o=hz,u=dz,a=[0,1/0],c=[[-1/0,-1/0],[1/0,1/0]],l=250,f=fU,s=[],h=qR("start","zoom","end"),d=500,p=150,v=0;function g(t){t.property("__zoom",sz).on("wheel.zoom",E).on("mousedown.zoom",M).on("dblclick.zoom",k).filter(u).on("touchstart.zoom",N).on("touchmove.zoom",S).on("touchend.zoom touchcancel.zoom",T).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function y(t,n){return(n=Math.max(a[0],Math.min(a[1],n)))===t.k?t:new iz(n,t.x,t.y)}function m(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new iz(t.k,r,i)}function _(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function b(t,n,e){t.on("start.zoom",function(){w(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){w(this,arguments).end()}).tween("zoom",function(){var t=arguments,i=w(this,t),o=r.apply(this,t),u=e||_(o),a=Math.max(o[1][0]-o[0][0],o[1][1]-o[0][1]),c=this.__zoom,l="function"==typeof n?n.apply(this,t):n,s=f(c.invert(u).concat(a/c.k),l.invert(u).concat(a/l.k));return function(t){if(1===t)t=l;else{var n=s(t),e=a/n[2];t=new iz(e,u[0]-n[0]*e,u[1]-n[1]*e)}i.zoom(null,t)}})}function w(t,n){for(var e,r=0,i=s.length;rv}t.zoom("mouse",i(m(t.that.__zoom,t.mouse[0]=zD(t.that),t.mouse[1]),t.extent,c))},!0).on("mouseup.zoom",function(){r.on("mousemove.zoom mouseup.zoom",null),BD(xD.view,t.moved),cz(),t.end()},!0),o=zD(this),u=xD.clientX,a=xD.clientY;qD(xD.view),az(),t.mouse=[o,this.__zoom.invert(o)],VU(this),t.start()}}function k(){if(e.apply(this,arguments)){var t=this.__zoom,n=zD(this),o=t.invert(n),u=t.k*(xD.shiftKey?.5:2),a=i(m(y(t,u),n,o),r.apply(this,arguments),c);cz(),l>0?ID(this).transition().duration(l).call(b,a,n):ID(this).call(g.transform,a)}}function N(){if(e.apply(this,arguments)){var n,r,i,o,u=w(this,arguments),a=xD.changedTouches,c=a.length;for(az(),r=0;r3e4)&&($("#no-connection-modal").modal(),t.setState({modalShown:!0}))})}},{key:"resetTimer",value:function(){clearTimeout(this.timeoutId),this.timeoutId=setTimeout(this.refreshLoop.bind(this),1e3)}},{key:"componentDidMount",value:function(){this.refreshLoop.bind(this)()}},{key:"renderStatusLight",value:function(){return this.state.noConnection?this.state.lightShown?i.default.createElement("span",{className:"status-light status-light-red",id:"status-indicator"}):i.default.createElement("span",{className:"status-light",id:"status-indicator"}):i.default.createElement("span",{className:"status-light status-light-green",id:"status-indicator"})}},{key:"render",value:function(){var t=this.state.info;return t?i.default.createElement("div",null,i.default.createElement("nav",{className:"navbar"},i.default.createElement("div",{className:"container-fluid"},i.default.createElement("div",{className:"navbar-header"},i.default.createElement("table",null,i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",null,i.default.createElement("a",{href:"/ui/"},i.default.createElement("img",{src:"assets/logo.png"}))),i.default.createElement("td",null,i.default.createElement("span",{className:"navbar-brand"},this.props.title)))))),i.default.createElement("div",{id:"navbar",className:"navbar-collapse collapse"},i.default.createElement("ul",{className:"nav navbar-nav navbar-right"},i.default.createElement("li",null,i.default.createElement("span",{className:"navbar-cluster-info"},i.default.createElement("span",{className:"uppercase"},"Version"),i.default.createElement("br",null),i.default.createElement("span",{className:"text uppercase",id:"version-number"},t.nodeVersion.version))),i.default.createElement("li",null,i.default.createElement("span",{className:"navbar-cluster-info"},i.default.createElement("span",{className:"uppercase"},"Environment"),i.default.createElement("br",null),i.default.createElement("span",{className:"text uppercase",id:"environment"},t.environment))),i.default.createElement("li",null,i.default.createElement("span",{className:"navbar-cluster-info"},i.default.createElement("span",{className:"uppercase"},"Uptime"),i.default.createElement("br",null),i.default.createElement("span",{"data-toggle":"tooltip","data-placement":"bottom",title:"Connection status"},this.renderStatusLight())," ",i.default.createElement("span",{className:"text",id:"uptime"},t.uptime))))))),i.default.createElement("div",{id:"no-connection-modal",className:"modal",tabIndex:"-1",role:"dialog"},i.default.createElement("div",{className:"modal-dialog modal-sm",role:"document"},i.default.createElement("div",{className:"modal-content"},i.default.createElement("div",{className:"row error-message"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("br",null),i.default.createElement("h4",null,"Unable to connect to server"),i.default.createElement("p",null,this.state.errorText?"Error: "+this.state.errorText:null))))))):null}}]),n}()},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.QueryHeader=void 0;var r=function(){function t(t,n){for(var e=0;e0&&t.queryStats.runningDrivers>=0,t.queryStats.fullyBlocked,t.queryStats.blockedReasons,t.memoryPool,t.errorType,t.errorCode?t.errorCode.name:null),r=(0,o.getProgressBarPercentage)(t.queryStats.progressPercentage,t.state),u={width:r+"%",backgroundColor:n},a=(0,o.getProgressBarTitle)(t.queryStats.progressPercentage,t.state,e);return(0,o.isQueryEnded)(t.state)?i.default.createElement("div",{className:"progress-large"},i.default.createElement("div",{className:"progress-bar progress-bar-info",role:"progressbar","aria-valuenow":r,"aria-valuemin":"0","aria-valuemax":"100",style:u},a)):i.default.createElement("table",null,i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{width:"100%"},i.default.createElement("div",{className:"progress-large"},i.default.createElement("div",{className:"progress-bar progress-bar-info",role:"progressbar","aria-valuenow":r,"aria-valuemin":"0","aria-valuemax":"100",style:u},a))),i.default.createElement("td",null,i.default.createElement("a",{onClick:function(){return $.ajax({url:"/v1/query/"+t.queryId+"/preempted",type:"PUT",data:"Preempted via web UI"})},className:"btn btn-warning",target:"_blank"},"Preempt")),i.default.createElement("td",null,i.default.createElement("a",{onClick:function(){return $.ajax({url:"/v1/query/"+t.queryId+"/killed",type:"PUT",data:"Killed via web UI"})},className:"btn btn-warning",target:"_blank"},"Kill")))))}},{key:"renderTab",value:function(t,n){var e=this.props.query.queryId;return window.location.pathname.includes(t)?i.default.createElement("a",{href:t+"?"+e,className:"btn btn-info navbar-btn nav-disabled"},n):i.default.createElement("a",{href:t+"?"+e,className:"btn btn-info navbar-btn"},n)}},{key:"render",value:function(){var t=this.props.query;return i.default.createElement("div",null,i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",{className:"query-id"},i.default.createElement("span",{id:"query-id"},t.queryId),i.default.createElement("a",{className:"btn copy-button","data-clipboard-target":"#query-id","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"})))),i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("table",{className:"header-inline-links"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",null,this.renderTab("query.html","Overview")," ",this.renderTab("plan.html","Live Plan")," ",this.renderTab("stage.html","Stage Performance")," ",this.renderTab("timeline.html","Splits")," ",i.default.createElement("a",{href:"/v1/query/"+t.queryId+"?pretty",className:"btn btn-info navbar-btn",target:"_blank"},"JSON"))))))),i.default.createElement("hr",{className:"h2-hr"}),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},this.renderProgressBar())))}}]),n}()},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.filterPropsFrom=function(t){t=t||{};var n={};for(var e in t)e in r||(n[e]=t[e]);return n};var r={hideTableHeader:!0,column:!0,columns:!0,sortable:!0,filterable:!0,filtering:!0,onFilter:!0,filterPlaceholder:!0,filterClassName:!0,currentFilter:!0,sort:!0,sortBy:!0,sortableColumns:!0,onSort:!0,defaultSort:!0,defaultSortDescending:!0,itemsPerPage:!0,filterBy:!0,hideFilterInput:!0,noDataText:!0,currentPage:!0,onPageChange:!0,previousPageLabel:!0,nextPageLabel:!0,pageButtonLimit:!0,childNode:!0,data:!0,children:!0}},,,,,,function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function t(t,n){for(var e=0;e0&&(i+=" "+o),"object"==typeof e.props&&"string"==typeof e.props.className&&(i+=" "+e.props.className),t.push(u.default.createElement(a.Th,r({},e.props,{className:i,key:n,onClick:this.handleClickTh.bind(this,e),onKeyDown:this.handleKeyDownTh.bind(this,e),role:f,tabIndex:"0"}),e.label))}var s=(0,l.filterPropsFrom)(this.props);return u.default.createElement("thead",s,!0===this.props.filtering?u.default.createElement(c.Filterer,{colSpan:this.props.columns.length,onFilter:this.props.onFilter,placeholder:this.props.filterPlaceholder,value:this.props.currentFilter,className:this.props.filterClassName}):null,u.default.createElement("tr",{className:"reactable-column-header"},t))}}],[{key:"getColumns",value:function(t){var n=[];return u.default.Children.forEach(t.props.children,function(t){var e={};if(t){if(void 0!==t.props&&(e.props=(0,l.filterPropsFrom)(t.props),void 0!==t.props.children&&(e.label=t.props.children,e.key=e.label),"string"==typeof t.props.column&&(e.key=t.props.column,void 0===e.label&&(e.label=e.key))),void 0===e.key)throw new TypeError('
must have either a "column" property or a string child');n.push(e)}}),n}}]),n}();n.Thead=f},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=Object.assign||function(t){for(var n=1;n=0||Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e}(t,["props"]);if(this.props.data.hasOwnProperty(o.key)){var c=this.props.data[o.key];return void 0!==c&&null!==c&&!0===c.__reactableMeta&&(i=c.props,c=c.value),u.default.createElement(a.Td,r({column:o,key:o.key},i),c)}return u.default.createElement(a.Td,{column:o,key:o.key})}.bind(this))));var n=(0,l.filterPropsFrom)(this.props);return u.default.createElement("tr",n,t)}}]),n}();n.Tr=f,f.childNode=a.Td,f.dataType="object"},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=Object.assign||function(t){for(var n=1;ni.length)return 1;for(var o=0;oa?1:-1}return 0}},{key:"showPortNumbers",value:function(t){for(var n={},e=0;e=1e3){var o=Date.now(),a=(0,u.getStageNumber)(t.stageId);if(n.renderHistogram("#scheduled-time-histogram-"+a,r,u.formatDuration),n.renderHistogram("#cpu-time-histogram-"+a,i,u.formatDuration),this.state.expanded){for(var c={offset:{}},l=0;l=0){var s=((0,u.parseDuration)(t.queryStats.totalScheduledTime)-r)/(1e3*f),h=((0,u.parseDuration)(t.queryStats.totalCpuTime)-i)/(1e3*f),d=(t.queryStats.processedInputPositions-o)/f,p=((0,u.parseDataSize)(t.queryStats.processedInputDataSize)-a)/f;this.setState({scheduledTimeRate:(0,u.addToHistory)(s,this.state.scheduledTimeRate),cpuTimeRate:(0,u.addToHistory)(h,this.state.cpuTimeRate),rowInputRate:(0,u.addToHistory)(d,this.state.rowInputRate),byteInputRate:(0,u.addToHistory)(p,this.state.byteInputRate),reservedMemory:(0,u.addToHistory)((0,u.parseDataSize)(t.queryStats.userMemoryReservation),this.state.reservedMemory)})}this.resetTimer()}}.bind(this)).error(function(){t.setState({initialized:!0}),t.resetTimer()})}},{key:"handleStageRefreshClick",value:function(){this.state.stageRefresh?this.setState({stageRefresh:!1,lastSnapshotStages:this.state.query.outputStage}):this.setState({stageRefresh:!0})}},{key:"renderStageRefreshButton",value:function(){return this.state.stageRefresh?i.default.createElement("button",{className:"btn btn-info live-button",onClick:this.handleStageRefreshClick.bind(this)},"Auto-Refresh: On"):i.default.createElement("button",{className:"btn btn-info live-button",onClick:this.handleStageRefreshClick.bind(this)},"Auto-Refresh: Off")}},{key:"componentDidMount",value:function(){this.refreshLoop()}},{key:"componentDidUpdate",value:function(){if(null===this.state.lastRender||Date.now()-this.state.lastRender>=1e3){var t=Date.now();$("#scheduled-time-rate-sparkline").sparkline(this.state.scheduledTimeRate,$.extend({},x,{chartRangeMin:0,numberFormatter:u.precisionRound})),$("#cpu-time-rate-sparkline").sparkline(this.state.cpuTimeRate,$.extend({},x,{chartRangeMin:0,numberFormatter:u.precisionRound})),$("#row-input-rate-sparkline").sparkline(this.state.rowInputRate,$.extend({},x,{numberFormatter:u.formatCount})),$("#byte-input-rate-sparkline").sparkline(this.state.byteInputRate,$.extend({},x,{numberFormatter:u.formatDataSize})),$("#reserved-memory-sparkline").sparkline(this.state.reservedMemory,$.extend({},x,{numberFormatter:u.formatDataSize})),null===this.state.lastRender&&($("#query").each(function(t,n){hljs.highlightBlock(n)}),$("#prepared-query").each(function(t,n){hljs.highlightBlock(n)})),this.setState({lastRender:t})}$('[data-toggle="tooltip"]').tooltip(),new Clipboard(".copy-button")}},{key:"renderStages",value:function(){if(null!==this.state.lastSnapshotStage)return i.default.createElement("div",null,i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-9"},i.default.createElement("h3",null,"Stages")),i.default.createElement("div",{className:"col-xs-3"},i.default.createElement("table",{className:"header-inline-links"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",null,this.renderStageRefreshButton())))))),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement(w,{key:this.state.query.queryId,outputStage:this.state.lastSnapshotStage}))))}},{key:"renderPreparedQuery",value:function(){var t=this.state.query;if(t.hasOwnProperty("preparedQuery")&&null!==t.preparedQuery)return i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h3",null,"Prepared Query",i.default.createElement("a",{className:"btn copy-button","data-clipboard-target":"#prepared-query-text","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"}))),i.default.createElement("pre",{id:"prepared-query"},i.default.createElement("code",{className:"lang-sql",id:"prepared-query-text"},t.preparedQuery)))}},{key:"renderSessionProperties",value:function(){var t=this.state.query,n=[];for(var e in t.session.systemProperties)t.session.systemProperties.hasOwnProperty(e)&&n.push(i.default.createElement("span",null,"- ",e+"="+t.session.systemProperties[e]," ",i.default.createElement("br",null)));for(var r in t.session.catalogProperties)if(t.session.catalogProperties.hasOwnProperty(r))for(var o in t.session.catalogProperties[r])t.session.catalogProperties[r].hasOwnProperty(o)&&n.push(i.default.createElement("span",null,"- ",r+"."+o+"="+t.session.catalogProperties[r][o]," ",i.default.createElement("br",null)));return n}},{key:"renderResourceEstimates",value:function(){var t=this.state.query,n=t.session.resourceEstimates,e=[];for(var r in n)if(n.hasOwnProperty(r)){for(var o=r.match(/([A-Z])/g)||[],u=r,a=0,c=o.length;a0?i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h3",null,"Warnings"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table",id:"warnings-table"},t.warnings.map(function(t){return i.default.createElement("tr",null,i.default.createElement("td",null,t.warningCode.name),i.default.createElement("td",null,t.message))})))):null}},{key:"renderMetricValue",value:function(t,n){return t.includes("Nanos")?(0,u.formatDuration)((0,u.parseDuration)(n+"ns")):(0,u.formatCount)(n)}},{key:"renderRuntimeStats",value:function(){var t=this,n=this.state.query;return void 0===n.queryStats.runtimeStats?null:0==Object.values(n.queryStats.runtimeStats).length?null:i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"RuntimeStats"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table",id:"runtime-stats-table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("th",{className:"info-text"},"Metric Name"),i.default.createElement("th",{className:"info-text"},"Sum"),i.default.createElement("th",{className:"info-text"},"Count"),i.default.createElement("th",{className:"info-text"},"Min"),i.default.createElement("th",{className:"info-text"},"Max")),Object.values(n.queryStats.runtimeStats).sort(function(t,n){return t.name.localeCompare(n.name)}).map(function(n){return i.default.createElement("tr",null,i.default.createElement("td",{className:"info-text"},n.name),i.default.createElement("td",{className:"info-text"},t.renderMetricValue(n.name,n.sum)),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(n.count)),i.default.createElement("td",{className:"info-text"},t.renderMetricValue(n.name,n.min)),i.default.createElement("td",{className:"info-text"},t.renderMetricValue(n.name,n.max)))})))))}},{key:"renderFailureInfo",value:function(){var t=this.state.query;return t.failureInfo?i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h3",null,"Error Information"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Error Type"),i.default.createElement("td",{className:"info-text"},t.errorType)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Error Code"),i.default.createElement("td",{className:"info-text"},t.errorCode.name+" ("+this.state.query.errorCode.code+")")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Stack Trace",i.default.createElement("a",{className:"btn copy-button","data-clipboard-target":"#stack-trace","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"}))),i.default.createElement("td",{className:"info-text"},i.default.createElement("pre",{id:"stack-trace"},n.formatStackTrace(t.failureInfo)))))))):""}},{key:"render",value:function(){var t=this.state.query;if(null===t||!1===this.state.initialized){var n=i.default.createElement("div",{className:"loader"},"Loading...");return this.state.initialized&&(n="Query not found"),i.default.createElement("div",{className:"row error-message"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h4",null,n)))}return i.default.createElement("div",null,i.default.createElement(a.QueryHeader,{query:t}),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"Session"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"User"),i.default.createElement("td",{className:"info-text wrap-text"},i.default.createElement("span",{id:"query-user"},t.session.user),"  ",i.default.createElement("a",{href:"#",className:"copy-button","data-clipboard-target":"#query-user","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"})))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Principal"),i.default.createElement("td",{className:"info-text wrap-text"},t.session.principal)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Source"),i.default.createElement("td",{className:"info-text wrap-text"},t.session.source)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Catalog"),i.default.createElement("td",{className:"info-text"},t.session.catalog)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Schema"),i.default.createElement("td",{className:"info-text"},t.session.schema)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Client Address"),i.default.createElement("td",{className:"info-text"},t.session.remoteUserAddress)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Client Tags"),i.default.createElement("td",{className:"info-text"},t.session.clientTags.join(", "))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Session Properties"),i.default.createElement("td",{className:"info-text wrap-text"},this.renderSessionProperties())),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Resource Estimates"),i.default.createElement("td",{className:"info-text wrap-text"},this.renderResourceEstimates()))))),i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"Execution"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Resource Group"),i.default.createElement("td",{className:"info-text wrap-text"},t.resourceGroupId?t.resourceGroupId.join("."):"n/a")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Submission Time"),i.default.createElement("td",{className:"info-text"},(0,u.formatShortDateTime)(new Date(t.queryStats.createTime)))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Completion Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.endTime?(0,u.formatShortDateTime)(new Date(t.queryStats.endTime)):"")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Elapsed Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.elapsedTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Prerequisites Wait Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.waitingForPrerequisitesTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Queued Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.queuedTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Planning Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.totalPlanningTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Execution Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.executionTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Coordinator"),i.default.createElement("td",{className:"info-text"},(0,u.getHostname)(t.self))))))),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"Resource Utilization Summary"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"CPU Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.totalCpuTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Scheduled Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.totalScheduledTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Blocked Time"),i.default.createElement("td",{className:"info-text"},t.queryStats.totalBlockedTime)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Input Rows"),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(t.queryStats.processedInputPositions))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Input Data"),i.default.createElement("td",{className:"info-text"},t.queryStats.processedInputDataSize)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Raw Input Rows"),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(t.queryStats.rawInputPositions))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Raw Input Data"),i.default.createElement("td",{className:"info-text"},t.queryStats.rawInputDataSize)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Peak User Memory"),i.default.createElement("td",{className:"info-text"},t.queryStats.peakUserMemoryReservation)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Peak Total Memory"),i.default.createElement("td",{className:"info-text"},t.queryStats.peakTotalMemoryReservation)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Memory Pool"),i.default.createElement("td",{className:"info-text"},t.memoryPool)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Cumulative User Memory"),i.default.createElement("td",{className:"info-text"},(0,u.formatDataSizeBytes)(t.queryStats.cumulativeUserMemory/1e3)+" seconds")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Cumulative Total"),i.default.createElement("td",{className:"info-text"},(0,u.formatDataSizeBytes)(t.queryStats.cumulativeTotalMemory/1e3)+" seconds")),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Output Rows"),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(t.queryStats.outputPositions))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Output Data"),i.default.createElement("td",{className:"info-text"},t.queryStats.outputDataSize)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Written Output Rows"),i.default.createElement("td",{className:"info-text"},(0,u.formatCount)(t.queryStats.writtenOutputPositions))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Written Output Logical Data Size"),i.default.createElement("td",{className:"info-text"},t.queryStats.writtenOutputLogicalDataSize)),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Written Output Physical Data Size"),i.default.createElement("td",{className:"info-text"},t.queryStats.writtenOutputPhysicalDataSize)),(0,u.parseDataSize)(t.queryStats.spilledDataSize)>0&&i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Spilled Data"),i.default.createElement("td",{className:"info-text"},t.queryStats.spilledDataSize))))),i.default.createElement("div",{className:"col-xs-6"},i.default.createElement("h3",null,"Timeline"),i.default.createElement("hr",{className:"h3-hr"}),i.default.createElement("table",{className:"table"},i.default.createElement("tbody",null,i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Parallelism"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"cpu-time-rate-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatCount)(this.state.cpuTimeRate[this.state.cpuTimeRate.length-1]))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Scheduled Time/s"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"scheduled-time-rate-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatCount)(this.state.scheduledTimeRate[this.state.scheduledTimeRate.length-1]))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Input Rows/s"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"row-input-rate-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatCount)(this.state.rowInputRate[this.state.rowInputRate.length-1]))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Input Bytes/s"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"byte-input-rate-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatDataSize)(this.state.byteInputRate[this.state.byteInputRate.length-1]))),i.default.createElement("tr",null,i.default.createElement("td",{className:"info-title"},"Memory Utilization"),i.default.createElement("td",{rowSpan:"2"},i.default.createElement("div",{className:"query-stats-sparkline-container"},i.default.createElement("span",{className:"sparkline",id:"reserved-memory-sparkline"},i.default.createElement("div",{className:"loader"},"Loading ..."))))),i.default.createElement("tr",{className:"tr-noborder"},i.default.createElement("td",{className:"info-sparkline-text"},(0,u.formatDataSize)(this.state.reservedMemory[this.state.reservedMemory.length-1]))))))))),this.renderRuntimeStats(),this.renderWarningInfo(),this.renderFailureInfo(),i.default.createElement("div",{className:"row"},i.default.createElement("div",{className:"col-xs-12"},i.default.createElement("h3",null,"Query",i.default.createElement("a",{className:"btn copy-button","data-clipboard-target":"#query-text","data-toggle":"tooltip","data-placement":"right",title:"Copy to clipboard"},i.default.createElement("span",{className:"glyphicon glyphicon-copy","aria-hidden":"true",alt:"Copy to clipboard"}))),i.default.createElement("pre",{id:"query"},i.default.createElement("code",{className:"lang-sql",id:"query-text"},t.query))),this.renderPreparedQuery()),this.renderStages())}}],[{key:"formatStackTrace",value:function(t){return n.formatStackTraceHelper(t,[],"","")}},{key:"formatStackTraceHelper",value:function(t,e,r,i){var o=i+r+n.failureInfoToString(t)+"\n";if(t.stack){var u=0;null!==e&&(u=n.countSharedStackFrames(t.stack,e));for(var a=0;a>>0,i=arguments[1],o=0;o, but more than one was specified.Ignoring all but the last one"),e=t;break;case s.Tr:var r=t.props.data||{};u.default.Children.forEach(t.props.children,function(t){if("object"==typeof t&&null!=t)if(void 0!==t.props.column){var n=void 0;if(void 0!==t.props.data)n=t.props.data;else{if(void 0===t.props.children)return void console.warn("exports.Td specified without a `data` property or children, ignoring");n=t.props.children}r[t.props.column]={value:n,props:(0,a.filterPropsFrom)(t.props),__reactableMeta:!0}}else console.warn("exports.Td specified without a `column` property, ignoring")}),n.push({data:r,props:(0,a.filterPropsFrom)(t.props),__reactableMeta:!0});break;default:console.warn("The only possible children of are , , or one .")}}.bind(this)),{data:n,tfoot:e}}},{key:"initialize",value:function(t){this.data=t.data||[];var n=this.parseChildData(t),e=n.data,r=n.tfoot;this.data=this.data.concat(e),this.tfoot=r,this.initializeSorts(t),this.initializeFilters(t)}},{key:"initializeFilters",value:function(t){for(var n in this._filterable={},t.filterable){var e=t.filterable[n],r=void 0,i=void 0;if(e instanceof Object){if(void 0===e.column){console.warn("Filterable column specified without column name");continue}r=e.column,i="function"==typeof e.filterFunction?e.filterFunction:"default"}else r=e,i="default";this._filterable[r]=i}}},{key:"initializeSorts",value:function(t){for(var n in this._sortable={},t.sortable){var e=t.sortable[n],r=void 0,i=void 0;if(e instanceof Object){if(void 0===e.column)return void console.warn("Sortable column specified without column name");r=e.column,i="function"==typeof e.sortFunction?e.sortFunction:"default"}else r=e,i="default";this._sortable[r]=i}}},{key:"getCurrentSort",value:function(t){var n=void 0,e=void 0;if(t instanceof Object){if(void 0===t.column)return void console.warn("Default column specified without column name");if(n=t.column,void 0!==t.direction)if(1===t.direction||"asc"===t.direction)e=1;else if(-1===t.direction||"desc"===t.direction)e=-1;else{var r=this.props.defaultSortDescending?"descending":"ascending";console.warn("Invalid default sort specified. Defaulting to "+r),e=this.props.defaultSortDescending?-1:1}else e=this.props.defaultSortDescending?-1:1}else n=t,e=this.props.defaultSortDescending?-1:1;return{column:n,direction:e}}},{key:"updateCurrentSort",value:function(t){!1!==t&&t.column!==this.state.currentSort.column&&t.direction!==this.state.currentSort.direction&&this.setState({currentSort:this.getCurrentSort(t)})}},{key:"updateCurrentPage",value:function(t){void 0!==t&&t!==this.state.currentPage&&this.setState({currentPage:t})}},{key:"componentWillMount",value:function(){this.initialize(this.props),this.sortByCurrentSort(),this.filterBy(this.props.filterBy)}},{key:"componentWillReceiveProps",value:function(t){this.initialize(t),this.updateCurrentPage(t.currentPage),this.updateCurrentSort(t.sortBy),this.sortByCurrentSort(),this.filterBy(t.filterBy)}},{key:"applyFilter",value:function(t,n){t=t.toLowerCase();for(var e=[],r=0;r-1){e.push(n[r]);break}}else if(this._filterable[o]((0,c.extractDataFrom)(i,o).toString(),t)){e.push(n[r]);break}}return e}},{key:"sortByCurrentSort",value:function(){var t=this.state.currentSort;null!==t.column&&this.data.sort(function(n,e){var r=(0,c.extractDataFrom)(n,t.column);r=(0,l.isUnsafe)(r)?r.toString():r||"";var i=(0,c.extractDataFrom)(e,t.column);return i=(0,l.isUnsafe)(i)?i.toString():i||"",void 0===this._sortable[t.column]||"default"===this._sortable[t.column]?ri?1*t.direction:0:1===t.direction?this._sortable[t.column](r,i):this._sortable[t.column](i,r)}.bind(this))}},{key:"onSort",value:function(t){if(void 0!==this._sortable[t]){var n=this.state.currentSort;n.column===t?n.direction*=-1:(n.column=t,n.direction=this.props.defaultSortDescending?-1:1),this.setState({currentSort:n}),this.sortByCurrentSort(),"function"==typeof this.props.onSort&&this.props.onSort(n)}}},{key:"render",value:function(){var t=this,n=[],e=void 0,i=!1,o=void 0===this.props.hideTableHeader,c=null;if(this.props.children&&(this.props.children.length>0&&this.props.children[0]&&this.props.children[0].type===f.Thead?c=this.props.children[0]:this.props.children.type===f.Thead&&(c=this.props.children)),(e=null!==c?f.Thead.getColumns(c):this.props.columns||[]).length>0&&(i=!0,e=this.translateColumnsArray(e)),this.data&&"function"==typeof this.data.map&&(n=n.concat(this.data.map(function(t,n){var o=t,a={};for(var c in!0===t.__reactableMeta&&(o=t.data,a=t.props),o)o.hasOwnProperty(c)&&!1===i&&function(){var t={key:c,label:c};void 0===e.find(function(n){return n.key===t.key})&&e.push(t)}();return u.default.createElement(s.Tr,r({columns:e,key:n,data:o},a))}.bind(this)))),!0===this.props.sortable)for(var l=0;l0&&!this.props.hideFilterInput&&(h=!0);var p=n;""!==this.state.filter&&(p=this.applyFilter(this.state.filter,p));var v=0,g=!1,y=void 0,m=this.state.currentPage,_=this.props.pageButtonLimit||10,b=p;this.props.itemsPerPage>0&&(v=this.props.itemsPerPage,m>(y=Math.ceil(p.length/v))-1&&(m=y-1),g=!0,b=p.slice(m*v,(m+1)*v));var w=(0,a.filterPropsFrom)(this.props),x=this.props.noDataText?u.default.createElement("tr",{className:"reactable-no-data"},u.default.createElement("td",{colSpan:e.length},this.props.noDataText)):null,E=null;return e&&e.length>0&&o&&(E=u.default.createElement(f.Thead,{columns:e,filtering:h,onFilter:function(n){t.setState({filter:n}),t.props.onFilter&&t.props.onFilter(n)},filterPlaceholder:this.props.filterPlaceholder,filterClassName:this.props.filterClassName,currentFilter:this.state.filter,sort:this.state.currentSort,sortableColumns:this._sortable,onSort:this.onSort.bind(this),key:"thead"})),u.default.createElement("table",w,E,u.default.createElement("tbody",{className:"reactable-data",key:"tbody"},b.length>0?b:x),!0===g?u.default.createElement(d.Paginator,{colSpan:e.length,pageButtonLimit:_,numPages:y,currentPage:m,onPageChange:function(n){t.setState({currentPage:n}),t.props.onPageChange&&t.props.onPageChange(n)},previousPageLabel:this.props.previousPageLabel,nextPageLabel:this.props.nextPageLabel,key:"paginator"}):null,this.tfoot)}}]),n}();n.Table=p,p.defaultProps={sortBy:!1,defaultSort:!1,defaultSortDescending:!1,itemsPerPage:0,filterBy:"",hideFilterInput:!1}},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.extractDataFrom=function(t,n){var e;e=void 0!==t&&null!==t&&!0===t.__reactableMeta?t.data[n]:t[n];void 0!==e&&null!==e&&!0===e.__reactableMeta&&(e=void 0!==e.props.value&&null!==e.props.value?e.props.value:e.value);return(0,r.stringable)(e)?e:""};var r=e(113)},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function t(t,n){for(var e=0;e0)return o.default.createElement("a",{className:"reactable-previous-page",href:u(this.props.currentPage-1),onClick:this.handlePrevious.bind(this)},this.props.previousPageLabel||"Previous")}},{key:"renderNext",value:function(){if(this.props.currentPage0&&(e>r-i?t.splice(0,r-n):t.splice(0,e-n+i)),r-e>u&&t.splice(n,t.length-n),o.default.createElement("tbody",{className:"reactable-pagination"},o.default.createElement("tr",null,o.default.createElement("td",{colSpan:this.props.colSpan},this.renderPrevious(),t,this.renderNext())))}}]),n}();n.Paginator=a},function(t,n,e){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r={Numeric:function(t,n){var e=parseFloat(t.toString().replace(/,/g,"")),r=parseFloat(n.toString().replace(/,/g,""));if(isNaN(e)&&isNaN(r))e=t,r=n;else{if(isNaN(e))return 1;if(isNaN(r))return-1}return er?1:0},NumericInteger:function(t,n){return isNaN(t)||isNaN(n)?t>n?1:-1:t-n},Currency:function(t,e){return t=t.replace(/[^0-9\.\-\,]+/g,""),e=e.replace(/[^0-9\.\-\,]+/g,""),n.Sort.Numeric(t,e)},Date:function(t){function n(n,e){return t.apply(this,arguments)}return n.toString=function(){return t.toString()},n}(function(t,e){var r=Date.parse(t),i=Date.parse(e);return isNaN(r)||isNaN(i)?n.Sort.Numeric(t,e):r>i?1:i>r?-1:0}),CaseInsensitive:function(t,n){return t.toLowerCase().localeCompare(n.toLowerCase())}};n.Sort=r}]); \ No newline at end of file diff --git a/presto-main/src/main/resources/webapp/src/components/QueryDetail.jsx b/presto-main/src/main/resources/webapp/src/components/QueryDetail.jsx index fb0f6a85e7cf4..afc5829a43ca9 100644 --- a/presto-main/src/main/resources/webapp/src/components/QueryDetail.jsx +++ b/presto-main/src/main/resources/webapp/src/components/QueryDetail.jsx @@ -1080,6 +1080,7 @@ export class QueryDetail extends React.Component { renderRuntimeStats() { const query = this.state.query; + if (query.queryStats.runtimeStats === undefined) return null; if (Object.values(query.queryStats.runtimeStats).length == 0) return null; return (
diff --git a/presto-main/src/test/java/com/facebook/presto/server/TestHttpRequestSessionContext.java b/presto-main/src/test/java/com/facebook/presto/server/TestHttpRequestSessionContext.java index 24b34a17a6298..f4dbbb6d12dc3 100644 --- a/presto-main/src/test/java/com/facebook/presto/server/TestHttpRequestSessionContext.java +++ b/presto-main/src/test/java/com/facebook/presto/server/TestHttpRequestSessionContext.java @@ -161,7 +161,7 @@ public void testPreparedStatementsSpecialCharacters() .put(PRESTO_LANGUAGE, "zh-TW") .put(PRESTO_TIME_ZONE, "Asia/Taipei") .put(PRESTO_CLIENT_INFO, "null") - .put(PRESTO_PREPARED_STATEMENT, "query1=select * from tbl:ns") + .put(PRESTO_PREPARED_STATEMENT, "query1=select * from \"tbl:ns\"") .build(), "testRemote"); SqlParserOptions options = new SqlParserOptions(); diff --git a/presto-main/src/test/java/com/facebook/presto/server/TestThreadResource.java b/presto-main/src/test/java/com/facebook/presto/server/TestThreadResource.java new file mode 100644 index 0000000000000..5b1d7f1f8ac70 --- /dev/null +++ b/presto-main/src/test/java/com/facebook/presto/server/TestThreadResource.java @@ -0,0 +1,154 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.server; + +import com.facebook.drift.codec.ThriftCodec; +import com.facebook.drift.codec.ThriftCodecManager; +import com.facebook.drift.codec.internal.compiler.CompilerThriftCodecFactory; +import com.facebook.drift.codec.internal.reflection.ReflectionThriftCodecFactory; +import com.facebook.drift.codec.metadata.ThriftCatalog; +import com.facebook.drift.codec.utils.DataSizeToBytesThriftCodec; +import com.facebook.drift.codec.utils.JodaDateTimeToEpochMillisThriftCodec; +import com.facebook.drift.protocol.TBinaryProtocol; +import com.facebook.drift.protocol.TCompactProtocol; +import com.facebook.drift.protocol.TFacebookCompactProtocol; +import com.facebook.drift.protocol.TMemoryBuffer; +import com.facebook.drift.protocol.TProtocol; +import com.facebook.drift.protocol.TTransport; +import com.google.common.collect.ImmutableSet; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import static org.testng.Assert.assertEquals; + +@Test(singleThreaded = true) +public class TestThreadResource +{ + private static final ThriftCatalog COMMON_CATALOG = new ThriftCatalog(); + private static final DataSizeToBytesThriftCodec DATA_SIZE_CODEC = new DataSizeToBytesThriftCodec(COMMON_CATALOG); + private static final JodaDateTimeToEpochMillisThriftCodec DATE_TIME_CODEC = new JodaDateTimeToEpochMillisThriftCodec(COMMON_CATALOG); + private static final ThriftCodecManager COMPILER_READ_CODEC_MANAGER = new ThriftCodecManager(new CompilerThriftCodecFactory(false), COMMON_CATALOG, ImmutableSet.of(DATA_SIZE_CODEC, DATE_TIME_CODEC)); + private static final ThriftCodec COMPILER_READ_CODEC = COMPILER_READ_CODEC_MANAGER.getCodec(ThreadResource.Info.class); + private static final ThriftCodecManager COMPILER_WRITE_CODEC_MANAGER = new ThriftCodecManager(new CompilerThriftCodecFactory(false), COMMON_CATALOG, ImmutableSet.of(DATA_SIZE_CODEC, DATE_TIME_CODEC)); + private static final ThriftCodec COMPILER_WRITE_CODEC = COMPILER_WRITE_CODEC_MANAGER.getCodec(ThreadResource.Info.class); + private static final ThriftCodecManager REFLECTION_READ_CODEC_MANAGER = new ThriftCodecManager(new ReflectionThriftCodecFactory(), COMMON_CATALOG, ImmutableSet.of(DATA_SIZE_CODEC, DATE_TIME_CODEC)); + private static final ThriftCodec REFLECTION_READ_CODEC = REFLECTION_READ_CODEC_MANAGER.getCodec(ThreadResource.Info.class); + private static final ThriftCodecManager REFLECTION_WRITE_CODEC_MANAGER = new ThriftCodecManager(new ReflectionThriftCodecFactory(), COMMON_CATALOG, ImmutableSet.of(DATA_SIZE_CODEC, DATE_TIME_CODEC)); + private static final ThriftCodec REFLECTION_WRITE_CODEC = REFLECTION_WRITE_CODEC_MANAGER.getCodec(ThreadResource.Info.class); + private static final TMemoryBuffer transport = new TMemoryBuffer(100 * 1024); + + // Dummy values for fake StackLine + private static final String FAKE_FILE_1 = "/fake/com/facebook/presto/server/Fake1.java"; + private static final String FAKE_FILE_2 = "/fake/com/facebook/presto/server/Fake2.java"; + private static final String FAKE_FILE_3 = "/fake/com/facebook/presto/server/Fake3.java"; + private static final int FAKE_LINE_1 = 1; + private static final int FAKE_LINE_2 = 2; + private static final int FAKE_LINE_3 = 3; + private static final String FAKE_CLASSNAME_1 = "com.facebook.presto.server.Fake1"; + private static final String FAKE_CLASSNAME_2 = "com.facebook.presto.server.Fake2"; + private static final String FAKE_CLASSNAME_3 = "com.facebook.presto.server.Fake3"; + private static final String FAKE_METHOD_1 = "fake1"; + private static final String FAKE_METHOD_2 = "fake2"; + private static final String FAKE_METHOD_3 = "fake3"; + + // Dummy values for fake Info + private static final long FAKE_ID = 1234L; + private static final String FAKE_NAME = "Thread-1"; + private static final String FAKE_STATE = "blocked"; + private static final Long FAKE_LOCK_OWNER_ID = 1235L; + + private ThreadResource.Info info; + + @BeforeMethod + public void setUp() + { + List stackLines = new ArrayList<>(); + stackLines.add(new ThreadResource.StackLine(FAKE_FILE_1, FAKE_LINE_1, FAKE_CLASSNAME_1, FAKE_METHOD_1)); + stackLines.add(new ThreadResource.StackLine(FAKE_FILE_2, FAKE_LINE_2, FAKE_CLASSNAME_2, FAKE_METHOD_2)); + stackLines.add(new ThreadResource.StackLine(FAKE_FILE_3, FAKE_LINE_3, FAKE_CLASSNAME_3, FAKE_METHOD_3)); + + info = new ThreadResource.Info(FAKE_ID, FAKE_NAME, FAKE_STATE, FAKE_LOCK_OWNER_ID, stackLines); + } + + @DataProvider + public Object[][] codecCombinations() + { + return new Object[][] {{COMPILER_READ_CODEC, COMPILER_WRITE_CODEC}, {COMPILER_READ_CODEC, REFLECTION_WRITE_CODEC}, {REFLECTION_READ_CODEC, COMPILER_WRITE_CODEC}, + {REFLECTION_READ_CODEC, REFLECTION_WRITE_CODEC}}; + } + + @Test(dataProvider = "codecCombinations") + public void testRoundTripSerializeBinaryProtocol(ThriftCodec readCodec, ThriftCodec writeCodec) + throws Exception + { + ThreadResource.Info serializedInfo = getRoundTripSerialize(readCodec, writeCodec, TBinaryProtocol::new); + assertInfo(serializedInfo); + } + + @Test(dataProvider = "codecCombinations") + public void testRoundTripSerializeTCompactProtocol(ThriftCodec readCodec, ThriftCodec writeCodec) + throws Exception + { + ThreadResource.Info serializedInfo = getRoundTripSerialize(readCodec, writeCodec, TCompactProtocol::new); + assertInfo(serializedInfo); + } + + @Test(dataProvider = "codecCombinations") + public void testRoundTripSerializeTFacebookCompactProtocol(ThriftCodec readCodec, ThriftCodec writeCodec) + throws Exception + { + ThreadResource.Info serializedInfo = getRoundTripSerialize(readCodec, writeCodec, TFacebookCompactProtocol::new); + assertInfo(serializedInfo); + } + + private void assertStackLines(List stackLines) + { + assertEquals(stackLines.get(0).getFile(), FAKE_FILE_1); + assertEquals(stackLines.get(0).getLine(), FAKE_LINE_1); + assertEquals(stackLines.get(0).getClassName(), FAKE_CLASSNAME_1); + assertEquals(stackLines.get(0).getMethod(), FAKE_METHOD_1); + + assertEquals(stackLines.get(1).getFile(), FAKE_FILE_2); + assertEquals(stackLines.get(1).getLine(), FAKE_LINE_2); + assertEquals(stackLines.get(1).getClassName(), FAKE_CLASSNAME_2); + assertEquals(stackLines.get(1).getMethod(), FAKE_METHOD_2); + + assertEquals(stackLines.get(2).getFile(), FAKE_FILE_3); + assertEquals(stackLines.get(2).getLine(), FAKE_LINE_3); + assertEquals(stackLines.get(2).getClassName(), FAKE_CLASSNAME_3); + assertEquals(stackLines.get(2).getMethod(), FAKE_METHOD_3); + } + + private void assertInfo(ThreadResource.Info actualInfo) + { + assertEquals(actualInfo.getId(), FAKE_ID); + assertEquals(actualInfo.getName(), FAKE_NAME); + assertEquals(actualInfo.getState(), FAKE_STATE); + assertEquals(actualInfo.getLockOwnerId(), FAKE_LOCK_OWNER_ID); + assertStackLines(actualInfo.getStackTrace()); + } + + private ThreadResource.Info getRoundTripSerialize(ThriftCodec readCodec, ThriftCodec writeCodec, Function protocolFactory) + throws Exception + { + TProtocol protocol = protocolFactory.apply(transport); + writeCodec.write(info, protocol); + return readCodec.read(protocol); + } +} diff --git a/presto-main/src/test/java/com/facebook/presto/sql/TestSqlFormatter.java b/presto-main/src/test/java/com/facebook/presto/sql/TestSqlFormatter.java new file mode 100644 index 0000000000000..9e6154021203c --- /dev/null +++ b/presto-main/src/test/java/com/facebook/presto/sql/TestSqlFormatter.java @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.sql; + +import com.facebook.presto.sql.parser.ParsingOptions; +import com.facebook.presto.sql.parser.SqlParser; +import com.facebook.presto.sql.tree.Statement; +import org.testng.annotations.Test; + +import java.util.Optional; + +import static com.facebook.presto.sql.SqlFormatterUtil.getFormattedSql; +import static org.testng.Assert.assertEquals; + +public class TestSqlFormatter +{ + @Test + public void testSimpleExpression() + { + assetQuery("SELECT id\nFROM\n public.orders\n"); + assetQuery("SELECT id\nFROM\n \"public\".\"order\"\n"); + assetQuery("SELECT id\nFROM\n \"public\".\"order\"\"2\"\n"); + } + + private void assetQuery(String query) + { + SqlParser parser = new SqlParser(); + Statement statement = parser.createStatement(query, new ParsingOptions()); + String formattedQuery = getFormattedSql(statement, parser, Optional.empty()); + assertEquals(formattedQuery, query); + } +} diff --git a/presto-main/src/test/java/com/facebook/presto/sql/analyzer/TestFeaturesConfig.java b/presto-main/src/test/java/com/facebook/presto/sql/analyzer/TestFeaturesConfig.java index b413f884b2ae2..21757c780ab12 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/analyzer/TestFeaturesConfig.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/analyzer/TestFeaturesConfig.java @@ -19,6 +19,8 @@ import com.facebook.presto.operator.aggregation.histogram.HistogramGroupImplementation; import com.facebook.presto.operator.aggregation.multimapagg.MultimapAggGroupImplementation; import com.facebook.presto.sql.analyzer.FeaturesConfig.AggregationIfToFilterRewriteStrategy; +import com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType; +import com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy; import com.facebook.presto.sql.analyzer.FeaturesConfig.PartialAggregationStrategy; import com.facebook.presto.sql.analyzer.FeaturesConfig.PartitioningPrecisionStrategy; import com.facebook.presto.sql.analyzer.FeaturesConfig.SingleStreamSpillerChoice; @@ -34,8 +36,6 @@ import static com.facebook.presto.sql.analyzer.FeaturesConfig.AggregationPartitioningMergingStrategy.LEGACY; import static com.facebook.presto.sql.analyzer.FeaturesConfig.AggregationPartitioningMergingStrategy.TOP_DOWN; import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.BROADCAST; -import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.PARTITIONED; -import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.NONE; import static com.facebook.presto.sql.analyzer.FeaturesConfig.PartialMergePushdownStrategy.PUSH_THROUGH_LOW_MEMORY_OPERATORS; import static com.facebook.presto.sql.analyzer.FeaturesConfig.SPILLER_SPILL_PATH; @@ -60,7 +60,7 @@ public void testDefaults() .setMemoryCostWeight(10) .setNetworkCostWeight(15) .setDistributedIndexJoinsEnabled(false) - .setJoinDistributionType(PARTITIONED) + .setJoinDistributionType(JoinDistributionType.AUTOMATIC) .setJoinMaxBroadcastTableSize(new DataSize(100, MEGABYTE)) .setGroupedExecutionEnabled(true) .setRecoverableGroupedExecutionEnabled(false) @@ -70,7 +70,7 @@ public void testDefaults() .setFastInequalityJoins(true) .setColocatedJoinsEnabled(true) .setSpatialJoinsEnabled(true) - .setJoinReorderingStrategy(ELIMINATE_CROSS_JOINS) + .setJoinReorderingStrategy(JoinReorderingStrategy.AUTOMATIC) .setPartialMergePushdownStrategy(FeaturesConfig.PartialMergePushdownStrategy.NONE) .setMaxReorderedJoins(9) .setRedistributeWrites(true) @@ -187,7 +187,8 @@ public void testDefaults() .setVerboseRuntimeStatsEnabled(false) .setAggregationIfToFilterRewriteStrategy(AggregationIfToFilterRewriteStrategy.DISABLED) .setHashBasedDistinctLimitEnabled(false) - .setHashBasedDistinctLimitThreshold(10000)); + .setHashBasedDistinctLimitThreshold(10000) + .setStreamingForPartialAggregationEnabled(false)); } @Test @@ -326,6 +327,7 @@ public void testExplicitPropertyMappings() .put("optimizer.aggregation-if-to-filter-rewrite-strategy", "filter_with_if") .put("hash-based-distinct-limit-enabled", "true") .put("hash-based-distinct-limit-threshold", "500") + .put("streaming-for-partial-aggregation-enabled", "true") .build(); FeaturesConfig expected = new FeaturesConfig() @@ -461,7 +463,8 @@ public void testExplicitPropertyMappings() .setVerboseRuntimeStatsEnabled(true) .setAggregationIfToFilterRewriteStrategy(AggregationIfToFilterRewriteStrategy.FILTER_WITH_IF) .setHashBasedDistinctLimitEnabled(true) - .setHashBasedDistinctLimitThreshold(500); + .setHashBasedDistinctLimitThreshold(500) + .setStreamingForPartialAggregationEnabled(true); assertFullMapping(properties, expected); } diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestCanonicalPlanGenerator.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestCanonicalPlanGenerator.java index d598f1aad02af..2ee351f041da1 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestCanonicalPlanGenerator.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestCanonicalPlanGenerator.java @@ -230,21 +230,25 @@ public void testCanonicalPartitioningScheme() { assertEquals( Arrays.stream(PartitioningScheme.class.getDeclaredFields()) + .filter(f -> !f.isSynthetic()) .map(Field::getName) .collect(toImmutableSet()), ImmutableSet.of("partitioning", "outputLayout", "hashColumn", "replicateNullsAndAny", "bucketToPartition")); assertEquals( Arrays.stream(Partitioning.class.getDeclaredFields()) + .filter(f -> !f.isSynthetic()) .map(Field::getName) .collect(toImmutableSet()), ImmutableSet.of("handle", "arguments")); assertEquals( Arrays.stream(PartitioningHandle.class.getDeclaredFields()) + .filter(f -> !f.isSynthetic()) .map(Field::getName) .collect(toImmutableSet()), ImmutableSet.of("connectorId", "transactionHandle", "connectorHandle")); assertEquals( Arrays.stream(CanonicalPartitioningScheme.class.getDeclaredFields()) + .filter(f -> !f.isSynthetic()) .map(Field::getName) .collect(toImmutableSet()), ImmutableSet.of("connectorId", "connectorHandle", "arguments", "outputLayout")); @@ -255,22 +259,26 @@ public void testCanonicalTableScanNodeField() { assertEquals( Arrays.stream(TableScanNode.class.getDeclaredFields()) + .filter(f -> !f.isSynthetic()) .map(Field::getName) .collect(toImmutableSet()), ImmutableSet.of("table", "assignments", "outputVariables", "currentConstraint", "enforcedConstraint")); assertEquals( Arrays.stream(CanonicalTableScanNode.class.getDeclaredFields()) + .filter(f -> !f.isSynthetic()) .map(Field::getName) .collect(toImmutableSet()), ImmutableSet.of("table", "assignments", "outputVariables")); assertEquals( Arrays.stream(TableHandle.class.getDeclaredFields()) + .filter(f -> !f.isSynthetic()) .map(Field::getName) .collect(toImmutableSet()), ImmutableSet.of("connectorId", "connectorHandle", "transaction", "layout", "dynamicFilter")); assertEquals( Arrays.stream(CanonicalTableHandle.class.getDeclaredFields()) + .filter(f -> !f.isSynthetic()) .map(Field::getName) .collect(toImmutableSet()), ImmutableSet.of("connectorId", "tableHandle", "layoutIdentifier", "layoutHandle")); diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestDynamicFilter.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestDynamicFilter.java index 76dad95e6ba1c..f65c7e13a5561 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestDynamicFilter.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestDynamicFilter.java @@ -13,6 +13,7 @@ */ package com.facebook.presto.sql.planner; +import com.facebook.presto.Session; import com.facebook.presto.spi.plan.FilterNode; import com.facebook.presto.sql.planner.assertions.BasePlanTest; import com.facebook.presto.sql.planner.plan.EnforceSingleRowNode; @@ -25,6 +26,10 @@ import java.util.Optional; import static com.facebook.presto.SystemSessionProperties.ENABLE_DYNAMIC_FILTERING; +import static com.facebook.presto.SystemSessionProperties.JOIN_DISTRIBUTION_TYPE; +import static com.facebook.presto.SystemSessionProperties.JOIN_REORDERING_STRATEGY; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.PARTITIONED; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anyNot; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anyTree; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.equiJoinClause; @@ -123,6 +128,7 @@ public void testJoin() { assertPlan( "SELECT o.orderkey FROM orders o, lineitem l WHERE l.orderkey = o.orderkey", + noJoinReordering(), anyTree( join( INNER, @@ -140,6 +146,7 @@ public void testJoinOnCast() { assertPlan( "SELECT o.orderkey FROM orders o, lineitem l WHERE cast(l.orderkey as int) = cast(o.orderkey as int)", + noJoinReordering(), anyTree( node( JoinNode.class, @@ -156,6 +163,7 @@ public void testJoinMultipleEquiJoinClauses() { assertPlan( "SELECT o.orderkey FROM orders o, lineitem l WHERE l.orderkey = o.orderkey AND l.partkey = o.custkey", + noJoinReordering(), anyTree( join( INNER, @@ -175,6 +183,7 @@ public void testJoinWithOrderBySameKey() { assertPlan( "SELECT o.orderkey FROM orders o, lineitem l WHERE l.orderkey = o.orderkey ORDER BY l.orderkey ASC, o.orderkey ASC", + noJoinReordering(), anyTree( join( INNER, @@ -234,6 +243,7 @@ public void testInnerInequalityJoinWithEquiJoinConjuncts() { assertPlan( "SELECT 1 FROM orders o JOIN lineitem l ON o.shippriority = l.linenumber AND o.orderkey < l.orderkey", + noJoinReordering(), anyTree( anyNot( FilterNode.class, @@ -254,6 +264,7 @@ public void testSubTreeJoinDFOnProbeSide() { assertPlan( "SELECT part.partkey from part JOIN (lineitem JOIN orders ON lineitem.orderkey = orders.orderkey) ON part.partkey = lineitem.orderkey", + noJoinReordering(), anyTree( join( INNER, @@ -450,4 +461,12 @@ public void testNonPushedDownJoinFilterRemoval() project( tableScan("part", ImmutableMap.of("K2", "partkey", "V2", "size"))))))); } + + private Session noJoinReordering() + { + return Session.builder(this.getQueryRunner().getDefaultSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.name()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, PARTITIONED.name()) + .build(); + } } diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestLogicalPlanner.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestLogicalPlanner.java index f3082ca0fdb73..eb331310a555d 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestLogicalPlanner.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestLogicalPlanner.java @@ -52,6 +52,7 @@ import static com.facebook.presto.SystemSessionProperties.ENFORCE_FIXED_DISTRIBUTION_FOR_OUTPUT_OPERATOR; import static com.facebook.presto.SystemSessionProperties.FORCE_SINGLE_NODE_OUTPUT; import static com.facebook.presto.SystemSessionProperties.JOIN_DISTRIBUTION_TYPE; +import static com.facebook.presto.SystemSessionProperties.JOIN_REORDERING_STRATEGY; import static com.facebook.presto.SystemSessionProperties.OFFSET_CLAUSE_ENABLED; import static com.facebook.presto.SystemSessionProperties.OPTIMIZE_HASH_GENERATION; import static com.facebook.presto.SystemSessionProperties.OPTIMIZE_JOINS_WITH_EMPTY_SOURCES; @@ -65,6 +66,7 @@ import static com.facebook.presto.spi.plan.AggregationNode.Step.FINAL; import static com.facebook.presto.spi.plan.AggregationNode.Step.PARTIAL; import static com.facebook.presto.spi.plan.AggregationNode.Step.SINGLE; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.aggregation; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.any; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anyNot; @@ -235,6 +237,7 @@ public void testWindowAfterJoin() { // Window partition key is a super set of join key. assertDistributedPlan("SELECT rank() OVER (PARTITION BY o.orderstatus, o.orderkey) FROM orders o JOIN lineitem l ON o.orderstatus = l.linestatus", + noJoinReordering(), anyTree( window(windowMatcherBuilder -> windowMatcherBuilder .specification(specification(ImmutableList.of("orderstatus", "orderkey"), ImmutableList.of(), ImmutableMap.of())) @@ -250,6 +253,7 @@ public void testWindowAfterJoin() // Window partition key is not a super set of join key. assertDistributedPlan("SELECT rank() OVER (PARTITION BY o.orderkey) FROM orders o JOIN lineitem l ON o.orderstatus = l.linestatus", + noJoinReordering(), anyTree( window(windowMatcherBuilder -> windowMatcherBuilder .specification(specification(ImmutableList.of("orderkey"), ImmutableList.of(), ImmutableMap.of())) @@ -265,6 +269,7 @@ public void testWindowAfterJoin() // Test broadcast join Session broadcastJoin = Session.builder(this.getQueryRunner().getDefaultSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.name()) .setSystemProperty(JOIN_DISTRIBUTION_TYPE, JoinDistributionType.BROADCAST.name()) .setSystemProperty(FORCE_SINGLE_NODE_OUTPUT, Boolean.toString(false)) .build(); @@ -326,6 +331,7 @@ public void testDistinctLimitOverInequalityJoin() .withExactOutputs(ImmutableList.of("O_ORDERKEY", "L_ORDERKEY"))))))); assertPlan("SELECT DISTINCT o.orderkey FROM orders o JOIN lineitem l ON o.shippriority = l.linenumber AND o.orderkey < l.orderkey LIMIT 1", + noJoinReordering(), anyTree( node(DistinctLimitNode.class, anyTree( @@ -370,6 +376,7 @@ public void testInnerInequalityJoinNoEquiJoinConjuncts() public void testInnerInequalityJoinWithEquiJoinConjuncts() { assertPlan("SELECT 1 FROM orders o JOIN lineitem l ON o.shippriority = l.linenumber AND o.orderkey < l.orderkey", + noJoinReordering(), anyTree( anyNot(FilterNode.class, join(INNER, @@ -400,6 +407,7 @@ public void testLeftConvertedToInnerInequalityJoinNoEquiJoinConjuncts() public void testJoin() { assertPlan("SELECT o.orderkey FROM orders o, lineitem l WHERE l.orderkey = o.orderkey", + noJoinReordering(), anyTree( join(INNER, ImmutableList.of(equiJoinClause("ORDERS_OK", "LINEITEM_OK")), any( @@ -412,6 +420,7 @@ public void testJoin() public void testJoinWithOrderBySameKey() { assertPlan("SELECT o.orderkey FROM orders o, lineitem l WHERE l.orderkey = o.orderkey ORDER BY l.orderkey ASC, o.orderkey ASC", + noJoinReordering(), anyTree( join(INNER, ImmutableList.of(equiJoinClause("ORDERS_OK", "LINEITEM_OK")), any( @@ -613,6 +622,7 @@ public void testCorrelatedSubqueries() public void testCorrelatedScalarSubqueryInSelect() { assertDistributedPlan("SELECT name, (SELECT name FROM region WHERE regionkey = nation.regionkey) FROM nation", + noJoinReordering(), anyTree( filter(format("CASE \"is_distinct\" WHEN true THEN true ELSE CAST(fail(%s, 'Scalar sub-query has returned multiple rows') AS boolean) END", SUBQUERY_MULTIPLE_ROWS.toErrorCode().getCode()), markDistinct("is_distinct", ImmutableList.of("unique"), @@ -630,6 +640,7 @@ public void testStreamingAggregationForCorrelatedSubquery() // Use equi-clause to trigger hash partitioning of the join sources assertDistributedPlan( "SELECT name, (SELECT max(name) FROM region WHERE regionkey = nation.regionkey AND length(name) > length(nation.name)) FROM nation", + noJoinReordering(), anyTree( aggregation( singleGroupingSet("n_name", "n_regionkey", "unique"), @@ -673,6 +684,7 @@ public void testStreamingAggregationOverJoin() // inner join -> streaming aggregation assertPlan("SELECT o.orderkey, count(*) FROM orders o, lineitem l WHERE o.orderkey=l.orderkey GROUP BY 1", + noJoinReordering(), anyTree( aggregation( singleGroupingSet("o_orderkey"), @@ -898,6 +910,7 @@ public void testBroadcastCorrelatedSubqueryAvoidsRemoteExchangeBeforeAggregation public void testUsesDistributedJoinIfNaturallyPartitionedOnProbeSymbols() { Session broadcastJoin = Session.builder(this.getQueryRunner().getDefaultSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.toString()) .setSystemProperty(JOIN_DISTRIBUTION_TYPE, JoinDistributionType.BROADCAST.name()) .setSystemProperty(FORCE_SINGLE_NODE_OUTPUT, Boolean.toString(false)) .setSystemProperty(OPTIMIZE_HASH_GENERATION, Boolean.toString(false)) @@ -1232,6 +1245,8 @@ public void testComplexOrderBy() public void testJoinNullFilters() { Session nullFiltersInJoin = Session.builder(this.getQueryRunner().getDefaultSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.toString()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, JoinDistributionType.PARTITIONED.toString()) .setSystemProperty(OPTIMIZE_NULLS_IN_JOINS, Boolean.toString(true)) .build(); assertPlanWithSession("SELECT nationkey FROM nation INNER JOIN region ON nation.regionkey = region.regionkey", @@ -1373,4 +1388,12 @@ public void testOffset() tableScan("nation", ImmutableMap.of("name", "name", "regionkey", "regionkey")))))) .withAlias("row_num", new RowNumberSymbolMatcher()))))); } + + private Session noJoinReordering() + { + return Session.builder(this.getQueryRunner().getDefaultSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.name()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, JoinDistributionType.PARTITIONED.name()) + .build(); + } } diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPlanMatchingFramework.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPlanMatchingFramework.java index e7f5ab9413c27..87277e79d8318 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPlanMatchingFramework.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPlanMatchingFramework.java @@ -13,6 +13,7 @@ */ package com.facebook.presto.sql.planner; +import com.facebook.presto.Session; import com.facebook.presto.spi.plan.TableScanNode; import com.facebook.presto.sql.planner.assertions.BasePlanTest; import com.facebook.presto.sql.planner.plan.OutputNode; @@ -20,6 +21,10 @@ import com.google.common.collect.ImmutableMap; import org.testng.annotations.Test; +import static com.facebook.presto.SystemSessionProperties.JOIN_DISTRIBUTION_TYPE; +import static com.facebook.presto.SystemSessionProperties.JOIN_REORDERING_STRATEGY; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.PARTITIONED; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.aggregation; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anyTree; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.columnReference; @@ -141,6 +146,7 @@ public void testTableScan() public void testJoinMatcher() { assertPlan("SELECT o.orderkey FROM orders o, lineitem l WHERE l.orderkey = o.orderkey", + noJoinReordering(), anyTree( join(INNER, ImmutableList.of(equiJoinClause("ORDERS_OK", "LINEITEM_OK")), anyTree( @@ -241,6 +247,7 @@ public void testStrictProjectExtraSymbols() public void testDuplicateAliases() { assertPlan("SELECT o.orderkey FROM orders o, lineitem l WHERE l.orderkey = o.orderkey", + noJoinReordering(), anyTree( join(INNER, ImmutableList.of(equiJoinClause("ORDERS_OK", "LINEITEM_OK")), anyTree( @@ -257,4 +264,12 @@ public void testProjectLimitsScope() project(ImmutableMap.of("EXPRESSION", expression("CAST(1 AS bigint) + ORDERKEY")), tableScan("lineitem", ImmutableMap.of("ORDERKEY", "orderkey"))))); } + + private Session noJoinReordering() + { + return Session.builder(this.getQueryRunner().getDefaultSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.name()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, PARTITIONED.name()) + .build(); + } } diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPredicatePushdown.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPredicatePushdown.java index e68c4f48c39d3..38e078f06f864 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPredicatePushdown.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPredicatePushdown.java @@ -31,7 +31,6 @@ import java.util.Optional; import static com.facebook.presto.common.type.IntegerType.INTEGER; -import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.any; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anyTree; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.assignUniqueId; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.equiJoinClause; @@ -68,14 +67,14 @@ public void testNonStraddlingJoinExpression() { assertPlan("SELECT * FROM orders JOIN lineitem ON orders.orderkey = lineitem.orderkey AND cast(lineitem.linenumber AS varchar) = '2'", anyTree( - join(INNER, ImmutableList.of(equiJoinClause("ORDERS_OK", "LINEITEM_OK")), - any( - tableScan("orders", ImmutableMap.of("ORDERS_OK", "orderkey"))), + join(INNER, ImmutableList.of(equiJoinClause("LINEITEM_OK", "ORDERS_OK")), anyTree( filter("cast('2' as varchar) = cast(LINEITEM_LINENUMBER as varchar)", tableScan("lineitem", ImmutableMap.of( "LINEITEM_OK", "orderkey", - "LINEITEM_LINENUMBER", "linenumber"))))))); + "LINEITEM_LINENUMBER", "linenumber")))), + anyTree( + tableScan("orders", ImmutableMap.of("ORDERS_OK", "orderkey")))))); } @Test diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPredicatePushdownWithDynamicFilter.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPredicatePushdownWithDynamicFilter.java index 9e9ea1b99a211..7742533356743 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPredicatePushdownWithDynamicFilter.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestPredicatePushdownWithDynamicFilter.java @@ -47,14 +47,14 @@ public void testNonStraddlingJoinExpression() anyTree( join( INNER, - ImmutableList.of(equiJoinClause("ORDERS_OK", "LINEITEM_OK")), - anyTree(tableScan("orders", ImmutableMap.of("ORDERS_OK", "orderkey"))), + ImmutableList.of(equiJoinClause("LINEITEM_OK", "ORDERS_OK")), anyTree( - filter( - "cast('2' as varchar) = cast(LINEITEM_LINENUMBER as varchar)", + node( + FilterNode.class, tableScan("lineitem", ImmutableMap.of( "LINEITEM_OK", "orderkey", - "LINEITEM_LINENUMBER", "linenumber"))))))); + "LINEITEM_LINENUMBER", "linenumber")))), + anyTree(tableScan("orders", ImmutableMap.of("ORDERS_OK", "orderkey")))))); } @Override diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestStreamingForPartialAggregation.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestStreamingForPartialAggregation.java new file mode 100644 index 0000000000000..35d8969a32230 --- /dev/null +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestStreamingForPartialAggregation.java @@ -0,0 +1,52 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.sql.planner; + +import com.facebook.presto.sql.planner.assertions.BasePlanTest; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.testng.annotations.Test; + +import java.util.Optional; + +import static com.facebook.presto.SystemSessionProperties.STREAMING_FOR_PARTIAL_AGGREGATION_ENABLED; +import static com.facebook.presto.spi.plan.AggregationNode.Step.PARTIAL; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.aggregation; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anyTree; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.functionCall; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.singleGroupingSet; +import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.tableScan; + +public class TestStreamingForPartialAggregation + extends BasePlanTest +{ + TestStreamingForPartialAggregation() + { + super(ImmutableMap.of(STREAMING_FOR_PARTIAL_AGGREGATION_ENABLED, "true")); + } + + @Test + public void testMultidates() + { + assertPlan("SELECT clerk, count(*) FROM orders GROUP BY 1", + anyTree(aggregation( + singleGroupingSet("clerk"), + ImmutableMap.of(Optional.empty(), functionCall("count", ImmutableList.of())), + ImmutableList.of("clerk"), // streaming + ImmutableMap.of(), + Optional.empty(), + PARTIAL, + tableScan("orders", ImmutableMap.of("clerk", "clerk"))))); + } +} diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/assertions/BasePlanTest.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/assertions/BasePlanTest.java index de72928d3e682..8e32a5e85649d 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/planner/assertions/BasePlanTest.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/assertions/BasePlanTest.java @@ -112,16 +112,21 @@ protected void assertPlan(String sql, PlanMatchPattern pattern) assertPlan(sql, LogicalPlanner.Stage.OPTIMIZED_AND_VALIDATED, pattern); } + protected void assertPlan(String sql, Session session, PlanMatchPattern pattern) + { + assertPlan(sql, session, LogicalPlanner.Stage.OPTIMIZED_AND_VALIDATED, pattern, queryRunner.getPlanOptimizers(true)); + } + protected void assertPlan(String sql, LogicalPlanner.Stage stage, PlanMatchPattern pattern) { List optimizers = queryRunner.getPlanOptimizers(true); - assertPlan(sql, stage, pattern, optimizers); + assertPlan(sql, queryRunner.getDefaultSession(), stage, pattern, optimizers); } protected void assertPlan(String sql, PlanMatchPattern pattern, List optimizers) { - assertPlan(sql, LogicalPlanner.Stage.OPTIMIZED, pattern, optimizers); + assertPlan(sql, queryRunner.getDefaultSession(), LogicalPlanner.Stage.OPTIMIZED, pattern, optimizers); } protected void assertPlan(String sql, LogicalPlanner.Stage stage, PlanMatchPattern pattern, Predicate optimizerPredicate) @@ -130,12 +135,12 @@ protected void assertPlan(String sql, LogicalPlanner.Stage stage, PlanMatchPatte .filter(optimizerPredicate) .collect(toList()); - assertPlan(sql, stage, pattern, optimizers); + assertPlan(sql, queryRunner.getDefaultSession(), stage, pattern, optimizers); } - protected void assertPlan(String sql, LogicalPlanner.Stage stage, PlanMatchPattern pattern, List optimizers) + protected void assertPlan(String sql, Session session, LogicalPlanner.Stage stage, PlanMatchPattern pattern, List optimizers) { - queryRunner.inTransaction(transactionSession -> { + queryRunner.inTransaction(session, transactionSession -> { Plan actualPlan = queryRunner.createPlan( transactionSession, sql, @@ -171,7 +176,7 @@ protected void assertMinimallyOptimizedPlan(@Language("SQL") String sql, PlanMat ImmutableSet.of(new RemoveRedundantIdentityProjections())), getExpressionTranslator()); // To avoid assert plan failure not printing out plan (#12885) - assertPlan(sql, LogicalPlanner.Stage.OPTIMIZED, pattern, optimizers); + assertPlan(sql, queryRunner.getDefaultSession(), LogicalPlanner.Stage.OPTIMIZED, pattern, optimizers); } protected void assertPlanWithSession(@Language("SQL") String sql, Session session, boolean forceSingleNode, PlanMatchPattern pattern) diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/optimizations/TestAddExchangesPlans.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/optimizations/TestAddExchangesPlans.java index e4f4a262bae8e..3970eafea7c0e 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/planner/optimizations/TestAddExchangesPlans.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/optimizations/TestAddExchangesPlans.java @@ -33,11 +33,15 @@ import static com.facebook.presto.SystemSessionProperties.AGGREGATION_PARTITIONING_MERGING_STRATEGY; import static com.facebook.presto.SystemSessionProperties.EXCHANGE_MATERIALIZATION_STRATEGY; +import static com.facebook.presto.SystemSessionProperties.JOIN_DISTRIBUTION_TYPE; +import static com.facebook.presto.SystemSessionProperties.JOIN_REORDERING_STRATEGY; import static com.facebook.presto.SystemSessionProperties.PARTITIONING_PRECISION_STRATEGY; import static com.facebook.presto.SystemSessionProperties.TASK_CONCURRENCY; import static com.facebook.presto.SystemSessionProperties.USE_STREAMING_EXCHANGE_FOR_MARK_DISTINCT; import static com.facebook.presto.execution.QueryManagerConfig.ExchangeMaterializationStrategy.ALL; import static com.facebook.presto.spi.plan.AggregationNode.Step.SINGLE; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.PARTITIONED; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static com.facebook.presto.sql.analyzer.FeaturesConfig.PartitioningPrecisionStrategy.PREFER_EXACT_PARTITIONING; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.aggregation; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anySymbol; @@ -99,7 +103,13 @@ public void testRepartitionForUnionWithAnyTableScans() @Test public void testRepartitionForUnionAllBeforeHashJoin() { - assertDistributedPlan("SELECT * FROM (SELECT nationkey FROM nation UNION ALL select nationkey from nation) n join region r on n.nationkey = r.regionkey", + Session session = Session.builder(this.getQueryRunner().getDefaultSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.name()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, PARTITIONED.name()) + .build(); + assertPlanWithSession("SELECT * FROM (SELECT nationkey FROM nation UNION ALL select nationkey from nation) n join region r on n.nationkey = r.regionkey", + session, + false, anyTree( join(INNER, ImmutableList.of(equiJoinClause("nationkey", "regionkey")), anyTree( @@ -114,7 +124,9 @@ public void testRepartitionForUnionAllBeforeHashJoin() anyTree( tableScan("region", ImmutableMap.of("regionkey", "regionkey")))))))); - assertDistributedPlan("SELECT * FROM (SELECT nationkey FROM nation UNION ALL select 1) n join region r on n.nationkey = r.regionkey", + assertPlanWithSession("SELECT * FROM (SELECT nationkey FROM nation UNION ALL select 1) n join region r on n.nationkey = r.regionkey", + session, + false, anyTree( join(INNER, ImmutableList.of(equiJoinClause("nationkey", "regionkey")), anyTree( @@ -469,6 +481,8 @@ void assertExactDistributedPlan(String sql, PlanMatchPattern pattern) TestingSession.testSessionBuilder() .setCatalog("local") .setSchema("tiny") + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.toString()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, PARTITIONED.toString()) .setSystemProperty(PARTITIONING_PRECISION_STRATEGY, PREFER_EXACT_PARTITIONING.toString()) .build(), pattern); diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/optimizations/TestFullOuterJoinWithCoalesce.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/optimizations/TestFullOuterJoinWithCoalesce.java index a3cd96bb8fbd2..4623e9c13347d 100644 --- a/presto-main/src/test/java/com/facebook/presto/sql/planner/optimizations/TestFullOuterJoinWithCoalesce.java +++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/optimizations/TestFullOuterJoinWithCoalesce.java @@ -13,12 +13,17 @@ */ package com.facebook.presto.sql.planner.optimizations; +import com.facebook.presto.Session; import com.facebook.presto.sql.planner.assertions.BasePlanTest; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.testng.annotations.Test; +import static com.facebook.presto.SystemSessionProperties.JOIN_DISTRIBUTION_TYPE; +import static com.facebook.presto.SystemSessionProperties.JOIN_REORDERING_STRATEGY; import static com.facebook.presto.spi.plan.AggregationNode.Step.PARTIAL; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.PARTITIONED; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.aggregation; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.anyTree; import static com.facebook.presto.sql.planner.assertions.PlanMatchPattern.equiJoinClause; @@ -103,6 +108,10 @@ public void testDuplicatePartitionColumn() " ON t.a = s.a AND t.a = s.b) ts " + "FULL OUTER JOIN (VALUES (2, 2), (5, 5)) r(a, b) " + "ON ts.a = r.a and ts.b = r.b", + Session.builder(this.getQueryRunner().getDefaultSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.name()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, PARTITIONED.name()) + .build(), anyTree( project( ImmutableMap.of("tsra", expression("coalesce(ra, tsa)"), "tsrb", expression("coalesce(tsb, rb)")), diff --git a/presto-matching/pom.xml b/presto-matching/pom.xml index 2cdef59e067a7..8a05259e8f01b 100644 --- a/presto-matching/pom.xml +++ b/presto-matching/pom.xml @@ -18,7 +18,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-matching diff --git a/presto-memory-context/pom.xml b/presto-memory-context/pom.xml index 45e6c6755f083..658bdc1a7320e 100644 --- a/presto-memory-context/pom.xml +++ b/presto-memory-context/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-memory-context diff --git a/presto-memory/pom.xml b/presto-memory/pom.xml index 3d0bc327046e8..3efd3726382fe 100644 --- a/presto-memory/pom.xml +++ b/presto-memory/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-memory diff --git a/presto-ml/pom.xml b/presto-ml/pom.xml index 9087ff2ee79c2..3de1a8466b911 100644 --- a/presto-ml/pom.xml +++ b/presto-ml/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-ml diff --git a/presto-mongodb/pom.xml b/presto-mongodb/pom.xml index 013e8bd61936d..823cb9a052114 100644 --- a/presto-mongodb/pom.xml +++ b/presto-mongodb/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-mongodb diff --git a/presto-mysql/pom.xml b/presto-mysql/pom.xml index 2dccfac1fc8b0..57e2decd97acb 100644 --- a/presto-mysql/pom.xml +++ b/presto-mysql/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-mysql diff --git a/presto-node-ttl-fetchers/pom.xml b/presto-node-ttl-fetchers/pom.xml index de0173012d6bf..b9e8136ee6747 100644 --- a/presto-node-ttl-fetchers/pom.xml +++ b/presto-node-ttl-fetchers/pom.xml @@ -7,7 +7,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-node-ttl-fetchers diff --git a/presto-oracle/pom.xml b/presto-oracle/pom.xml index cc4d254e1f837..c851d27160a01 100644 --- a/presto-oracle/pom.xml +++ b/presto-oracle/pom.xml @@ -7,7 +7,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-oracle diff --git a/presto-orc/pom.xml b/presto-orc/pom.xml index f6e8b7ee43ec7..95b07ca2f6d48 100644 --- a/presto-orc/pom.xml +++ b/presto-orc/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-orc diff --git a/presto-orc/src/main/java/com/facebook/presto/orc/OrcReaderOptions.java b/presto-orc/src/main/java/com/facebook/presto/orc/OrcReaderOptions.java index 6eb21e87452ec..5241031e87b70 100644 --- a/presto-orc/src/main/java/com/facebook/presto/orc/OrcReaderOptions.java +++ b/presto-orc/src/main/java/com/facebook/presto/orc/OrcReaderOptions.java @@ -25,10 +25,24 @@ public class OrcReaderOptions private final boolean zstdJniDecompressionEnabled; private final boolean mapNullKeysEnabled; private final boolean enableTimestampMicroPrecision; + // if the option is set to true, OrcSelectiveReader will append a row number block at the end of the page + private final boolean appendRowNumber; - public OrcReaderOptions(DataSize maxMergeDistance, DataSize tinyStripeThreshold, DataSize maxBlockSize, boolean zstdJniDecompressionEnabled) + public OrcReaderOptions(DataSize maxMergeDistance, + DataSize tinyStripeThreshold, + DataSize maxBlockSize, + boolean zstdJniDecompressionEnabled) { - this(maxMergeDistance, tinyStripeThreshold, maxBlockSize, zstdJniDecompressionEnabled, false, false); + this(maxMergeDistance, tinyStripeThreshold, maxBlockSize, zstdJniDecompressionEnabled, false, false, false); + } + + public OrcReaderOptions(DataSize maxMergeDistance, + DataSize tinyStripeThreshold, + DataSize maxBlockSize, + boolean zstdJniDecompressionEnabled, + boolean appendRowNumber) + { + this(maxMergeDistance, tinyStripeThreshold, maxBlockSize, zstdJniDecompressionEnabled, false, false, appendRowNumber); } public OrcReaderOptions( @@ -37,7 +51,8 @@ public OrcReaderOptions( DataSize maxBlockSize, boolean zstdJniDecompressionEnabled, boolean mapNullKeysEnabled, - boolean enableTimestampMicroPrecision) + boolean enableTimestampMicroPrecision, + boolean appendRowNumber) { this.maxMergeDistance = requireNonNull(maxMergeDistance, "maxMergeDistance is null"); this.maxBlockSize = requireNonNull(maxBlockSize, "maxBlockSize is null"); @@ -45,6 +60,7 @@ public OrcReaderOptions( this.zstdJniDecompressionEnabled = zstdJniDecompressionEnabled; this.mapNullKeysEnabled = mapNullKeysEnabled; this.enableTimestampMicroPrecision = enableTimestampMicroPrecision; + this.appendRowNumber = appendRowNumber; } public DataSize getMaxMergeDistance() @@ -76,4 +92,9 @@ public boolean enableTimestampMicroPrecision() { return enableTimestampMicroPrecision; } + + public boolean appendRowNumber() + { + return appendRowNumber; + } } diff --git a/presto-orc/src/main/java/com/facebook/presto/orc/OrcRecordReaderOptions.java b/presto-orc/src/main/java/com/facebook/presto/orc/OrcRecordReaderOptions.java index d786c99dddfaf..86145a91a311f 100644 --- a/presto-orc/src/main/java/com/facebook/presto/orc/OrcRecordReaderOptions.java +++ b/presto-orc/src/main/java/com/facebook/presto/orc/OrcRecordReaderOptions.java @@ -24,10 +24,11 @@ public class OrcRecordReaderOptions private final DataSize maxBlockSize; private final boolean mapNullKeysEnabled; private final boolean enableTimestampMicroPrecision; + private final boolean appendRowNumber; public OrcRecordReaderOptions(OrcReaderOptions options) { - this(options.getMaxMergeDistance(), options.getTinyStripeThreshold(), options.getMaxBlockSize(), options.mapNullKeysEnabled(), options.enableTimestampMicroPrecision()); + this(options.getMaxMergeDistance(), options.getTinyStripeThreshold(), options.getMaxBlockSize(), options.mapNullKeysEnabled(), options.enableTimestampMicroPrecision(), options.appendRowNumber()); } public OrcRecordReaderOptions( @@ -35,13 +36,15 @@ public OrcRecordReaderOptions( DataSize tinyStripeThreshold, DataSize maxBlockSize, boolean mapNullKeysEnabled, - boolean enableTimestampMicroPrecision) + boolean enableTimestampMicroPrecision, + boolean appendRowNumber) { this.maxMergeDistance = requireNonNull(maxMergeDistance, "maxMergeDistance is null"); this.maxBlockSize = requireNonNull(maxBlockSize, "maxBlockSize is null"); this.tinyStripeThreshold = requireNonNull(tinyStripeThreshold, "tinyStripeThreshold is null"); this.mapNullKeysEnabled = mapNullKeysEnabled; this.enableTimestampMicroPrecision = enableTimestampMicroPrecision; + this.appendRowNumber = appendRowNumber; } public DataSize getMaxMergeDistance() @@ -68,4 +71,9 @@ public boolean enableTimestampMicroPrecision() { return enableTimestampMicroPrecision; } + + public boolean appendRowNumber() + { + return appendRowNumber; + } } diff --git a/presto-orc/src/main/java/com/facebook/presto/orc/OrcSelectiveRecordReader.java b/presto-orc/src/main/java/com/facebook/presto/orc/OrcSelectiveRecordReader.java index d098aed4f2ec7..e33e48501fcee 100644 --- a/presto-orc/src/main/java/com/facebook/presto/orc/OrcSelectiveRecordReader.java +++ b/presto-orc/src/main/java/com/facebook/presto/orc/OrcSelectiveRecordReader.java @@ -20,6 +20,7 @@ import com.facebook.presto.common.block.BlockLease; import com.facebook.presto.common.block.LazyBlock; import com.facebook.presto.common.block.LazyBlockLoader; +import com.facebook.presto.common.block.LongArrayBlock; import com.facebook.presto.common.block.RunLengthEncodedBlock; import com.facebook.presto.common.predicate.FilterFunction; import com.facebook.presto.common.predicate.TupleDomainFilter; @@ -148,6 +149,9 @@ public class OrcSelectiveRecordReader private int readPositions; + // true if row number needs to be added, false otherwise + private final boolean appendRowNumber; + public OrcSelectiveRecordReader( Map includedColumns, // key: hiveColumnIndex List outputColumns, // elements are hive column indices @@ -260,6 +264,7 @@ public OrcSelectiveRecordReader( requireNonNull(constantValues, "constantValues is null"); this.constantValues = new Object[this.hiveColumnIndices.length]; + this.appendRowNumber = options.appendRowNumber(); for (int columnIndex : includedColumns.keySet()) { if (!isColumnPresent(columnIndex)) { // Any filter not true of null on a missing column @@ -631,7 +636,6 @@ public Page getNextPage() if (batchSize < 0) { return null; } - readPositions += batchSize; initializePositions(batchSize); @@ -716,7 +720,7 @@ public Page getNextPage() } } - Block[] blocks = new Block[outputColumns.size()]; + Block[] blocks = new Block[ appendRowNumber ? outputColumns.size() + 1 : outputColumns.size()]; for (int i = 0; i < outputColumns.size(); i++) { int columnIndex = outputColumns.get(i); if (constantValues[columnIndex] != null) { @@ -737,10 +741,11 @@ else if (!hasAnyFilter(columnIndex)) { } } + if (appendRowNumber) { + blocks[outputColumns.size()] = createRowNumbersBlock(positionsToRead, positionCount, this.getFilePosition()); + } Page page = new Page(positionCount, blocks); - validateWritePageChecksum(page); - return page; } @@ -882,6 +887,15 @@ private void initializeOutputPositions(int positionCount) } } + private static Block createRowNumbersBlock(int[] positionsToRead, int positionCount, long startRowNumber) + { + long[] rowNumbers = new long[positionCount]; + for (int i = 0; i < positionCount; i++) { + rowNumbers[i] = positionsToRead[i] + startRowNumber; + } + return new LongArrayBlock(positionCount, Optional.empty(), rowNumbers); + } + @Override public void close() throws IOException diff --git a/presto-orc/src/main/java/com/facebook/presto/orc/OrcWriteValidation.java b/presto-orc/src/main/java/com/facebook/presto/orc/OrcWriteValidation.java index ce311b10eff62..841d04c816df2 100644 --- a/presto-orc/src/main/java/com/facebook/presto/orc/OrcWriteValidation.java +++ b/presto-orc/src/main/java/com/facebook/presto/orc/OrcWriteValidation.java @@ -490,7 +490,8 @@ public void addStripe(long rowCount) public void addPage(Page page) { requireNonNull(page, "page is null"); - checkArgument(page.getChannelCount() == columnHashes.size(), "invalid page"); + // When append row number is set to true, the page will have an additional block appended at the end + checkArgument(page.getChannelCount() >= columnHashes.size(), "invalid page"); for (int channel = 0; channel < columnHashes.size(); channel++) { Type type = types.get(channel); diff --git a/presto-orc/src/test/java/com/facebook/presto/orc/OrcTester.java b/presto-orc/src/test/java/com/facebook/presto/orc/OrcTester.java index 7721d6af31f48..bc3b473869d07 100644 --- a/presto-orc/src/test/java/com/facebook/presto/orc/OrcTester.java +++ b/presto-orc/src/test/java/com/facebook/presto/orc/OrcTester.java @@ -899,7 +899,8 @@ public static void assertFileContentsPresto( includedColumns, outputColumns, false, - new TestingHiveOrcAggregatedMemoryContext())) { + new TestingHiveOrcAggregatedMemoryContext(), + false)) { assertEquals(recordReader.getReaderPosition(), 0); assertEquals(recordReader.getFilePosition(), 0); assertFileContentsPresto(types, recordReader, expectedValues, outputColumns); @@ -1440,7 +1441,17 @@ static OrcBatchRecordReader createCustomOrcRecordReader(TempFile tempFile, OrcEn static OrcBatchRecordReader createCustomOrcRecordReader(TempFile tempFile, OrcEncoding orcEncoding, OrcPredicate predicate, List types, int initialBatchSize, boolean cacheable, boolean mapNullKeysEnabled) throws IOException { - return createCustomOrcRecordReader(tempFile, orcEncoding, predicate, types, initialBatchSize, new StorageOrcFileTailSource(), new StorageStripeMetadataSource(), cacheable, ImmutableMap.of(), mapNullKeysEnabled); + return createCustomOrcRecordReader( + tempFile, + orcEncoding, + predicate, + types, + initialBatchSize, + new StorageOrcFileTailSource(), + new StorageStripeMetadataSource(), + cacheable, + ImmutableMap.of(), + mapNullKeysEnabled); } static OrcBatchRecordReader createCustomOrcRecordReader( @@ -1469,6 +1480,7 @@ static OrcBatchRecordReader createCustomOrcRecordReader( MAX_BLOCK_SIZE, false, mapNullKeysEnabled, + false, false), cacheable, new DwrfEncryptionProvider(new UnsupportedEncryptionLibrary(), new TestingEncryptionLibrary()), @@ -1504,6 +1516,7 @@ static OrcReader createCustomOrcReader( MAX_BLOCK_SIZE, false, mapNullKeysEnabled, + false, false), false, new DwrfEncryptionProvider(new UnsupportedEncryptionLibrary(), new TestingEncryptionLibrary()), @@ -1636,7 +1649,8 @@ static OrcSelectiveRecordReader createCustomOrcSelectiveRecordReader( OrcPredicate predicate, Type type, int initialBatchSize, - boolean mapNullKeysEnabled) + boolean mapNullKeysEnabled, + boolean appendRowNumber) throws IOException { return createCustomOrcSelectiveRecordReader( @@ -1654,7 +1668,8 @@ static OrcSelectiveRecordReader createCustomOrcSelectiveRecordReader( ImmutableMap.of(0, type), ImmutableList.of(0), mapNullKeysEnabled, - new TestingHiveOrcAggregatedMemoryContext()); + new TestingHiveOrcAggregatedMemoryContext(), + appendRowNumber); } public static OrcSelectiveRecordReader createCustomOrcSelectiveRecordReader( @@ -1672,7 +1687,8 @@ public static OrcSelectiveRecordReader createCustomOrcSelectiveRecordReader( Map includedColumns, List outputColumns, boolean mapNullKeysEnabled, - OrcAggregatedMemoryContext systemMemoryUsage) + OrcAggregatedMemoryContext systemMemoryUsage, + boolean appendRowNumber) throws IOException { OrcDataSource orcDataSource = new FileOrcDataSource(file, new DataSize(1, MEGABYTE), new DataSize(1, MEGABYTE), new DataSize(1, MEGABYTE), true); @@ -1688,7 +1704,8 @@ public static OrcSelectiveRecordReader createCustomOrcSelectiveRecordReader( MAX_BLOCK_SIZE, false, mapNullKeysEnabled, - false), + false, + appendRowNumber), false, new DwrfEncryptionProvider(new UnsupportedEncryptionLibrary(), new TestingEncryptionLibrary()), DwrfKeyProvider.of(intermediateEncryptionKeys), diff --git a/presto-orc/src/test/java/com/facebook/presto/orc/TestDecryption.java b/presto-orc/src/test/java/com/facebook/presto/orc/TestDecryption.java index 2fb2a086f9dd9..11a71fb600f85 100644 --- a/presto-orc/src/test/java/com/facebook/presto/orc/TestDecryption.java +++ b/presto-orc/src/test/java/com/facebook/presto/orc/TestDecryption.java @@ -493,6 +493,7 @@ public void testSkipFirstStripe() MAX_BLOCK_SIZE, false, false, + false, false), false, new DwrfEncryptionProvider(new UnsupportedEncryptionLibrary(), new TestingPlainKeyEncryptionLibrary()), diff --git a/presto-orc/src/test/java/com/facebook/presto/orc/TestDictionaryColumnWriter.java b/presto-orc/src/test/java/com/facebook/presto/orc/TestDictionaryColumnWriter.java index cec505d0988d2..569954cdbbb37 100644 --- a/presto-orc/src/test/java/com/facebook/presto/orc/TestDictionaryColumnWriter.java +++ b/presto-orc/src/test/java/com/facebook/presto/orc/TestDictionaryColumnWriter.java @@ -847,7 +847,8 @@ private List testDictionary(Type type, OrcEncoding encoding, OrcWr OrcPredicate.TRUE, type, INITIAL_BATCH_SIZE, - true)) { + true, + false)) { while (index < values.size()) { Page page = reader.getNextPage(); if (page == null) { diff --git a/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcMapNullKey.java b/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcMapNullKey.java index 09b5d05e274ba..06c43bea50cb5 100644 --- a/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcMapNullKey.java +++ b/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcMapNullKey.java @@ -100,7 +100,8 @@ public void testMapTypeWithNullsWithSelectiveReader(boolean mapNullKeysEnabled) OrcPredicate.TRUE, mapType, INITIAL_BATCH_SIZE, - mapNullKeysEnabled)) { + mapNullKeysEnabled, + false)) { assertEquals(readMap(reader.getNextPage().getBlock(0).getLoadedBlock(), 0), expectedToRead); assertNull(reader.getNextPage()); diff --git a/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcReaderPositions.java b/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcReaderPositions.java index 2c8735e7f9d79..4be9af4c0b156 100644 --- a/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcReaderPositions.java +++ b/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcReaderPositions.java @@ -13,12 +13,18 @@ */ package com.facebook.presto.orc; +import com.facebook.presto.common.Page; import com.facebook.presto.common.RuntimeStats; import com.facebook.presto.common.block.Block; +import com.facebook.presto.common.function.SqlFunctionProperties; +import com.facebook.presto.common.predicate.FilterFunction; +import com.facebook.presto.common.relation.Predicate; import com.facebook.presto.orc.cache.StorageOrcFileTailSource; import com.facebook.presto.orc.metadata.CompressionKind; import com.facebook.presto.orc.metadata.Footer; import com.facebook.presto.orc.metadata.statistics.IntegerStatistics; +import com.facebook.presto.spi.ConnectorSession; +import com.facebook.presto.testing.TestingConnectorSession; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; @@ -43,7 +49,10 @@ import java.io.IOException; import java.lang.reflect.Field; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.stream.LongStream; import static com.facebook.presto.common.type.BigintType.BIGINT; import static com.facebook.presto.common.type.VarcharType.VARCHAR; @@ -56,6 +65,7 @@ import static com.facebook.presto.orc.OrcTester.Format.ORC_12; import static com.facebook.presto.orc.OrcTester.MAX_BLOCK_SIZE; import static com.facebook.presto.orc.OrcTester.createCustomOrcRecordReader; +import static com.facebook.presto.orc.OrcTester.createCustomOrcSelectiveRecordReader; import static com.facebook.presto.orc.OrcTester.createOrcRecordWriter; import static com.facebook.presto.orc.OrcTester.createSettableStructObjectInspector; import static io.airlift.units.DataSize.Unit.MEGABYTE; @@ -63,6 +73,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.hadoop.hive.ql.io.orc.CompressionKind.SNAPPY; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; public class TestOrcReaderPositions @@ -136,12 +147,158 @@ public void testStripeSkipping() } } + @Test + public void testCompleteFileWithAppendRowNumber() + throws Exception + { + try (TempFile tempFile = new TempFile()) { + // create single stripe file with multiple row groups + int rowCount = 142_000; + createSequentialFile(tempFile.getFile(), rowCount); + List expectedValues = new ArrayList<>(); + expectedValues.addAll(LongStream.range(0, 142_000).collect(ArrayList::new, List::add, List::addAll)); + OrcSelectiveRecordReader reader = createCustomOrcSelectiveRecordReader(tempFile, ORC, OrcPredicate.TRUE, BIGINT, MAX_BATCH_SIZE, false, true); + verifyAppendNumber(expectedValues, reader); + } + } + + @Test + public void testCompleteFileWithAppendRowNumberWithValidation() + throws Exception + { + try (TempFile tempFile = new TempFile()) { + // create single stripe file with multiple row groups + int rowCount = 142_000; + createSequentialFile(tempFile.getFile(), rowCount); + List expectedValues = new ArrayList<>(); + expectedValues.addAll(LongStream.range(0, 142_000).collect(ArrayList::new, List::add, List::addAll)); + OrcSelectiveRecordReader reader = createCustomOrcSelectiveRecordReader(tempFile, ORC, OrcPredicate.TRUE, BIGINT, MAX_BATCH_SIZE, false, true); + verifyAppendNumber(expectedValues, reader); + } + } + + @Test + public void testFilterFunctionWithAppendRowNumber() + throws Exception + { + try (TempFile tempFile = new TempFile()) { + int rowCount = 100; + createSequentialFile(tempFile.getFile(), rowCount); + List expectedValues = LongStream.range(0, 100).boxed().filter(input -> input % 2 != 0) + .collect(ArrayList::new, List::add, List::addAll); + + ConnectorSession session = new TestingConnectorSession(ImmutableList.of()); + FilterFunction filter = new FilterFunction(session.getSqlFunctionProperties(), true, new IsOddPredicate()); + OrcSelectiveRecordReader reader = createCustomOrcSelectiveRecordReader(tempFile.getFile(), + ORC, + OrcPredicate.TRUE, + ImmutableList.of(BIGINT), + MAX_BATCH_SIZE, + ImmutableMap.of(), + ImmutableList.of(filter), + ImmutableMap.of(0, 0), + ImmutableMap.of(), + ImmutableMap.of(), + ImmutableMap.of(), + ImmutableMap.of(0, BIGINT), + ImmutableList.of(0), + false, + new TestingHiveOrcAggregatedMemoryContext(), + true); + verifyAppendNumber(expectedValues, reader); + } + } + + @Test + public void testRowGroupSkippingWithAppendRowNumber() + throws Exception + { + try (TempFile tempFile = new TempFile()) { + // create single stripe file with multiple row groups + int rowCount = 142_000; + createSequentialFile(tempFile.getFile(), rowCount); + // test reading two row groups from middle of file + OrcPredicate predicate = (numberOfRows, statisticsByColumnIndex) -> { + if (numberOfRows == rowCount) { + return true; + } + IntegerStatistics stats = statisticsByColumnIndex.get(0).getIntegerStatistics(); + return (stats.getMin() == 50_000) || (stats.getMin() == 70_000); + }; + List expectedValues = new ArrayList<>(); + expectedValues.addAll(LongStream.range(50_000, 60_000).collect(ArrayList::new, List::add, List::addAll)); + expectedValues.addAll(LongStream.range(70_000, 80_000).collect(ArrayList::new, List::add, List::addAll)); + OrcSelectiveRecordReader reader = createCustomOrcSelectiveRecordReader(tempFile, ORC, predicate, BIGINT, MAX_BATCH_SIZE, false, true); + verifyAppendNumber(expectedValues, reader); + } + } + + @Test + public void testStripeSkippingWithAppendNumber() + throws Exception + { + try (TempFile tempFile = new TempFile()) { + createMultiStripeFile(tempFile.getFile()); + // EVery stripe has 20 rows and there are total of 5 stripes + // test reading second and fourth stripes + OrcPredicate predicate = (numberOfRows, statisticsByColumnIndex) -> { + if (numberOfRows == 100) { + return true; + } + IntegerStatistics stats = statisticsByColumnIndex.get(0).getIntegerStatistics(); + return ((stats.getMin() == 60) && (stats.getMax() == 117)) || + ((stats.getMin() == 180) && (stats.getMax() == 237)); + }; + + List expectedValues = new ArrayList<>(); + expectedValues.addAll(LongStream.range(20, 40).collect(ArrayList::new, List::add, List::addAll)); + expectedValues.addAll(LongStream.range(60, 80).collect(ArrayList::new, List::add, List::addAll)); + + List actualValues = new ArrayList<>(); + OrcSelectiveRecordReader reader = createCustomOrcSelectiveRecordReader(tempFile, ORC, predicate, BIGINT, MAX_BATCH_SIZE, false, true); + assertNotNull(reader); + Page returnPage; + while (true) { + returnPage = reader.getNextPage(); + if (returnPage == null) { + break; + } + Block rowNumberBlock = returnPage.getBlock(1); + for (int i = 0; i < returnPage.getPositionCount(); i++) { + actualValues.add(rowNumberBlock.getLong(i)); + } + } + assertEquals(actualValues, expectedValues); + } + } + + private void verifyAppendNumber(List expectedValues, OrcSelectiveRecordReader reader) + throws IOException + { + assertNotNull(reader); + assertNotNull(expectedValues); + List actualValues = new ArrayList<>(); + while (true) { + Page returnPage = reader.getNextPage(); + if (returnPage == null) { + break; + } + Block dataBlock = returnPage.getBlock(0); + Block rowNumberBlock = returnPage.getBlock(1); + for (int i = 0; i < returnPage.getPositionCount(); i++) { + actualValues.add(dataBlock.getLong(i)); + assertEquals(dataBlock.getLong(i), rowNumberBlock.getLong(i)); + } + } + assertEquals(actualValues, expectedValues); + } + @Test public void testRowGroupSkipping() throws Exception { try (TempFile tempFile = new TempFile()) { - // create single strip file with multiple row groups + // create single stripe file with multiple row groups int rowCount = 142_000; createSequentialFile(tempFile.getFile(), rowCount); @@ -518,4 +675,21 @@ private static void createGrowingSequentialFile(File file, int count, int step, writer.close(false); } + + private static class IsOddPredicate + implements Predicate + { + @Override + public int[] getInputChannels() + { + return new int[] {0}; + } + + @Override + public boolean evaluate(SqlFunctionProperties properties, Page page, int position) + { + long number = page.getBlock(0).getLong(position); + return (number & 1) == 1; + } + } } diff --git a/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcSelectiveStreamReaders.java b/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcSelectiveStreamReaders.java index 020b832333dd0..49445150346a4 100644 --- a/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcSelectiveStreamReaders.java +++ b/presto-orc/src/test/java/com/facebook/presto/orc/TestOrcSelectiveStreamReaders.java @@ -105,7 +105,8 @@ public void testEmptyStrings() includedColumns, outputColumns, false, - systemMemoryUsage)) { + systemMemoryUsage, + false)) { assertEquals(recordReader.getReaderPosition(), 0); assertEquals(recordReader.getFilePosition(), 0); diff --git a/presto-orc/src/test/java/com/facebook/presto/orc/TestSelectiveOrcReader.java b/presto-orc/src/test/java/com/facebook/presto/orc/TestSelectiveOrcReader.java index fc0489aa6e486..5f67514aa3638 100644 --- a/presto-orc/src/test/java/com/facebook/presto/orc/TestSelectiveOrcReader.java +++ b/presto-orc/src/test/java/com/facebook/presto/orc/TestSelectiveOrcReader.java @@ -978,7 +978,8 @@ private void testMemoryTracking(CompressionKind compression, long lowerRetainedM includedColumns, outputColumns, false, - systemMemoryUsage)) { + systemMemoryUsage, + false)) { assertEquals(recordReader.getReaderPosition(), 0); assertEquals(recordReader.getFilePosition(), 0); @@ -1040,7 +1041,8 @@ public void testOutputNotRequired() includedColumns, outputColumns, false, - new TestingHiveOrcAggregatedMemoryContext())) { + new TestingHiveOrcAggregatedMemoryContext(), + false)) { assertEquals(recordReader.getReaderPosition(), 0); assertEquals(recordReader.getFilePosition(), 0); @@ -1095,7 +1097,7 @@ public void testAdaptiveBatchSizes() System.out.println(System.currentTimeMillis() - start); writeOrcColumnsPresto(tempFile.getFile(), DWRF, NONE, Optional.empty(), types, ImmutableList.of(values), new OrcWriterStats()); - try (OrcSelectiveRecordReader recordReader = createCustomOrcSelectiveRecordReader(tempFile, OrcEncoding.DWRF, OrcPredicate.TRUE, type, MAX_BATCH_SIZE, false)) { + try (OrcSelectiveRecordReader recordReader = createCustomOrcSelectiveRecordReader(tempFile, OrcEncoding.DWRF, OrcPredicate.TRUE, type, MAX_BATCH_SIZE, false, false)) { assertEquals(recordReader.getFileRowCount(), rowCount); assertEquals(recordReader.getReaderRowCount(), rowCount); assertEquals(recordReader.getFilePosition(), 0); @@ -1162,7 +1164,8 @@ public void testHiddenConstantColumns() includedColumns, outputColumns, false, - systemMemoryUsage)) { + systemMemoryUsage, + false)) { Page page = recordReader.getNextPage(); assertEquals(page.getPositionCount(), 1); diff --git a/presto-parquet/pom.xml b/presto-parquet/pom.xml index c6105bcd7a9c7..d20d8a87244d3 100644 --- a/presto-parquet/pom.xml +++ b/presto-parquet/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-parquet diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/ColumnReader.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/ColumnReader.java index 43238a1b2cccb..dfde65e1ddd94 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/ColumnReader.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/ColumnReader.java @@ -15,12 +15,13 @@ import com.facebook.presto.parquet.reader.ColumnChunk; import com.facebook.presto.parquet.reader.PageReader; +import org.apache.parquet.internal.filter2.columnindex.RowRanges; public interface ColumnReader { boolean isInitialized(); - void init(PageReader pageReader, Field field); + void init(PageReader pageReader, Field field, RowRanges rowRanges); void prepareNextRead(int batchSize); diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPage.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPage.java index 065684e6f91fb..27667ed7ec1ec 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPage.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPage.java @@ -13,15 +13,33 @@ */ package com.facebook.presto.parquet; +import java.util.Optional; + public abstract class DataPage extends Page { protected final int valueCount; + private final long firstRowIndex; public DataPage(int compressedSize, int uncompressedSize, int valueCount) + { + this(compressedSize, uncompressedSize, valueCount, -1); + } + + DataPage(int compressedSize, int uncompressedSize, int valueCount, long firstRowIndex) { super(compressedSize, uncompressedSize); this.valueCount = valueCount; + this.firstRowIndex = firstRowIndex; + } + + /** + * @return the index of the first row in this page if the related data is available (the optional column-index + * contains this value) + */ + public Optional getFirstRowIndex() + { + return firstRowIndex < 0 ? Optional.empty() : Optional.of(firstRowIndex); } public int getValueCount() diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPageV1.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPageV1.java index 87c9ebe70a0bf..0f172651e98f8 100755 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPageV1.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPageV1.java @@ -32,12 +32,13 @@ public DataPageV1( Slice slice, int valueCount, int uncompressedSize, + long firstRowIndex, Statistics statistics, ParquetEncoding repetitionLevelEncoding, ParquetEncoding definitionLevelEncoding, ParquetEncoding valuesEncoding) { - super(slice.length(), uncompressedSize, valueCount); + super(slice.length(), uncompressedSize, valueCount, firstRowIndex); this.slice = requireNonNull(slice, "slice is null"); this.statistics = statistics; this.repetitionLevelEncoding = repetitionLevelEncoding; @@ -82,6 +83,7 @@ public String toString() .add("valueCount", valueCount) .add("compressedSize", compressedSize) .add("uncompressedSize", uncompressedSize) + .add("firstRowIndex", getFirstRowIndex()) .toString(); } } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPageV2.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPageV2.java index 7d2f4d0b934ff..569d715cacd93 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPageV2.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/DataPageV2.java @@ -35,6 +35,7 @@ public DataPageV2( int rowCount, int nullCount, int valueCount, + long firstRowIndex, Slice repetitionLevels, Slice definitionLevels, ParquetEncoding dataEncoding, @@ -43,7 +44,7 @@ public DataPageV2( Statistics statistics, boolean isCompressed) { - super(repetitionLevels.length() + definitionLevels.length() + slice.length(), uncompressedSize, valueCount); + super(repetitionLevels.length() + definitionLevels.length() + slice.length(), uncompressedSize, valueCount, firstRowIndex); this.rowCount = rowCount; this.nullCount = nullCount; this.repetitionLevels = requireNonNull(repetitionLevels, "repetitionLevels slice is null"); @@ -109,6 +110,7 @@ public String toString() .add("valueCount", valueCount) .add("compressedSize", compressedSize) .add("uncompressedSize", uncompressedSize) + .add("firstRowIndex", getFirstRowIndex()) .toString(); } } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/FileParquetDataSource.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/FileParquetDataSource.java index 3f8f8f8f88ad5..964035c5651f4 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/FileParquetDataSource.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/FileParquetDataSource.java @@ -28,11 +28,16 @@ package com.facebook.presto.parquet; +import org.apache.parquet.hadoop.metadata.ColumnChunkMetaData; +import org.apache.parquet.internal.column.columnindex.ColumnIndex; +import org.apache.parquet.internal.column.columnindex.OffsetIndex; + import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UncheckedIOException; +import java.util.Optional; public class FileParquetDataSource extends AbstractParquetDataSource @@ -64,4 +69,16 @@ protected void readInternal(long position, byte[] buffer, int bufferOffset, int throw new UncheckedIOException(e); } } + + @Override + public Optional readColumnIndex(ColumnChunkMetaData column) throws IOException + { + throw new UnsupportedOperationException(); + } + + @Override + public Optional readOffsetIndex(ColumnChunkMetaData column) throws IOException + { + throw new UnsupportedOperationException(); + } } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/ParquetDataSource.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/ParquetDataSource.java index 630fea44acee7..44278d23570ad 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/ParquetDataSource.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/ParquetDataSource.java @@ -13,8 +13,13 @@ */ package com.facebook.presto.parquet; +import org.apache.parquet.hadoop.metadata.ColumnChunkMetaData; +import org.apache.parquet.internal.column.columnindex.ColumnIndex; +import org.apache.parquet.internal.column.columnindex.OffsetIndex; + import java.io.Closeable; import java.io.IOException; +import java.util.Optional; public interface ParquetDataSource extends Closeable @@ -29,6 +34,10 @@ public interface ParquetDataSource void readFully(long position, byte[] buffer, int bufferOffset, int bufferLength); + Optional readColumnIndex(ColumnChunkMetaData column) throws IOException; + + Optional readOffsetIndex(ColumnChunkMetaData column) throws IOException; + @Override default void close() throws IOException diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/AbstractNestedBatchReader.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/AbstractNestedBatchReader.java index 9d2df83b8f293..8e246a56a5d1c 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/AbstractNestedBatchReader.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/AbstractNestedBatchReader.java @@ -29,6 +29,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import org.apache.parquet.Preconditions; +import org.apache.parquet.internal.filter2.columnindex.RowRanges; import org.apache.parquet.io.ParquetDecodingException; import java.io.IOException; @@ -77,7 +78,7 @@ public boolean isInitialized() } @Override - public void init(PageReader pageReader, Field field) + public void init(PageReader pageReader, Field field, RowRanges rowRanges) { Preconditions.checkState(!isInitialized(), "already initialized"); this.pageReader = requireNonNull(pageReader, "pageReader is null"); diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/BinaryFlatBatchReader.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/BinaryFlatBatchReader.java index 1a409fdb164d9..585103c146083 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/BinaryFlatBatchReader.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/BinaryFlatBatchReader.java @@ -33,6 +33,7 @@ import com.facebook.presto.spi.PrestoException; import io.airlift.slice.Slice; import io.airlift.slice.Slices; +import org.apache.parquet.internal.filter2.columnindex.RowRanges; import java.io.IOException; import java.util.ArrayList; @@ -72,7 +73,7 @@ public boolean isInitialized() } @Override - public void init(PageReader pageReader, Field field) + public void init(PageReader pageReader, Field field, RowRanges rowRanges) { checkArgument(!isInitialized(), "Parquet batch reader already initialized"); this.pageReader = requireNonNull(pageReader, "pageReader is null"); diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/Int32FlatBatchReader.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/Int32FlatBatchReader.java index 084380b0d0a26..e4107cebcd741 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/Int32FlatBatchReader.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/batchreader/Int32FlatBatchReader.java @@ -29,6 +29,7 @@ import com.facebook.presto.parquet.reader.ColumnChunk; import com.facebook.presto.parquet.reader.PageReader; import com.facebook.presto.spi.PrestoException; +import org.apache.parquet.internal.filter2.columnindex.RowRanges; import org.apache.parquet.io.ParquetDecodingException; import java.io.IOException; @@ -67,7 +68,7 @@ public boolean isInitialized() } @Override - public void init(PageReader pageReader, Field field) + public void init(PageReader pageReader, Field field, RowRanges rowRanges) { checkArgument(!isInitialized(), "Parquet batch reader already initialized"); this.pageReader = requireNonNull(pageReader, "pageReader is null"); diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/cache/MetadataReader.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/cache/MetadataReader.java index f32b094538b1b..a4742918f9a7a 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/cache/MetadataReader.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/cache/MetadataReader.java @@ -32,6 +32,7 @@ import org.apache.parquet.hadoop.metadata.ColumnPath; import org.apache.parquet.hadoop.metadata.CompressionCodecName; import org.apache.parquet.hadoop.metadata.ParquetMetadata; +import org.apache.parquet.internal.hadoop.metadata.IndexReference; import org.apache.parquet.schema.MessageType; import org.apache.parquet.schema.OriginalType; import org.apache.parquet.schema.PrimitiveType; @@ -144,6 +145,8 @@ public static ParquetFileMetadata readFooter(ParquetDataSource parquetDataSource metaData.num_values, metaData.total_compressed_size, metaData.total_uncompressed_size); + column.setColumnIndexReference(toColumnIndexReference(columnChunk)); + column.setOffsetIndexReference(toOffsetIndexReference(columnChunk)); blockMetaData.addColumn(column); } blockMetaData.setPath(filePath); @@ -308,4 +311,20 @@ public ParquetFileMetadata getParquetMetadata(ParquetDataSource parquetDataSourc { return readFooter(parquetDataSource, fileSize); } + + private static IndexReference toColumnIndexReference(ColumnChunk columnChunk) + { + if (columnChunk.isSetColumn_index_offset() && columnChunk.isSetColumn_index_length()) { + return new IndexReference(columnChunk.getColumn_index_offset(), columnChunk.getColumn_index_length()); + } + return null; + } + + private static IndexReference toOffsetIndexReference(ColumnChunk columnChunk) + { + if (columnChunk.isSetOffset_index_offset() && columnChunk.isSetOffset_index_length()) { + return new IndexReference(columnChunk.getOffset_index_offset(), columnChunk.getOffset_index_length()); + } + return null; + } } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/Predicate.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/Predicate.java index 0cf048381a71d..0fd9b0b08e8bd 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/Predicate.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/Predicate.java @@ -17,8 +17,10 @@ import com.facebook.presto.parquet.ParquetDataSourceId; import org.apache.parquet.column.ColumnDescriptor; import org.apache.parquet.column.statistics.Statistics; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; import java.util.Map; +import java.util.Optional; public interface Predicate { @@ -36,6 +38,12 @@ public boolean matches(DictionaryDescriptor dictionary) { return true; } + + @Override + public boolean matches(long numberOfRows, Optional columnIndexStore) + { + return true; + } }; /** @@ -57,4 +65,13 @@ boolean matches(long numberOfRows, Map> statisti * @param dictionary The single column dictionary */ boolean matches(DictionaryDescriptor dictionary); + + /** + * Should the Parquet Reader process a file section with the specified statistics. + * + * @param numberOfRows the number of rows in the segment; this can be used with + * Statistics to determine if a column is only null + * @param columnIndexStore column index (statistics) store + */ + boolean matches(long numberOfRows, Optional columnIndexStore); } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/PredicateUtils.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/PredicateUtils.java index 364ab2ff9c164..05e019b2894f0 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/PredicateUtils.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/PredicateUtils.java @@ -37,6 +37,7 @@ import org.apache.parquet.hadoop.metadata.BlockMetaData; import org.apache.parquet.hadoop.metadata.ColumnChunkMetaData; import org.apache.parquet.hadoop.metadata.CompressionCodecName; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; import org.apache.parquet.schema.MessageType; import java.io.ByteArrayInputStream; @@ -84,7 +85,7 @@ public static Predicate buildPredicate(MessageType requestedSchema, TupleDomain< return new TupleDomainParquetPredicate(parquetTupleDomain, columnReferences.build()); } - public static boolean predicateMatches(Predicate parquetPredicate, BlockMetaData block, ParquetDataSource dataSource, Map, RichColumnDescriptor> descriptorsByPath, TupleDomain parquetTupleDomain) + public static boolean predicateMatches(Predicate parquetPredicate, BlockMetaData block, ParquetDataSource dataSource, Map, RichColumnDescriptor> descriptorsByPath, TupleDomain parquetTupleDomain, Optional columnIndexStore, boolean readColumnIndex) throws ParquetCorruptionException { Map> columnStatistics = getStatistics(block, descriptorsByPath); @@ -92,6 +93,11 @@ public static boolean predicateMatches(Predicate parquetPredicate, BlockMetaData return false; } + // Page stats is finer grained but relatively more expensive, so we do the filtering after above block filtering. + if (columnIndexStore.isPresent() && readColumnIndex && !parquetPredicate.matches(block.getRowCount(), columnIndexStore)) { + return false; + } + return dictionaryPredicatesMatch(parquetPredicate, block, dataSource, descriptorsByPath, parquetTupleDomain); } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/TupleDomainParquetPredicate.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/TupleDomainParquetPredicate.java index 531e5284e36bf..7cca6fd6df29c 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/TupleDomainParquetPredicate.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/predicate/TupleDomainParquetPredicate.java @@ -30,10 +30,20 @@ import io.airlift.slice.Slices; import org.apache.parquet.column.ColumnDescriptor; import org.apache.parquet.column.statistics.Statistics; +import org.apache.parquet.filter2.predicate.FilterApi; +import org.apache.parquet.filter2.predicate.FilterPredicate; +import org.apache.parquet.filter2.predicate.UserDefinedPredicate; +import org.apache.parquet.hadoop.metadata.ColumnPath; +import org.apache.parquet.internal.column.columnindex.ColumnIndex; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; import org.apache.parquet.io.api.Binary; import org.apache.parquet.schema.PrimitiveType; +import org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName; +import java.io.Serializable; +import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -52,18 +62,25 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.lang.Float.floatToRawIntBits; import static java.lang.String.format; +import static java.nio.ByteOrder.LITTLE_ENDIAN; import static java.util.Objects.requireNonNull; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.BINARY; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.FLOAT; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT32; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT64; public class TupleDomainParquetPredicate implements Predicate { private final TupleDomain effectivePredicate; private final List columns; + private final ColumnIndexValueConverter converter; public TupleDomainParquetPredicate(TupleDomain effectivePredicate, List columns) { this.effectivePredicate = requireNonNull(effectivePredicate, "effectivePredicate is null"); this.columns = ImmutableList.copyOf(requireNonNull(columns, "columns is null")); + this.converter = new ColumnIndexValueConverter(columns); } @Override @@ -122,6 +139,42 @@ public boolean matches(DictionaryDescriptor dictionary) return effectivePredicateDomain == null || effectivePredicateMatches(effectivePredicateDomain, dictionary); } + @Override + public boolean matches(long numberOfRows, Optional columnIndexStore) + { + if (numberOfRows == 0 || !columnIndexStore.isPresent()) { + return false; + } + + if (effectivePredicate.isNone()) { + return false; + } + Map effectivePredicateDomains = effectivePredicate.getDomains() + .orElseThrow(() -> new IllegalStateException("Effective predicate other than none should have domains")); + + for (RichColumnDescriptor column : columns) { + Domain effectivePredicateDomain = effectivePredicateDomains.get(column); + if (effectivePredicateDomain == null) { + continue; + } + + if (columnIndexStore.isPresent()) { + ColumnIndex columnIndex = columnIndexStore.get().getColumnIndex(ColumnPath.get(column.getPath())); + if (columnIndex == null || columnIndex.getMinValues().size() == 0 || columnIndex.getMaxValues().size() == 0 || columnIndex.getMinValues().size() != columnIndex.getMaxValues().size()) { + continue; + } + else { + Domain domain = getDomain(effectivePredicateDomain.getType(), numberOfRows, columnIndex, column); + if (effectivePredicateDomain.intersect(domain).isNone()) { + return false; + } + } + } + } + + return true; + } + private static boolean effectivePredicateMatches(Domain effectivePredicateDomain, DictionaryDescriptor dictionary) { return !effectivePredicateDomain.intersect(getDomain(effectivePredicateDomain.getType(), dictionary)).isNone(); @@ -295,6 +348,57 @@ public static Domain getDomain(Type type, DictionaryDescriptor dictionaryDescrip return getDomain(columnDescriptor, type, values, values, true); } + @VisibleForTesting + public Domain getDomain(Type type, long rowCount, ColumnIndex columnIndex, RichColumnDescriptor descriptor) + { + if (columnIndex == null) { + return Domain.all(type); + } + + String columnName = descriptor.getPrimitiveType().getName(); + if (isCorruptedColumnIndex(columnIndex)) { + return Domain.all(type); + } + + if (isEmptyColumnIndex(columnIndex)) { + return Domain.all(type); + } + + long totalNullCount = columnIndex.getNullCounts().stream().reduce(0L, (a, b) -> a + b); + if (totalNullCount == rowCount) { + return Domain.onlyNull(type); + } + + boolean hasNullValue = totalNullCount > 0; + + if (descriptor.getType().equals(PrimitiveTypeName.BOOLEAN)) { + // After row-group filtering for boolean, page filtering shouldn't do more + return Domain.all(type); + } + + if (descriptor.getType().equals(INT32) || descriptor.getType().equals(INT64) || descriptor.getType().equals(FLOAT)) { + List mins = converter.getMinValuesAsLong(type, columnIndex, columnName); + List maxs = converter.getMaxValuesAsLong(type, columnIndex, columnName); + return createDomain(type, columnIndex, hasNullValue, mins, maxs); + } + + if (descriptor.getType().equals(PrimitiveTypeName.DOUBLE)) { + List mins = converter.getMinValuesAsDouble(type, columnIndex, columnName); + List maxs = converter.getMaxValuesAsDouble(type, columnIndex, columnName); + return createDomain(type, columnIndex, hasNullValue, mins, maxs); + } + + if (descriptor.getType().equals(BINARY)) { + List mins = converter.getMinValuesAsSlice(type, columnIndex); + List maxs = converter.getMaxValuesAsSlice(type, columnIndex); + return createDomain(type, columnIndex, hasNullValue, mins, maxs); + } + + //TODO: Add INT96 and FIXED_LEN_BYTE_ARRAY later + + return Domain.create(ValueSet.all(type), hasNullValue); + } + public static long asLong(Object value) { if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) { @@ -333,4 +437,253 @@ private Function getConverter(PrimitiveType primitiveType) } } } + + private static > Domain createDomain(Type type, ColumnIndex columnIndex, boolean hasNullValue, List mins, List maxs) + { + if (mins.size() == 0 || maxs.size() == 0 || mins.size() != maxs.size()) { + return Domain.create(ValueSet.all(type), hasNullValue); + } + int pageCount = columnIndex.getMinValues().size(); + List ranges = new ArrayList<>(); + for (int i = 0; i < pageCount; i++) { + T min = mins.get(i); + T max = maxs.get(i); + if (min.compareTo(max) > 0) { + return Domain.create(ValueSet.all(type), hasNullValue); + } + + if (min instanceof Long) { + if (isStatisticsOverflow(type, asLong(min), asLong(max))) { + return Domain.create(ValueSet.all(type), hasNullValue); + } + ranges.add(Range.range(type, min, true, max, true)); + } + else if (min instanceof Double) { + if (((Double) min).isNaN() || ((Double) max).isNaN()) { + return Domain.create(ValueSet.all(type), hasNullValue); + } + ranges.add(Range.range(type, min, true, max, true)); + } + else if (min instanceof Slice) { + ranges.add(Range.range(type, min, true, max, true)); + } + } + checkArgument(!ranges.isEmpty(), "cannot use empty ranges"); + return Domain.create(ValueSet.ofRanges(ranges), hasNullValue); + } + + private boolean isCorruptedColumnIndex(ColumnIndex columnIndex) + { + if (columnIndex.getMaxValues() == null || columnIndex.getMinValues() == null || + columnIndex.getNullCounts() == null || columnIndex.getNullPages() == null) { + return true; + } + + if (columnIndex.getMaxValues().size() != columnIndex.getMinValues().size() || + columnIndex.getMaxValues().size() != columnIndex.getNullPages().size() || + columnIndex.getMaxValues().size() != columnIndex.getNullCounts().size()) { + return true; + } + + return false; + } + + // Caller should verify isCorruptedColumnIndex is false first + private boolean isEmptyColumnIndex(ColumnIndex columnIndex) + { + return columnIndex.getMaxValues().size() == 0; + } + + public FilterPredicate getParquetUserDefinedPredicate() + { + FilterPredicate filter = null; + + // It could be a Presto bug that we don't see effectivePredicate.getDomains().get() has more than 1 domain. + // For example, the 'where c1=3 or c1=10002' clause should have two domains but it has none + // we assume the relation cross domains are 'or' + for (RichColumnDescriptor column : columns) { + Domain domain = effectivePredicate.getDomains().get().get(column); + if (domain == null || domain.isNone()) { + continue; + } + + if (domain.isAll()) { + continue; + } + + FilterPredicate columnFilter = FilterApi.userDefined(FilterApi.intColumn(ColumnPath.get(column.getPath()).toDotString()), new ParquetUserDefinedPredicateTupleDomain(domain)); + if (filter == null) { + filter = columnFilter; + } + else { + filter = FilterApi.or(filter, columnFilter); + } + } + + return filter; + } + + /** + * This class implements methods defined in UserDefinedPredicate based on the page statistic and tuple domain(for a column). + */ + static class ParquetUserDefinedPredicateTupleDomain> + extends UserDefinedPredicate + implements Serializable + { + private Domain columnDomain; + + ParquetUserDefinedPredicateTupleDomain(Domain domain) + { + this.columnDomain = domain; + } + + @Override + public boolean keep(T value) + { + if (value == null && !columnDomain.isNullAllowed()) { + return false; + } + + return true; + } + + @Override + public boolean canDrop(org.apache.parquet.filter2.predicate.Statistics statistic) + { + if (statistic == null) { + return false; + } + List ranges = new ArrayList<>(); + ranges.add(Range.range(columnDomain.getType(), statistic.getMin(), true, statistic.getMax(), true)); + return canDropWithRangeStatistics(ranges); + } + + @Override + public boolean inverseCanDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + // !canDrop() cannot be used because it might not be correct. To be safe, we just keep the record by returning false. + // Since we don't use LogicalNotUserDefined, this method is not called. + return false; + } + + private boolean canDropWithRangeStatistics(List ranges) + { + checkArgument(!ranges.isEmpty(), "cannot use empty ranges"); + Domain domain = Domain.create(ValueSet.ofRanges(ranges), true); + return columnDomain.intersect(domain).isNone(); + } + } + + class ColumnIndexValueConverter + { + private final Map> conversions; + + private ColumnIndexValueConverter(List columns) + { + this.conversions = new HashMap<>(); + for (RichColumnDescriptor column : columns) { + conversions.put(column.getPrimitiveType().getName(), getColumnIndexConversions(column.getPrimitiveType())); + } + } + + public List getMinValuesAsLong(Type type, ColumnIndex columnIndex, String column) + { + return getValuesAsLong(type, column, columnIndex.getMinValues().size(), columnIndex.getMinValues()); + } + + public List getMaxValuesAsLong(Type type, ColumnIndex columnIndex, String column) + { + return getValuesAsLong(type, column, columnIndex.getMaxValues().size(), columnIndex.getMaxValues()); + } + + public List getMinValuesAsDouble(Type type, ColumnIndex columnIndex, String column) + { + return getValuesAsDouble(type, column, columnIndex.getMinValues().size(), columnIndex.getMinValues()); + } + + public List getMaxValuesAsDouble(Type type, ColumnIndex columnIndex, String column) + { + return getValuesAsDouble(type, column, columnIndex.getMaxValues().size(), columnIndex.getMaxValues()); + } + + public List getMinValuesAsSlice(Type type, ColumnIndex columnIndex) + { + return getValuesAsSlice(type, columnIndex.getMinValues().size(), columnIndex.getMinValues()); + } + + public List getMaxValuesAsSlice(Type type, ColumnIndex columnIndex) + { + return getValuesAsSlice(type, columnIndex.getMaxValues().size(), columnIndex.getMaxValues()); + } + + private List getValuesAsLong(Type type, String column, int pageCount, List values) + { + List result = new ArrayList<>(); + if (TINYINT.equals(type) || SMALLINT.equals(type) || INTEGER.equals(type)) { + for (int i = 0; i < pageCount; i++) { + result.add((long) converter.convert(values.get(i), column)); + } + } + else if (BIGINT.equals(type)) { + for (int i = 0; i < pageCount; i++) { + result.add((long) converter.convert(values.get(i), column)); + } + } + else if (REAL.equals(type)) { + for (int i = 0; i < pageCount; i++) { + result.add((long) floatToRawIntBits(converter.convert(values.get(i), column))); + } + } + return result; + } + + private List getValuesAsDouble(Type type, String column, int pageCount, List values) + { + List result = new ArrayList<>(); + if (DOUBLE.equals(type)) { + for (int i = 0; i < pageCount; i++) { + result.add(converter.convert(values.get(i), column)); + } + } + return result; + } + + private List getValuesAsSlice(Type type, int pageCount, List values) + { + List result = new ArrayList<>(); + if (isVarcharType(type)) { + for (int i = 0; i < pageCount; i++) { + result.add(Slices.wrappedBuffer(values.get(i))); + } + } + return result; + } + + private T convert(ByteBuffer buffer, String name) + { + return (T) conversions.get(name).apply(buffer); + } + + private Function getColumnIndexConversions(PrimitiveType type) + { + switch (type.getPrimitiveTypeName()) { + case BOOLEAN: + return buffer -> ((ByteBuffer) buffer).get(0) != 0; + case INT32: + return buffer -> ((ByteBuffer) buffer).order(LITTLE_ENDIAN).getInt(0); + case INT64: + return buffer -> ((ByteBuffer) buffer).order(LITTLE_ENDIAN).getLong(0); + case FLOAT: + return buffer -> ((ByteBuffer) buffer).order(LITTLE_ENDIAN).getFloat(0); + case DOUBLE: + return buffer -> ((ByteBuffer) buffer).order(LITTLE_ENDIAN).getDouble(0); + case BINARY: + case FIXED_LEN_BYTE_ARRAY: + case INT96: + return binary -> ByteBuffer.wrap(((Binary) binary).getBytes()); + default: + throw new IllegalArgumentException("Unsupported Parquet type: " + type.getPrimitiveTypeName()); + } + } + } } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/AbstractColumnReader.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/AbstractColumnReader.java index 9cd2515be3881..305029d9d1e98 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/AbstractColumnReader.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/AbstractColumnReader.java @@ -33,9 +33,11 @@ import org.apache.parquet.bytes.BytesUtils; import org.apache.parquet.column.values.ValuesReader; import org.apache.parquet.column.values.rle.RunLengthBitPackingHybridDecoder; +import org.apache.parquet.internal.filter2.columnindex.RowRanges; import org.apache.parquet.io.ParquetDecodingException; import java.io.IOException; +import java.util.PrimitiveIterator; import java.util.function.Consumer; import static com.facebook.presto.parquet.ValuesType.DEFINITION_LEVEL; @@ -66,6 +68,9 @@ public abstract class AbstractColumnReader private DataPage page; private int remainingValueCountInPage; private int readOffset; + private PrimitiveIterator.OfLong indexIterator; + private long currentRow; + private long targetRow; protected abstract void readValue(BlockBuilder blockBuilder, Type type); @@ -80,6 +85,8 @@ public AbstractColumnReader(RichColumnDescriptor columnDescriptor) { this.columnDescriptor = requireNonNull(columnDescriptor, "columnDescriptor"); pageReader = null; + this.targetRow = Long.MIN_VALUE; + this.indexIterator = null; } @Override @@ -89,7 +96,7 @@ public boolean isInitialized() } @Override - public void init(PageReader pageReader, Field field) + public void init(PageReader pageReader, Field field, RowRanges rowRanges) { this.pageReader = requireNonNull(pageReader, "pageReader is null"); this.field = requireNonNull(field, "field is null"); @@ -108,6 +115,7 @@ public void init(PageReader pageReader, Field field) } checkArgument(pageReader.getTotalValueCount() > 0, "page is empty"); totalValueCount = pageReader.getTotalValueCount(); + indexIterator = (rowRanges == null) ? null : rowRanges.iterator(); } @Override @@ -130,10 +138,13 @@ public ColumnChunk readNext() readNextPage(); } int valuesToRead = Math.min(remainingValueCountInPage, nextBatchSize - valueCount); + if (valuesToRead == 0) { + // When we break here, we could end up with valueCount < nextBatchSize, this is because we may skip reading values in readValues() + break; + } readValues(blockBuilder, valuesToRead, field.getType(), definitionLevels, repetitionLevels); valueCount += valuesToRead; } - checkArgument(valueCount == nextBatchSize, "valueCount %s not equals to batchSize %s", valueCount, nextBatchSize); readOffset = 0; nextBatchSize = 0; @@ -146,38 +157,81 @@ private void readValues(BlockBuilder blockBuilder, int valuesToRead, Type type, readValue(blockBuilder, type); definitionLevels.add(definitionLevel); repetitionLevels.add(repetitionLevel); - }); + }, indexIterator != null); } private void skipValues(int valuesToRead) { - processValues(valuesToRead, ignored -> skipValue()); + processValues(valuesToRead, ignored -> skipValue(), false); } - private void processValues(int valuesToRead, Consumer valueConsumer) + /** + * When filtering using column indexes we might skip reading some pages for different columns. Because the rows are + * not aligned between the pages of the different columns it might be required to skip some values. The values (and the + * related rl and dl) are skipped based on the iterator of the required row indexes and the first row index of each + * page. + * For example: + * + * rows col1 col2 col3 + * ┌──────┬──────┬──────┐ + * 0 │ p0 │ │ │ + * ╞══════╡ p0 │ p0 │ + * 20 │ p1(X)│------│------│ + * ╞══════╪══════╡ │ + * 40 │ p2(X)│ │------│ + * ╞══════╡ p1(X)╞══════╡ + * 60 │ p3(X)│ │------│ + * ╞══════╪══════╡ │ + * 80 │ p4 │ │ p1 │ + * ╞══════╡ p2 │ │ + * 100 │ p5 │ │ │ + * └──────┴──────┴──────┘ + * + * The pages 1, 2, 3 in col1 are skipped so we have to skip the rows [20, 79]. Because page 1 in col2 contains values + * only for the rows [40, 79] we skip this entire page as well. To synchronize the row reading we have to skip the + * values (and the related rl and dl) for the rows [20, 39] in the end of the page 0 for col2. Similarly, we have to + * skip values while reading page0 and page1 for col3. + */ + private void processValues(int valuesToRead, Consumer valueConsumer, boolean indexEnabled) { if (definitionLevel == EMPTY_LEVEL_VALUE && repetitionLevel == EMPTY_LEVEL_VALUE) { definitionLevel = definitionReader.readLevel(); repetitionLevel = repetitionReader.readLevel(); } int valueCount = 0; - for (int i = 0; i < valuesToRead; i++) { + int skipCount = 0; + for (int i = 0; i < valuesToRead; ) { + boolean consumed = false; do { - valueConsumer.accept(null); - valueCount++; - if (valueCount == remainingValueCountInPage) { - updateValueCounts(valueCount); + if (skipRL(repetitionLevel, indexEnabled)) { + skipValue(); + skipCount++; + } + else { + valueConsumer.accept(null); + valueCount++; + consumed = true; + } + + if (valueCount + skipCount == remainingValueCountInPage) { + updateValueCounts(valueCount, skipCount); if (!readNextPage()) { return; } valueCount = 0; + skipCount = 0; } + repetitionLevel = repetitionReader.readLevel(); definitionLevel = definitionReader.readLevel(); } while (repetitionLevel != 0); + + if (consumed) { + i++; + } } - updateValueCounts(valueCount); + updateValueCounts(valueCount, skipCount); } private void seek() @@ -216,13 +270,14 @@ private boolean readNextPage() return true; } - private void updateValueCounts(int valuesRead) + private void updateValueCounts(int valuesRead, int skipCount) { - if (valuesRead == remainingValueCountInPage) { + int totalCount = valuesRead + skipCount; + if (totalCount == remainingValueCountInPage) { page = null; valuesReader = null; } - remainingValueCountInPage -= valuesRead; + remainingValueCountInPage -= totalCount; currentValueCount += valuesRead; } @@ -236,7 +291,8 @@ private ValuesReader readPageV1(DataPageV1 page) ByteBufferInputStream bufferInputStream = ByteBufferInputStream.wrap(page.getSlice().toByteBuffer()); repetitionLevelReader.initFromPage(page.getValueCount(), bufferInputStream); definitionLevelReader.initFromPage(page.getValueCount(), bufferInputStream); - return initDataReader(page.getValueEncoding(), bufferInputStream, page.getValueCount()); + long firstRowIndex = page.getFirstRowIndex().orElse(-1L); + return initDataReader(page.getValueEncoding(), bufferInputStream, page.getValueCount(), firstRowIndex); } catch (IOException e) { throw new ParquetDecodingException("Error reading parquet page " + page + " in column " + columnDescriptor, e); @@ -247,7 +303,8 @@ private ValuesReader readPageV2(DataPageV2 page) { repetitionReader = buildLevelRLEReader(columnDescriptor.getMaxRepetitionLevel(), page.getRepetitionLevels()); definitionReader = buildLevelRLEReader(columnDescriptor.getMaxDefinitionLevel(), page.getDefinitionLevels()); - return initDataReader(page.getDataEncoding(), ByteBufferInputStream.wrap(ImmutableList.of(page.getSlice().toByteBuffer())), page.getValueCount()); + long firstRowIndex = page.getFirstRowIndex().orElse(-1L); + return initDataReader(page.getDataEncoding(), ByteBufferInputStream.wrap(ImmutableList.of(page.getSlice().toByteBuffer())), page.getValueCount(), firstRowIndex); } private LevelReader buildLevelRLEReader(int maxLevel, Slice slice) @@ -259,7 +316,7 @@ private LevelReader buildLevelRLEReader(int maxLevel, Slice slice) return new LevelRLEReader(new RunLengthBitPackingHybridDecoder(BytesUtils.getWidthFromMaxInt(maxLevel), slice.getInput())); } - private ValuesReader initDataReader(ParquetEncoding dataEncoding, ByteBufferInputStream inputStream, int valueCount) + private ValuesReader initDataReader(ParquetEncoding dataEncoding, ByteBufferInputStream inputStream, int valueCount, long firstRowIndex) { ValuesReader valuesReader; if (dataEncoding.usesDictionary()) { @@ -274,10 +331,32 @@ private ValuesReader initDataReader(ParquetEncoding dataEncoding, ByteBufferInpu try { valuesReader.initFromPage(valueCount, inputStream); + if (firstRowIndex != -1) { + currentRow = firstRowIndex - 1; + } + else { + currentRow = -1; + } return valuesReader; } catch (IOException e) { throw new ParquetDecodingException("Error reading parquet page in column " + columnDescriptor, e); } } + + private boolean skipRL(int repetitionLevel, boolean indexEnabled) + { + if (!indexEnabled || indexIterator == null) { + return false; + } + + if (repetitionLevel == 0) { + currentRow = currentRow + 1; + if (currentRow > targetRow) { + targetRow = indexIterator.hasNext() ? indexIterator.nextLong() : Long.MAX_VALUE; + } + } + + return currentRow < targetRow; + } } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ColumnIndexFilterUtils.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ColumnIndexFilterUtils.java new file mode 100644 index 0000000000000..431baa2a584a7 --- /dev/null +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ColumnIndexFilterUtils.java @@ -0,0 +1,208 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.parquet.reader; + +import com.facebook.presto.parquet.ParquetDataSource; +import com.facebook.presto.parquet.RichColumnDescriptor; +import com.facebook.presto.parquet.predicate.Predicate; +import com.facebook.presto.parquet.predicate.TupleDomainParquetPredicate; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import org.apache.parquet.hadoop.metadata.BlockMetaData; +import org.apache.parquet.hadoop.metadata.ColumnChunkMetaData; +import org.apache.parquet.hadoop.metadata.ColumnPath; +import org.apache.parquet.internal.column.columnindex.OffsetIndex; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; +import org.apache.parquet.internal.filter2.columnindex.RowRanges; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Formatter; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +public class ColumnIndexFilterUtils +{ + private ColumnIndexFilterUtils() {} + + static class OffsetRange + { + private final long offset; + private long length; + + public OffsetRange(long offset, int length) + { + this.offset = offset; + this.length = length; + } + + long getOffset() + { + return offset; + } + + long getLength() + { + return length; + } + + private boolean extendWithCheck(long offset, int length) + { + if (this.offset + this.length == offset) { + this.length += length; + return true; + } + else { + return false; + } + } + + public void extendLength(long length) + { + this.length += length; + } + + public long endPos() + { + return offset + length; + } + } + + private static class FilteredOffsetIndex + implements OffsetIndex + { + private final OffsetIndex offsetIndex; + private final int[] indices; + + private FilteredOffsetIndex(OffsetIndex offsetIndex, int[] indices) + { + this.offsetIndex = offsetIndex; + this.indices = indices; + } + + @Override + public int getPageCount() + { + return indices.length; + } + + @Override + public long getOffset(int pageIndex) + { + return offsetIndex.getOffset(indices[pageIndex]); + } + + @Override + public int getCompressedPageSize(int pageIndex) + { + return offsetIndex.getCompressedPageSize(indices[pageIndex]); + } + + @Override + public long getFirstRowIndex(int pageIndex) + { + return offsetIndex.getFirstRowIndex(indices[pageIndex]); + } + + @Override + public long getLastRowIndex(int pageIndex, long totalRowCount) + { + int nextIndex = indices[pageIndex] + 1; + return (nextIndex >= offsetIndex.getPageCount() ? totalRowCount : offsetIndex.getFirstRowIndex(nextIndex)) - 1; + } + + @Override + public String toString() + { + try (Formatter formatter = new Formatter()) { + formatter.format("%-12s %20s %16s %20s\n", "", "offset", "compressed size", "first row index"); + for (int i = 0, n = offsetIndex.getPageCount(); i < n; ++i) { + int index = Arrays.binarySearch(indices, i); + boolean isHidden = index < 0; + formatter.format("%spage-%-5d %20d %16d %20d\n", + isHidden ? "- " : " ", + isHidden ? i : index, + offsetIndex.getOffset(i), + offsetIndex.getCompressedPageSize(i), + offsetIndex.getFirstRowIndex(i)); + } + return formatter.toString(); + } + } + } + + /* + * Returns the filtered offset index containing only the pages which are overlapping with rowRanges. + */ + static OffsetIndex filterOffsetIndex(OffsetIndex offsetIndex, RowRanges rowRanges, long totalRowCount) + { + IntList indices = new IntArrayList(); + for (int i = 0; i < offsetIndex.getPageCount(); i++) { + long from = offsetIndex.getFirstRowIndex(i); + if (rowRanges.isOverlapping(from, offsetIndex.getLastRowIndex(i, totalRowCount))) { + indices.add(i); + } + } + return new FilteredOffsetIndex(offsetIndex, indices.toIntArray()); + } + + static List calculateOffsetRanges(OffsetIndex offsetIndex, ColumnChunkMetaData columnChunkMetadata, long firstPageOffset, long startingPosition) + { + List ranges = new ArrayList<>(); + int pageCount = offsetIndex.getPageCount(); + if (pageCount > 0) { + OffsetRange currentRange = null; + + // Add a range for the dictionary page if required + long rowGroupOffset = columnChunkMetadata.getStartingPos(); + if (rowGroupOffset < firstPageOffset) { + // We need to adjust the offset by startingPosition for presto because dataSource.readFully() started at startingPosition + currentRange = new OffsetRange(rowGroupOffset - startingPosition, (int) (firstPageOffset - rowGroupOffset)); + ranges.add(currentRange); + } + + for (int i = 0; i < pageCount; i++) { + long offset = offsetIndex.getOffset(i); + int length = offsetIndex.getCompressedPageSize(i); + // We need to adjust the offset by startingPosition for presto because dataSource.readFully() started at startingPosition + if (currentRange == null || !currentRange.extendWithCheck(offset - startingPosition, length)) { + currentRange = new OffsetRange(offset - startingPosition, length); + ranges.add(currentRange); + } + } + } + return ranges; + } + + public static Optional getColumnIndexStore(Predicate parquetPredicate, ParquetDataSource dataSource, BlockMetaData blockMetadata, Map, RichColumnDescriptor> descriptorsByPath, boolean columnIndexFilterEnabled) + { + if (!columnIndexFilterEnabled || parquetPredicate == null || !(parquetPredicate instanceof TupleDomainParquetPredicate)) { + return Optional.empty(); + } + + for (ColumnChunkMetaData column : blockMetadata.getColumns()) { + if (column.getColumnIndexReference() != null && column.getOffsetIndexReference() != null) { + Set paths = new HashSet<>(); + for (List path : descriptorsByPath.keySet()) { + paths.add(ColumnPath.get(path.toArray(new String[0]))); + } + return Optional.of(ParquetColumnIndexStore.create(dataSource, blockMetadata, paths)); + } + } + return Optional.empty(); + } +} diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/PageReader.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/PageReader.java index 82e76aa4af135..c0a0b2e51ede2 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/PageReader.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/PageReader.java @@ -17,7 +17,9 @@ import com.facebook.presto.parquet.DataPageV1; import com.facebook.presto.parquet.DataPageV2; import com.facebook.presto.parquet.DictionaryPage; +import io.airlift.slice.Slice; import org.apache.parquet.hadoop.metadata.CompressionCodecName; +import org.apache.parquet.internal.column.columnindex.OffsetIndex; import java.io.IOException; import java.util.LinkedList; @@ -31,6 +33,8 @@ public class PageReader private final long valueCount; private final LinkedList compressedPages; private final DictionaryPage compressedDictionaryPage; + private final OffsetIndex offsetIndex; + private int pageIndex; /** * @param compressedPages This parameter will be mutated destructively as {@link DataPage} entries are removed as part of {@link #readPage()}. The caller @@ -38,14 +42,27 @@ public class PageReader */ public PageReader(CompressionCodecName codec, LinkedList compressedPages, - DictionaryPage compressedDictionaryPage, - long valueCount) + DictionaryPage compressedDictionaryPage) throws IOException + { + this(codec, compressedPages, compressedDictionaryPage, null); + } + + public PageReader(CompressionCodecName codec, + LinkedList compressedPages, + DictionaryPage compressedDictionaryPage, + OffsetIndex offsetIndex) { this.codec = codec; this.compressedPages = compressedPages; this.compressedDictionaryPage = compressedDictionaryPage; - this.valueCount = valueCount; + int count = 0; + for (DataPage page : compressedPages) { + count += page.getValueCount(); + } + this.valueCount = count; + this.offsetIndex = offsetIndex; + this.pageIndex = 0; } public long getTotalValueCount() @@ -60,12 +77,16 @@ public DataPage readPage() } DataPage compressedPage = compressedPages.removeFirst(); try { + long firstRowIndex = getFirstRowIndex(pageIndex, offsetIndex); + pageIndex = pageIndex + 1; if (compressedPage instanceof DataPageV1) { DataPageV1 dataPageV1 = (DataPageV1) compressedPage; + Slice slice = decompress(codec, dataPageV1.getSlice(), dataPageV1.getUncompressedSize()); return new DataPageV1( - decompress(codec, dataPageV1.getSlice(), dataPageV1.getUncompressedSize()), + slice, dataPageV1.getValueCount(), dataPageV1.getUncompressedSize(), + firstRowIndex, dataPageV1.getStatistics(), dataPageV1.getRepetitionLevelEncoding(), dataPageV1.getDefinitionLevelEncoding(), @@ -79,14 +100,16 @@ public DataPage readPage() int uncompressedSize = toIntExact(dataPageV2.getUncompressedSize() - dataPageV2.getDefinitionLevels().length() - dataPageV2.getRepetitionLevels().length()); + Slice slice = decompress(codec, dataPageV2.getSlice(), uncompressedSize); return new DataPageV2( dataPageV2.getRowCount(), dataPageV2.getNullCount(), dataPageV2.getValueCount(), + firstRowIndex, dataPageV2.getRepetitionLevels(), dataPageV2.getDefinitionLevels(), dataPageV2.getDataEncoding(), - decompress(codec, dataPageV2.getSlice(), uncompressedSize), + slice, dataPageV2.getUncompressedSize(), dataPageV2.getStatistics(), false); @@ -112,4 +135,9 @@ public DictionaryPage readDictionaryPage() throw new RuntimeException("Error reading dictionary page", e); } } + + public static long getFirstRowIndex(int pageIndex, OffsetIndex offsetIndex) + { + return offsetIndex == null ? -1 : offsetIndex.getFirstRowIndex(pageIndex); + } } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetColumnChunk.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetColumnChunk.java index 6fe85c97f975d..1ebe589f8148c 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetColumnChunk.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetColumnChunk.java @@ -20,15 +20,17 @@ import com.facebook.presto.parquet.ParquetCorruptionException; import com.facebook.presto.parquet.cache.MetadataReader; import io.airlift.slice.Slice; +import org.apache.parquet.bytes.ByteBufferInputStream; import org.apache.parquet.column.Encoding; import org.apache.parquet.format.DataPageHeader; import org.apache.parquet.format.DataPageHeaderV2; import org.apache.parquet.format.DictionaryPageHeader; import org.apache.parquet.format.PageHeader; import org.apache.parquet.format.Util; +import org.apache.parquet.internal.column.columnindex.OffsetIndex; -import java.io.ByteArrayInputStream; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.List; @@ -36,18 +38,29 @@ import static io.airlift.slice.Slices.wrappedBuffer; public class ParquetColumnChunk - extends ByteArrayInputStream { private final ColumnChunkDescriptor descriptor; + private final ByteBufferInputStream stream; + private final OffsetIndex offsetIndex; public ParquetColumnChunk( ColumnChunkDescriptor descriptor, byte[] data, int offset) { - super(data); + this.stream = ByteBufferInputStream.wrap(ByteBuffer.wrap(data, offset, data.length - offset)); this.descriptor = descriptor; - this.pos = offset; + this.offsetIndex = null; + } + + public ParquetColumnChunk( + ColumnChunkDescriptor descriptor, + List data, + OffsetIndex offsetIndex) + { + this.stream = ByteBufferInputStream.wrap(data); + this.descriptor = descriptor; + this.offsetIndex = offsetIndex; } public ColumnChunkDescriptor getDescriptor() @@ -58,7 +71,7 @@ public ColumnChunkDescriptor getDescriptor() protected PageHeader readPageHeader() throws IOException { - return Util.readPageHeader(this); + return Util.readPageHeader(stream); } public PageReader readAllPages() @@ -67,10 +80,12 @@ public PageReader readAllPages() LinkedList pages = new LinkedList<>(); DictionaryPage dictionaryPage = null; long valueCount = 0; - while (valueCount < descriptor.getColumnChunkMetaData().getValueCount()) { + int dataPageCount = 0; + while (hasMorePages(valueCount, dataPageCount)) { PageHeader pageHeader = readPageHeader(); int uncompressedPageSize = pageHeader.getUncompressed_page_size(); int compressedPageSize = pageHeader.getCompressed_page_size(); + long firstRowIndex = -1; switch (pageHeader.type) { case DICTIONARY_PAGE: if (dictionaryPage != null) { @@ -79,32 +94,36 @@ public PageReader readAllPages() dictionaryPage = readDictionaryPage(pageHeader, uncompressedPageSize, compressedPageSize); break; case DATA_PAGE: - valueCount += readDataPageV1(pageHeader, uncompressedPageSize, compressedPageSize, pages); + firstRowIndex = PageReader.getFirstRowIndex(dataPageCount, offsetIndex); + valueCount += readDataPageV1(pageHeader, uncompressedPageSize, compressedPageSize, firstRowIndex, pages); + dataPageCount = dataPageCount + 1; break; case DATA_PAGE_V2: - valueCount += readDataPageV2(pageHeader, uncompressedPageSize, compressedPageSize, pages); + firstRowIndex = PageReader.getFirstRowIndex(dataPageCount, offsetIndex); + valueCount += readDataPageV2(pageHeader, uncompressedPageSize, compressedPageSize, firstRowIndex, pages); + dataPageCount = dataPageCount + 1; break; default: - skip(compressedPageSize); + stream.skipFully(compressedPageSize); break; } } - return new PageReader(descriptor.getColumnChunkMetaData().getCodec(), pages, dictionaryPage, valueCount); + return new PageReader(descriptor.getColumnChunkMetaData().getCodec(), pages, dictionaryPage, offsetIndex); } - public int getPosition() + private Slice getSlice(int size) throws IOException { - return pos; - } - - private Slice getSlice(int size) - { - Slice slice = wrappedBuffer(buf, pos, size); - pos += size; - return slice; + //Todo: 1) The stream.slice() in both MultiBufferInputStream and SingleBufferInputStream will clone the memory. + // Need to check how much the memory consumption goes up. Since we skip reading pages, that would reduce + // a lot of memory consumption and compensate. + // 2) It adds exception IOException. It is OK because eventually it rewinds to readAllPages() which + // already has IOException + ByteBuffer buffer = stream.slice(size); + return wrappedBuffer(buffer.array(), buffer.position(), size); } private DictionaryPage readDictionaryPage(PageHeader pageHeader, int uncompressedPageSize, int compressedPageSize) + throws IOException { DictionaryPageHeader dicHeader = pageHeader.getDictionary_page_header(); return new DictionaryPage( @@ -117,13 +136,16 @@ private DictionaryPage readDictionaryPage(PageHeader pageHeader, int uncompresse private long readDataPageV1(PageHeader pageHeader, int uncompressedPageSize, int compressedPageSize, + long firstRowIndex, List pages) + throws IOException { DataPageHeader dataHeaderV1 = pageHeader.getData_page_header(); pages.add(new DataPageV1( getSlice(compressedPageSize), dataHeaderV1.getNum_values(), uncompressedPageSize, + firstRowIndex, MetadataReader.readStats( dataHeaderV1.getStatistics(), descriptor.getColumnDescriptor().getType()), @@ -136,7 +158,9 @@ private long readDataPageV1(PageHeader pageHeader, private long readDataPageV2(PageHeader pageHeader, int uncompressedPageSize, int compressedPageSize, + long firstRowIndex, List pages) + throws IOException { DataPageHeaderV2 dataHeaderV2 = pageHeader.getData_page_header_v2(); int dataSize = compressedPageSize - dataHeaderV2.getRepetition_levels_byte_length() - dataHeaderV2.getDefinition_levels_byte_length(); @@ -144,6 +168,7 @@ private long readDataPageV2(PageHeader pageHeader, dataHeaderV2.getNum_rows(), dataHeaderV2.getNum_nulls(), dataHeaderV2.getNum_values(), + firstRowIndex, getSlice(dataHeaderV2.getRepetition_levels_byte_length()), getSlice(dataHeaderV2.getDefinition_levels_byte_length()), getParquetEncoding(Encoding.valueOf(dataHeaderV2.getEncoding().name())), @@ -155,4 +180,10 @@ private long readDataPageV2(PageHeader pageHeader, dataHeaderV2.isIs_compressed())); return dataHeaderV2.getNum_values(); } + + private boolean hasMorePages(long valuesCount, int pagesCount) + { + return offsetIndex == null ? valuesCount < descriptor.getColumnChunkMetaData().getValueCount() + : pagesCount < offsetIndex.getPageCount(); + } } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetColumnIndexStore.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetColumnIndexStore.java new file mode 100644 index 0000000000000..08ced0b03e266 --- /dev/null +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetColumnIndexStore.java @@ -0,0 +1,160 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.parquet.reader; + +import com.facebook.presto.parquet.ParquetDataSource; +import org.apache.parquet.hadoop.metadata.BlockMetaData; +import org.apache.parquet.hadoop.metadata.ColumnChunkMetaData; +import org.apache.parquet.hadoop.metadata.ColumnPath; +import org.apache.parquet.internal.column.columnindex.ColumnIndex; +import org.apache.parquet.internal.column.columnindex.OffsetIndex; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static java.util.Collections.emptySet; + +/** + * Internal implementation of {@link ColumnIndexStore}. + */ +public class ParquetColumnIndexStore + implements ColumnIndexStore +{ + private interface IndexStore + { + Optional getColumnIndex(); + + Optional getOffsetIndex(); + } + + private class PageIndexStore + implements IndexStore + { + private final ColumnChunkMetaData columnChunkMetadata; + private Optional columnIndex; + private boolean columnIndexRead; + private final Optional offsetIndex; + + PageIndexStore(ColumnChunkMetaData meta) + { + this.columnChunkMetadata = meta; + try { + this.offsetIndex = dataSource.readOffsetIndex(meta); + } + catch (IOException e) { + // If the I/O issue still stands it will fail the reading later; + // otherwise we fail the filtering only with a missing offset index. + throw new MissingOffsetIndexException(meta.getPath()); + } + } + + @Override + public Optional getColumnIndex() + { + if (!columnIndexRead) { + try { + columnIndex = dataSource.readColumnIndex(columnChunkMetadata); + } + catch (IOException e) { + // If the I/O issue still stands it will fail the reading later; + // otherwise we fail the filtering only with a missing column index. + } + columnIndexRead = true; + } + return columnIndex; + } + + @Override + public Optional getOffsetIndex() + { + return offsetIndex; + } + } + + private static final ParquetColumnIndexStore.IndexStore MISSING_INDEX_STORE = new IndexStore() + { + @Override + public Optional getColumnIndex() + { + return null; + } + + @Override + public Optional getOffsetIndex() + { + return null; + } + }; + + private static final ParquetColumnIndexStore EMPTY = new ParquetColumnIndexStore(null, new BlockMetaData(), emptySet()) + { + @Override + public ColumnIndex getColumnIndex(ColumnPath column) + { + return null; + } + + @Override + public OffsetIndex getOffsetIndex(ColumnPath column) + { + throw new MissingOffsetIndexException(column); + } + }; + + private final ParquetDataSource dataSource; + private final Map store; + + /* + * Creates a column index store which lazily reads column/offset indexes for the columns in paths. (paths are the set + * of columns used for the projection) + */ + public static ColumnIndexStore create(ParquetDataSource dataSource, BlockMetaData block, Set paths) + { + try { + return new ParquetColumnIndexStore(dataSource, block, paths); + } + catch (MissingOffsetIndexException e) { + return EMPTY; + } + } + + private ParquetColumnIndexStore(ParquetDataSource dataSource, BlockMetaData block, Set paths) + { + this.dataSource = dataSource; + Map store = new HashMap<>(); + for (ColumnChunkMetaData column : block.getColumns()) { + ColumnPath path = column.getPath(); + if (paths.contains(path)) { + store.put(path, new ParquetColumnIndexStore.PageIndexStore(column)); + } + } + this.store = store; + } + + @Override + public ColumnIndex getColumnIndex(ColumnPath column) + { + return store.getOrDefault(column, MISSING_INDEX_STORE).getColumnIndex().orElse(null); + } + + @Override + public OffsetIndex getOffsetIndex(ColumnPath column) + { + return store.getOrDefault(column, MISSING_INDEX_STORE).getOffsetIndex().orElse(null); + } +} diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetReader.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetReader.java index 02722e33f4d7b..53296b9575961 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetReader.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/reader/ParquetReader.java @@ -34,24 +34,39 @@ import com.facebook.presto.parquet.ParquetResultVerifierUtils; import com.facebook.presto.parquet.PrimitiveField; import com.facebook.presto.parquet.RichColumnDescriptor; +import com.facebook.presto.parquet.predicate.Predicate; +import com.facebook.presto.parquet.predicate.TupleDomainParquetPredicate; +import com.facebook.presto.parquet.reader.ColumnIndexFilterUtils.OffsetRange; import io.airlift.units.DataSize; import it.unimi.dsi.fastutil.booleans.BooleanArrayList; import it.unimi.dsi.fastutil.booleans.BooleanList; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import org.apache.parquet.column.ColumnDescriptor; +import org.apache.parquet.filter2.compat.FilterCompat; +import org.apache.parquet.filter2.predicate.FilterPredicate; import org.apache.parquet.hadoop.metadata.BlockMetaData; import org.apache.parquet.hadoop.metadata.ColumnChunkMetaData; import org.apache.parquet.hadoop.metadata.ColumnPath; +import org.apache.parquet.internal.column.columnindex.OffsetIndex; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexFilter; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; +import org.apache.parquet.internal.filter2.columnindex.RowRanges; import org.apache.parquet.io.MessageColumnIO; import org.apache.parquet.io.PrimitiveColumnIO; import org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName; import java.io.Closeable; import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.facebook.presto.common.type.BigintType.BIGINT; import static com.facebook.presto.common.type.IntegerType.INTEGER; @@ -81,11 +96,13 @@ public class ParquetReader private final AggregatedMemoryContext systemMemoryContext; private final boolean batchReadEnabled; private final boolean enableVerification; + private final FilterPredicate filter; private int currentBlock; private BlockMetaData currentBlockMetadata; private long currentPosition; private long currentGroupRowCount; + private RowRanges currentGroupRowRanges; private long nextRowInGroup; private int batchSize; @@ -99,6 +116,12 @@ public class ParquetReader private AggregatedMemoryContext currentRowGroupMemoryContext; + private final List blockIndexStores; + private final List blockRowRanges; + private final Map paths = new HashMap<>(); + + private final boolean columnIndexFilterEnabled; + public ParquetReader(MessageColumnIO messageColumnIO, List blocks, @@ -106,7 +129,10 @@ public ParquetReader(MessageColumnIO AggregatedMemoryContext systemMemoryContext, DataSize maxReadBlockSize, boolean batchReadEnabled, - boolean enableVerification) + boolean enableVerification, + Predicate parquetPredicate, + List blockIndexStores, + boolean columnIndexFilterEnabled) { this.blocks = blocks; this.dataSource = requireNonNull(dataSource, "dataSource is null"); @@ -119,6 +145,20 @@ public ParquetReader(MessageColumnIO this.enableVerification = enableVerification; verificationColumnReaders = enableVerification ? new ColumnReader[columns.size()] : null; maxBytesPerCell = new long[columns.size()]; + this.blockIndexStores = blockIndexStores; + this.blockRowRanges = listWithNulls(this.blocks.size()); + for (PrimitiveColumnIO column : columns) { + ColumnDescriptor columnDescriptor = column.getColumnDescriptor(); + this.paths.put(ColumnPath.get(columnDescriptor.getPath()), columnDescriptor); + } + if (parquetPredicate != null && columnIndexFilterEnabled && parquetPredicate instanceof TupleDomainParquetPredicate) { + this.filter = ((TupleDomainParquetPredicate) parquetPredicate).getParquetUserDefinedPredicate(); + } + else { + this.filter = null; + } + this.currentBlock = -1; + this.columnIndexFilterEnabled = columnIndexFilterEnabled; } @Override @@ -159,6 +199,7 @@ public int nextBatch() private boolean advanceToNextRowGroup() { + currentBlock++; currentRowGroupMemoryContext.close(); currentRowGroupMemoryContext = systemMemoryContext.newAggregatedMemoryContext(); @@ -166,7 +207,17 @@ private boolean advanceToNextRowGroup() return false; } currentBlockMetadata = blocks.get(currentBlock); - currentBlock = currentBlock + 1; + + if (filter != null && columnIndexFilterEnabled) { + ColumnIndexStore columnIndexStore = blockIndexStores.get(currentBlock); + if (columnIndexStore != null) { + currentGroupRowRanges = getRowRanges(currentBlock); + long rowCount = currentGroupRowRanges.rowCount(); + if (rowCount == 0) { + return false; + } + } + } nextRowInGroup = 0L; currentGroupRowCount = currentBlockMetadata.getRowCount(); @@ -243,16 +294,37 @@ private ColumnChunk readPrimitive(PrimitiveField field) ColumnChunkMetaData metadata = getColumnChunkMetaData(columnDescriptor); long startingPosition = metadata.getStartingPos(); int totalSize = toIntExact(metadata.getTotalSize()); - byte[] buffer = allocateBlock(totalSize); - dataSource.readFully(startingPosition, buffer); - ColumnChunkDescriptor descriptor = new ColumnChunkDescriptor(columnDescriptor, metadata, totalSize); - ParquetColumnChunk columnChunk = new ParquetColumnChunk(descriptor, buffer, 0); - columnReader.init(columnChunk.readAllPages(), field); - if (enableVerification) { - ColumnReader verificationColumnReader = verificationColumnReaders[field.getId()]; - ParquetColumnChunk columnChunkVerfication = new ParquetColumnChunk(descriptor, buffer, 0); - verificationColumnReader.init(columnChunkVerfication.readAllPages(), field); + if (shouldUseColumnIndex(metadata.getPath())) { + OffsetIndex offsetIndex = blockIndexStores.get(currentBlock).getOffsetIndex(metadata.getPath()); + OffsetIndex filteredOffsetIndex = ColumnIndexFilterUtils.filterOffsetIndex(offsetIndex, currentGroupRowRanges, blocks.get(currentBlock).getRowCount()); + List offsetRanges = ColumnIndexFilterUtils.calculateOffsetRanges(filteredOffsetIndex, metadata, offsetIndex.getOffset(0), startingPosition); + List consecutiveRanges = concatRanges(offsetRanges); + List buffers = allocateBlocks(consecutiveRanges); + for (int i = 0; i < consecutiveRanges.size(); i++) { + ByteBuffer buffer = buffers.get(i); + dataSource.readFully(startingPosition + consecutiveRanges.get(i).getOffset(), buffer.array()); + } + PageReader pageReader = createPageReader(buffers, totalSize, metadata, columnDescriptor, filteredOffsetIndex); + columnReader.init(pageReader, field, currentGroupRowRanges); + + if (enableVerification) { + ColumnReader verificationColumnReader = verificationColumnReaders[field.getId()]; + PageReader pageReaderVerification = createPageReader(buffers, totalSize, metadata, columnDescriptor, filteredOffsetIndex); + verificationColumnReader.init(pageReaderVerification, field, currentGroupRowRanges); + } + } + else { + byte[] buffer = allocateBlock(totalSize); + dataSource.readFully(startingPosition, buffer); + PageReader pageReader = createPageReader(buffer, totalSize, metadata, columnDescriptor); + columnReader.init(pageReader, field, null); + + if (enableVerification) { + ColumnReader verificationColumnReader = verificationColumnReaders[field.getId()]; + PageReader pageReaderVerification = createPageReader(buffer, totalSize, metadata, columnDescriptor); + verificationColumnReader.init(pageReaderVerification, field, null); + } } } @@ -276,9 +348,44 @@ private ColumnChunk readPrimitive(PrimitiveField field) return columnChunk; } - private byte[] allocateBlock(int length) + private boolean shouldUseColumnIndex(ColumnPath path) + { + return filter != null && + columnIndexFilterEnabled && + currentGroupRowRanges != null && + currentGroupRowRanges.rowCount() < currentGroupRowCount && + blockIndexStores.get(currentBlock) != null && + blockIndexStores.get(currentBlock).getColumnIndex(path) != null; + } + + private List allocateBlocks(List pageRanges) + { + List buffers = new ArrayList<>(); + for (OffsetRange pageRange : pageRanges) { + buffers.add(ByteBuffer.wrap(allocateBlock(pageRange.getLength()))); + } + return buffers; + } + + protected PageReader createPageReader(List buffers, int bufferSize, ColumnChunkMetaData metadata, ColumnDescriptor columnDescriptor, OffsetIndex offsetIndex) + throws IOException + { + ColumnChunkDescriptor descriptor = new ColumnChunkDescriptor(columnDescriptor, metadata, bufferSize); + ParquetColumnChunk columnChunk = new ParquetColumnChunk(descriptor, buffers, offsetIndex); + return columnChunk.readAllPages(); + } + + protected PageReader createPageReader(byte[] buffer, int bufferSize, ColumnChunkMetaData metadata, ColumnDescriptor columnDescriptor) + throws IOException + { + ColumnChunkDescriptor descriptor = new ColumnChunkDescriptor(columnDescriptor, metadata, bufferSize); + ParquetColumnChunk columnChunk = new ParquetColumnChunk(descriptor, buffer, 0); + return columnChunk.readAllPages(); + } + + protected byte[] allocateBlock(long length) { - byte[] buffer = new byte[length]; + byte[] buffer = new byte[toIntExact(length)]; LocalMemoryContext blockMemoryContext = currentRowGroupMemoryContext.newLocalMemoryContext(ParquetReader.class.getSimpleName()); blockMemoryContext.setBytes(buffer.length); return buffer; @@ -408,4 +515,38 @@ private static Block rewriteLongArrayBlock(LongArrayBlock longArrayBlock, Type t return newBlockBuilder.build(); } + + private static List listWithNulls(int size) + { + return Stream.generate(() -> (T) null).limit(size).collect(Collectors.toCollection(ArrayList::new)); + } + + private RowRanges getRowRanges(int blockIndex) + { + assert filter != null; + + RowRanges rowRanges = blockRowRanges.get(blockIndex); + if (rowRanges == null) { + rowRanges = ColumnIndexFilter.calculateRowRanges(FilterCompat.get(filter), blockIndexStores.get(blockIndex), + paths.keySet(), blocks.get(blockIndex).getRowCount()); + blockRowRanges.set(blockIndex, rowRanges); + } + return rowRanges; + } + + private List concatRanges(List offsetRanges) + { + List pageRanges = new ArrayList<>(); + OffsetRange currentParts = null; + for (OffsetRange range : offsetRanges) { + long startPosition = range.getOffset(); + // first part or not consecutive => new list + if (currentParts == null || currentParts.endPos() != startPosition) { + currentParts = new OffsetRange(startPosition, 0); + } + pageRanges.add(currentParts); + currentParts.extendLength(range.getLength()); + } + return pageRanges; + } } diff --git a/presto-parquet/src/main/java/com/facebook/presto/parquet/writer/ParquetWriter.java b/presto-parquet/src/main/java/com/facebook/presto/parquet/writer/ParquetWriter.java index cb49fecc36b14..f4d1407aff0d7 100644 --- a/presto-parquet/src/main/java/com/facebook/presto/parquet/writer/ParquetWriter.java +++ b/presto-parquet/src/main/java/com/facebook/presto/parquet/writer/ParquetWriter.java @@ -211,7 +211,7 @@ private void flush() List bufferDataList = builder.build(); // update stats - long stripeStartOffset = outputStream.size(); + long stripeStartOffset = outputStream.longSize(); List metadatas = bufferDataList.stream() .map(BufferData::getMetaData) .collect(toImmutableList()); diff --git a/presto-parquet/src/test/java/com/facebook/presto/parquet/BenchmarkParquetReader.java b/presto-parquet/src/test/java/com/facebook/presto/parquet/BenchmarkParquetReader.java index d6291b601e4ff..8e0032bdff183 100644 --- a/presto-parquet/src/test/java/com/facebook/presto/parquet/BenchmarkParquetReader.java +++ b/presto-parquet/src/test/java/com/facebook/presto/parquet/BenchmarkParquetReader.java @@ -278,7 +278,7 @@ ParquetReader createRecordReader() this.field = ColumnIOConverter.constructField(getType(), messageColumnIO.getChild(0)).get(); - return new ParquetReader(messageColumnIO, parquetMetadata.getBlocks(), dataSource, newSimpleAggregatedMemoryContext(), new DataSize(16, MEGABYTE), enableOptimizedReader, enableVerification); + return new ParquetReader(messageColumnIO, parquetMetadata.getBlocks(), dataSource, newSimpleAggregatedMemoryContext(), new DataSize(16, MEGABYTE), enableOptimizedReader, enableVerification, null, null, false); } protected boolean getNullability() diff --git a/presto-parquet/src/test/java/com/facebook/presto/parquet/reader/TestColumnIndexBuilder.java b/presto-parquet/src/test/java/com/facebook/presto/parquet/reader/TestColumnIndexBuilder.java new file mode 100644 index 0000000000000..780429b0a0a1e --- /dev/null +++ b/presto-parquet/src/test/java/com/facebook/presto/parquet/reader/TestColumnIndexBuilder.java @@ -0,0 +1,1633 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.parquet.reader; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import org.apache.parquet.bytes.BytesUtils; +import org.apache.parquet.column.statistics.Statistics; +import org.apache.parquet.filter2.predicate.FilterPredicate; +import org.apache.parquet.filter2.predicate.Operators; +import org.apache.parquet.filter2.predicate.UserDefinedPredicate; +import org.apache.parquet.internal.column.columnindex.BoundaryOrder; +import org.apache.parquet.internal.column.columnindex.ColumnIndex; +import org.apache.parquet.internal.column.columnindex.ColumnIndexBuilder; +import org.apache.parquet.io.api.Binary; +import org.apache.parquet.schema.PrimitiveType; +import org.apache.parquet.schema.Types; +import org.testng.annotations.Test; + +import java.math.BigDecimal; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.PrimitiveIterator; + +import static java.util.Arrays.asList; +import static org.apache.parquet.filter2.predicate.FilterApi.binaryColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.booleanColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.doubleColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.eq; +import static org.apache.parquet.filter2.predicate.FilterApi.floatColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.gt; +import static org.apache.parquet.filter2.predicate.FilterApi.gtEq; +import static org.apache.parquet.filter2.predicate.FilterApi.intColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.longColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.lt; +import static org.apache.parquet.filter2.predicate.FilterApi.ltEq; +import static org.apache.parquet.filter2.predicate.FilterApi.notEq; +import static org.apache.parquet.filter2.predicate.FilterApi.userDefined; +import static org.apache.parquet.filter2.predicate.LogicalInverter.invert; +import static org.apache.parquet.schema.OriginalType.DECIMAL; +import static org.apache.parquet.schema.OriginalType.UINT_8; +import static org.apache.parquet.schema.OriginalType.UTF8; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.BINARY; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.BOOLEAN; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.DOUBLE; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.FLOAT; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT32; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT64; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; +import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; + +public class TestColumnIndexBuilder +{ + public static class BinaryDecimalIsNullOrZeroUdp + extends UserDefinedPredicate + { + private static final Binary ZERO = decimalBinary("0.0"); + + @Override + public boolean keep(Binary value) + { + return value == null || value.equals(ZERO); + } + + @Override + public boolean canDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + Comparator cmp = statistics.getComparator(); + return cmp.compare(statistics.getMin(), ZERO) > 0 || cmp.compare(statistics.getMax(), ZERO) < 0; + } + + @Override + public boolean inverseCanDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + Comparator cmp = statistics.getComparator(); + return cmp.compare(statistics.getMin(), ZERO) == 0 && cmp.compare(statistics.getMax(), ZERO) == 0; + } + } + + public static class BinaryUtf8StartsWithB + extends UserDefinedPredicate + { + private static final Binary B = stringBinary("B"); + private static final Binary C = stringBinary("C"); + + @Override + public boolean keep(Binary value) + { + return value != null && value.length() > 0 && value.getBytesUnsafe()[0] == 'B'; + } + + @Override + public boolean canDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + Comparator cmp = statistics.getComparator(); + return cmp.compare(statistics.getMin(), C) >= 0 || cmp.compare(statistics.getMax(), B) < 0; + } + + @Override + public boolean inverseCanDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + Comparator cmp = statistics.getComparator(); + return cmp.compare(statistics.getMin(), B) >= 0 && cmp.compare(statistics.getMax(), C) < 0; + } + } + + public static class BooleanIsTrueOrNull + extends UserDefinedPredicate + { + @Override + public boolean keep(Boolean value) + { + return value == null || value; + } + + @Override + public boolean canDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + return statistics.getComparator().compare(statistics.getMax(), true) != 0; + } + + @Override + public boolean inverseCanDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + return statistics.getComparator().compare(statistics.getMin(), true) == 0; + } + } + + public static class DoubleIsInteger + extends UserDefinedPredicate + { + @Override + public boolean keep(Double value) + { + return value != null && Math.floor(value) == value; + } + + @Override + public boolean canDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + double min = statistics.getMin(); + double max = statistics.getMax(); + Comparator cmp = statistics.getComparator(); + return cmp.compare(Math.floor(min), Math.floor(max)) == 0 && cmp.compare(Math.floor(min), min) != 0 + && cmp.compare(Math.floor(max), max) != 0; + } + + @Override + public boolean inverseCanDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + double min = statistics.getMin(); + double max = statistics.getMax(); + Comparator cmp = statistics.getComparator(); + return cmp.compare(min, max) == 0 && cmp.compare(Math.floor(min), min) == 0; + } + } + + public static class FloatIsInteger + extends UserDefinedPredicate + { + private static float floor(float value) + { + return (float) Math.floor(value); + } + + @Override + public boolean keep(Float value) + { + return value != null && Math.floor(value) == value; + } + + @Override + public boolean canDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + float min = statistics.getMin(); + float max = statistics.getMax(); + Comparator cmp = statistics.getComparator(); + return cmp.compare(floor(min), floor(max)) == 0 && cmp.compare(floor(min), min) != 0 + && cmp.compare(floor(max), max) != 0; + } + + @Override + public boolean inverseCanDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + float min = statistics.getMin(); + float max = statistics.getMax(); + Comparator cmp = statistics.getComparator(); + return cmp.compare(min, max) == 0 && cmp.compare(floor(min), min) == 0; + } + } + + public static class IntegerIsDivisableWith3 + extends UserDefinedPredicate + { + @Override + public boolean keep(Integer value) + { + return value != null && value % 3 == 0; + } + + @Override + public boolean canDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + int min = statistics.getMin(); + int max = statistics.getMax(); + return min % 3 != 0 && max % 3 != 0 && max - min < 3; + } + + @Override + public boolean inverseCanDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + int min = statistics.getMin(); + int max = statistics.getMax(); + return min == max && min % 3 == 0; + } + } + + public static class LongIsDivisableWith3 + extends UserDefinedPredicate + { + @Override + public boolean keep(Long value) + { + return value != null && value % 3 == 0; + } + + @Override + public boolean canDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + long min = statistics.getMin(); + long max = statistics.getMax(); + return min % 3 != 0 && max % 3 != 0 && max - min < 3; + } + + @Override + public boolean inverseCanDrop(org.apache.parquet.filter2.predicate.Statistics statistics) + { + long min = statistics.getMin(); + long max = statistics.getMax(); + return min == max && min % 3 == 0; + } + } + + @Test + public void testBuildBinaryDecimal() + { + PrimitiveType type = Types.required(BINARY).as(DECIMAL).precision(12).scale(2).named("test_binary_decimal"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + //assertThat(builder, instanceOf(BinaryColumnIndexBuilder.class)); + assertNull(builder.build()); + Operators.BinaryColumn col = binaryColumn("test_col"); + + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, decimalBinary("-0.17"), decimalBinary("1234567890.12"))); + builder.add(sb.stats(type, decimalBinary("-234.23"), null, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, decimalBinary("-9999293.23"), decimalBinary("2348978.45"))); + builder.add(sb.stats(type, null, null, null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, decimalBinary("87656273"))); + assertEquals(8, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + ColumnIndex columnIndex = builder.build(); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 0, 3, 3, 0, 4, 2, 0); + assertCorrectNullPages(columnIndex, true, false, false, true, false, true, true, false); + assertCorrectValues(columnIndex.getMaxValues(), + null, + decimalBinary("1234567890.12"), + decimalBinary("-234.23"), + null, + decimalBinary("2348978.45"), + null, + null, + decimalBinary("87656273")); + assertCorrectValues(columnIndex.getMinValues(), + null, + decimalBinary("-0.17"), + decimalBinary("-234.23"), + null, + decimalBinary("-9999293.23"), + null, + null, + decimalBinary("87656273")); + assertCorrectFiltering(columnIndex, eq(col, decimalBinary("0.0")), 1, 4); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 2, 3, 5, 6); + assertCorrectFiltering(columnIndex, notEq(col, decimalBinary("87656273")), 0, 1, 2, 3, 4, 5, 6); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 2, 4, 7); + assertCorrectFiltering(columnIndex, gt(col, decimalBinary("2348978.45")), 1); + assertCorrectFiltering(columnIndex, gtEq(col, decimalBinary("2348978.45")), 1, 4); + assertCorrectFiltering(columnIndex, lt(col, decimalBinary("-234.23")), 4); + assertCorrectFiltering(columnIndex, ltEq(col, decimalBinary("-234.23")), 2, 4); + assertCorrectFiltering(columnIndex, userDefined(col, BinaryDecimalIsNullOrZeroUdp.class), 0, 1, 2, 3, 4, 5, 6); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BinaryDecimalIsNullOrZeroUdp.class)), 1, 2, 4, 7); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null, null, null)); + builder.add(sb.stats(type, decimalBinary("-9999293.23"), decimalBinary("-234.23"))); + builder.add(sb.stats(type, decimalBinary("-0.17"), decimalBinary("87656273"))); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, decimalBinary("87656273"))); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, decimalBinary("1234567890.12"), null, null, null)); + builder.add(sb.stats(type, null, null, null)); + assertEquals(8, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 4, 0, 0, 2, 0, 2, 3, 3); + assertCorrectNullPages(columnIndex, true, false, false, true, false, true, false, true); + assertCorrectValues(columnIndex.getMaxValues(), + null, + decimalBinary("-234.23"), + decimalBinary("87656273"), + null, + decimalBinary("87656273"), + null, + decimalBinary("1234567890.12"), + null); + assertCorrectValues(columnIndex.getMinValues(), + null, + decimalBinary("-9999293.23"), + decimalBinary("-0.17"), + null, + decimalBinary("87656273"), + null, + decimalBinary("1234567890.12"), + null); + assertCorrectFiltering(columnIndex, eq(col, decimalBinary("87656273")), 2, 4); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 3, 5, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, decimalBinary("87656273")), 0, 1, 2, 3, 5, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 2, 4, 6); + assertCorrectFiltering(columnIndex, gt(col, decimalBinary("87656273")), 6); + assertCorrectFiltering(columnIndex, gtEq(col, decimalBinary("87656273")), 2, 4, 6); + assertCorrectFiltering(columnIndex, lt(col, decimalBinary("-0.17")), 1); + assertCorrectFiltering(columnIndex, ltEq(col, decimalBinary("-0.17")), 1, 2); + assertCorrectFiltering(columnIndex, userDefined(col, BinaryDecimalIsNullOrZeroUdp.class), 0, 2, 3, 5, 6, 7); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BinaryDecimalIsNullOrZeroUdp.class)), 1, 2, 4, 6); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, decimalBinary("1234567890.12"), null, null, null)); + builder.add(sb.stats(type, null, null, null, null)); + builder.add(sb.stats(type, decimalBinary("1234567890.12"), decimalBinary("87656273"))); + builder.add(sb.stats(type, decimalBinary("987656273"), decimalBinary("-0.17"))); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, decimalBinary("-234.23"), decimalBinary("-9999293.23"))); + assertEquals(8, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 3, 2, 3, 4, 0, 0, 2, 0); + assertCorrectNullPages(columnIndex, true, true, false, true, false, false, true, false); + assertCorrectValues(columnIndex.getMaxValues(), + null, + null, + decimalBinary("1234567890.12"), + null, + decimalBinary("1234567890.12"), + decimalBinary("987656273"), + null, + decimalBinary("-234.23")); + assertCorrectValues(columnIndex.getMinValues(), + null, + null, + decimalBinary("1234567890.12"), + null, + decimalBinary("87656273"), + decimalBinary("-0.17"), + null, + decimalBinary("-9999293.23")); + assertCorrectFiltering(columnIndex, eq(col, decimalBinary("1234567890.12")), 2, 4); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 1, 2, 3, 6); + assertCorrectFiltering(columnIndex, notEq(col, decimalBinary("0.0")), 0, 1, 2, 3, 4, 5, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, null), 2, 4, 5, 7); + assertCorrectFiltering(columnIndex, gt(col, decimalBinary("1234567890.12"))); + assertCorrectFiltering(columnIndex, gtEq(col, decimalBinary("1234567890.12")), 2, 4); + assertCorrectFiltering(columnIndex, lt(col, decimalBinary("-0.17")), 7); + assertCorrectFiltering(columnIndex, ltEq(col, decimalBinary("-0.17")), 5, 7); + assertCorrectFiltering(columnIndex, userDefined(col, BinaryDecimalIsNullOrZeroUdp.class), 0, 1, 2, 3, 5, 6); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BinaryDecimalIsNullOrZeroUdp.class)), 2, 4, 5, 7); + } + + @Test + public void testBuildBinaryUtf8() + { + PrimitiveType type = Types.required(BINARY).as(UTF8).named("test_binary_utf8"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + //assertThat(builder, instanceOf(BinaryColumnIndexBuilder.class)); + assertNull(builder.build()); + Operators.BinaryColumn col = binaryColumn("test_col"); + + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, stringBinary("Jeltz"), stringBinary("Slartibartfast"), null, null)); + builder.add(sb.stats(type, null, null, null, null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, stringBinary("Beeblebrox"), stringBinary("Prefect"))); + builder.add(sb.stats(type, stringBinary("Dent"), stringBinary("Trilian"), null)); + builder.add(sb.stats(type, stringBinary("Beeblebrox"))); + builder.add(sb.stats(type, null, null)); + assertEquals(8, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + ColumnIndex columnIndex = builder.build(); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 2, 5, 2, 0, 1, 0, 2); + assertCorrectNullPages(columnIndex, true, false, true, true, false, false, false, true); + assertCorrectValues(columnIndex.getMaxValues(), + null, + stringBinary("Slartibartfast"), + null, + null, + stringBinary("Prefect"), + stringBinary("Trilian"), + stringBinary("Beeblebrox"), + null); + assertCorrectValues(columnIndex.getMinValues(), + null, + stringBinary("Jeltz"), + null, + null, + stringBinary("Beeblebrox"), + stringBinary("Dent"), + stringBinary("Beeblebrox"), + null); + assertCorrectFiltering(columnIndex, eq(col, stringBinary("Marvin")), 1, 4, 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 1, 2, 3, 5, 7); + assertCorrectFiltering(columnIndex, notEq(col, stringBinary("Beeblebrox")), 0, 1, 2, 3, 4, 5, 7); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 4, 5, 6); + assertCorrectFiltering(columnIndex, gt(col, stringBinary("Prefect")), 1, 5); + assertCorrectFiltering(columnIndex, gtEq(col, stringBinary("Prefect")), 1, 4, 5); + assertCorrectFiltering(columnIndex, lt(col, stringBinary("Dent")), 4, 6); + assertCorrectFiltering(columnIndex, ltEq(col, stringBinary("Dent")), 4, 5, 6); + assertCorrectFiltering(columnIndex, userDefined(col, BinaryUtf8StartsWithB.class), 4, 6); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BinaryUtf8StartsWithB.class)), 0, 1, 2, 3, 4, 5, 7); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, stringBinary("Beeblebrox"), stringBinary("Dent"), null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null, null, null, null)); + builder.add(sb.stats(type, stringBinary("Dent"), stringBinary("Jeltz"))); + builder.add(sb.stats(type, stringBinary("Dent"), stringBinary("Prefect"), null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, stringBinary("Slartibartfast"))); + builder.add(sb.stats(type, null, null)); + assertEquals(8, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 2, 5, 0, 1, 2, 0, 2); + assertCorrectNullPages(columnIndex, false, true, true, false, false, true, false, true); + assertCorrectValues(columnIndex.getMaxValues(), + stringBinary("Dent"), + null, + null, + stringBinary("Jeltz"), + stringBinary("Prefect"), + null, + stringBinary("Slartibartfast"), + null); + assertCorrectValues(columnIndex.getMinValues(), + stringBinary("Beeblebrox"), + null, + null, + stringBinary("Dent"), + stringBinary("Dent"), + null, + stringBinary("Slartibartfast"), + null); + assertCorrectFiltering(columnIndex, eq(col, stringBinary("Jeltz")), 3, 4); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 1, 2, 4, 5, 7); + assertCorrectFiltering(columnIndex, notEq(col, stringBinary("Slartibartfast")), 0, 1, 2, 3, 4, 5, 7); + assertCorrectFiltering(columnIndex, notEq(col, null), 0, 3, 4, 6); + assertCorrectFiltering(columnIndex, gt(col, stringBinary("Marvin")), 4, 6); + assertCorrectFiltering(columnIndex, gtEq(col, stringBinary("Marvin")), 4, 6); + assertCorrectFiltering(columnIndex, lt(col, stringBinary("Dent")), 0); + assertCorrectFiltering(columnIndex, ltEq(col, stringBinary("Dent")), 0, 3, 4); + assertCorrectFiltering(columnIndex, userDefined(col, BinaryUtf8StartsWithB.class), 0); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BinaryUtf8StartsWithB.class)), 0, 1, 2, 3, 4, 5, 6, 7); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, stringBinary("Slartibartfast"))); + builder.add(sb.stats(type, null, null, null, null, null)); + builder.add(sb.stats(type, stringBinary("Prefect"), stringBinary("Jeltz"), null)); + builder.add(sb.stats(type, stringBinary("Dent"), stringBinary("Dent"))); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, stringBinary("Dent"), stringBinary("Beeblebrox"), null, null)); + assertEquals(8, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 0, 5, 1, 0, 2, 2, 2); + assertCorrectNullPages(columnIndex, true, false, true, false, false, true, true, false); + assertCorrectValues(columnIndex.getMaxValues(), + null, + stringBinary("Slartibartfast"), + null, + stringBinary("Prefect"), + stringBinary("Dent"), + null, + null, + stringBinary("Dent")); + assertCorrectValues(columnIndex.getMinValues(), + null, + stringBinary("Slartibartfast"), + null, + stringBinary("Jeltz"), + stringBinary("Dent"), + null, + null, + stringBinary("Beeblebrox")); + assertCorrectFiltering(columnIndex, eq(col, stringBinary("Marvin")), 3); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 2, 3, 5, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, stringBinary("Dent")), 0, 1, 2, 3, 5, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 3, 4, 7); + assertCorrectFiltering(columnIndex, gt(col, stringBinary("Prefect")), 1); + assertCorrectFiltering(columnIndex, gtEq(col, stringBinary("Prefect")), 1, 3); + assertCorrectFiltering(columnIndex, lt(col, stringBinary("Marvin")), 3, 4, 7); + assertCorrectFiltering(columnIndex, ltEq(col, stringBinary("Marvin")), 3, 4, 7); + assertCorrectFiltering(columnIndex, userDefined(col, BinaryUtf8StartsWithB.class), 7); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BinaryUtf8StartsWithB.class)), 0, 1, 2, 3, 4, 5, 6, 7); + } + + @Test + public void testStaticBuildBinary() + { + ColumnIndex columnIndex = ColumnIndexBuilder.build( + Types.required(BINARY).as(UTF8).named("test_binary_utf8"), + BoundaryOrder.ASCENDING, + asList(true, true, false, false, true, false, true, false), + asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L), + toBBList( + null, + null, + stringBinary("Beeblebrox"), + stringBinary("Dent"), + null, + stringBinary("Jeltz"), + null, + stringBinary("Slartibartfast")), + toBBList( + null, + null, + stringBinary("Dent"), + stringBinary("Dent"), + null, + stringBinary("Prefect"), + null, + stringBinary("Slartibartfast"))); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectNullPages(columnIndex, true, true, false, false, true, false, true, false); + assertCorrectValues(columnIndex.getMaxValues(), + null, + null, + stringBinary("Dent"), + stringBinary("Dent"), + null, + stringBinary("Prefect"), + null, + stringBinary("Slartibartfast")); + assertCorrectValues(columnIndex.getMinValues(), + null, + null, + stringBinary("Beeblebrox"), + stringBinary("Dent"), + null, + stringBinary("Jeltz"), + null, + stringBinary("Slartibartfast")); + } + + @Test + public void testFilterWithoutNullCounts() + { + ColumnIndex columnIndex = ColumnIndexBuilder.build( + Types.required(BINARY).as(UTF8).named("test_binary_utf8"), + BoundaryOrder.ASCENDING, + asList(true, true, false, false, true, false, true, false), + null, + toBBList( + null, + null, + stringBinary("Beeblebrox"), + stringBinary("Dent"), + null, + stringBinary("Jeltz"), + null, + stringBinary("Slartibartfast")), + toBBList( + null, + null, + stringBinary("Dent"), + stringBinary("Dent"), + null, + stringBinary("Prefect"), + null, + stringBinary("Slartibartfast"))); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertNull(columnIndex.getNullCounts()); + assertCorrectNullPages(columnIndex, true, true, false, false, true, false, true, false); + assertCorrectValues(columnIndex.getMaxValues(), + null, + null, + stringBinary("Dent"), + stringBinary("Dent"), + null, + stringBinary("Prefect"), + null, + stringBinary("Slartibartfast")); + assertCorrectValues(columnIndex.getMinValues(), + null, + null, + stringBinary("Beeblebrox"), + stringBinary("Dent"), + null, + stringBinary("Jeltz"), + null, + stringBinary("Slartibartfast")); + + Operators.BinaryColumn col = binaryColumn("test_col"); + assertCorrectFiltering(columnIndex, eq(col, stringBinary("Dent")), 2, 3); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 1, 2, 3, 4, 5, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, stringBinary("Dent")), 0, 1, 2, 3, 4, 5, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, null), 2, 3, 5, 7); + assertCorrectFiltering(columnIndex, userDefined(col, BinaryDecimalIsNullOrZeroUdp.class), 0, 1, 2, 3, 4, 5, 6, 7); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BinaryDecimalIsNullOrZeroUdp.class)), 2, 3, 5, 7); + } + + @Test + public void testBuildBoolean() + { + PrimitiveType type = Types.required(BOOLEAN).named("test_boolean"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + //assertThat(builder, instanceOf(BooleanColumnIndexBuilder.class)); + assertNull(builder.build()); + Operators.BooleanColumn col = booleanColumn("test_col"); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, false, true)); + builder.add(sb.stats(type, true, false, null)); + builder.add(sb.stats(type, true, true, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, false, false)); + assertEquals(5, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + ColumnIndex columnIndex = builder.build(); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 0, 1, 2, 3, 0); + assertCorrectNullPages(columnIndex, false, false, false, true, false); + assertCorrectValues(columnIndex.getMaxValues(), true, true, true, null, false); + assertCorrectValues(columnIndex.getMinValues(), false, false, true, null, false); + assertCorrectFiltering(columnIndex, eq(col, true), 0, 1, 2); + assertCorrectFiltering(columnIndex, eq(col, null), 1, 2, 3); + assertCorrectFiltering(columnIndex, notEq(col, true), 0, 1, 2, 3, 4); + assertCorrectFiltering(columnIndex, notEq(col, null), 0, 1, 2, 4); + assertCorrectFiltering(columnIndex, userDefined(col, BooleanIsTrueOrNull.class), 0, 1, 2, 3); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BooleanIsTrueOrNull.class)), 0, 1, 4); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, false, false)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, null, null, null, null)); + builder.add(sb.stats(type, false, true, null)); + builder.add(sb.stats(type, false, true, null, null)); + builder.add(sb.stats(type, null, null, null)); + assertEquals(7, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 0, 3, 4, 1, 2, 3); + assertCorrectNullPages(columnIndex, true, false, true, true, false, false, true); + assertCorrectValues(columnIndex.getMaxValues(), null, false, null, null, true, true, null); + assertCorrectValues(columnIndex.getMinValues(), null, false, null, null, false, false, null); + assertCorrectFiltering(columnIndex, eq(col, true), 4, 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 2, 3, 4, 5, 6); + assertCorrectFiltering(columnIndex, notEq(col, true), 0, 1, 2, 3, 4, 5, 6); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 4, 5); + assertCorrectFiltering(columnIndex, userDefined(col, BooleanIsTrueOrNull.class), 0, 2, 3, 4, 5, 6); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BooleanIsTrueOrNull.class)), 1, 4, 5); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, true, true)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, null, null, null, null)); + builder.add(sb.stats(type, true, false, null)); + builder.add(sb.stats(type, false, false, null, null)); + builder.add(sb.stats(type, null, null, null)); + assertEquals(7, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 0, 3, 4, 1, 2, 3); + assertCorrectNullPages(columnIndex, true, false, true, true, false, false, true); + assertCorrectValues(columnIndex.getMaxValues(), null, true, null, null, true, false, null); + assertCorrectValues(columnIndex.getMinValues(), null, true, null, null, false, false, null); + assertCorrectFiltering(columnIndex, eq(col, true), 1, 4); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 2, 3, 4, 5, 6); + assertCorrectFiltering(columnIndex, notEq(col, true), 0, 2, 3, 4, 5, 6); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 4, 5); + assertCorrectFiltering(columnIndex, userDefined(col, BooleanIsTrueOrNull.class), 0, 1, 2, 3, 4, 5, 6); + assertCorrectFiltering(columnIndex, invert(userDefined(col, BooleanIsTrueOrNull.class)), 4, 5); + } + + @Test + public void testStaticBuildBoolean() + { + ColumnIndex columnIndex = ColumnIndexBuilder.build( + Types.required(BOOLEAN).named("test_boolean"), + BoundaryOrder.DESCENDING, + asList(false, true, false, true, false, true), + asList(9L, 8L, 7L, 6L, 5L, 0L), + toBBList(false, null, false, null, true, null), + toBBList(true, null, false, null, true, null)); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 9, 8, 7, 6, 5, 0); + assertCorrectNullPages(columnIndex, false, true, false, true, false, true); + assertCorrectValues(columnIndex.getMaxValues(), true, null, false, null, true, null); + assertCorrectValues(columnIndex.getMinValues(), false, null, false, null, true, null); + } + + @Test + public void testBuildDouble() + { + PrimitiveType type = Types.required(DOUBLE).named("test_double"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + //assertThat(builder, instanceOf(DoubleColumnIndexBuilder.class)); + assertNull(builder.build()); + Operators.DoubleColumn col = doubleColumn("test_col"); + + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, -4.2, -4.1)); + builder.add(sb.stats(type, -11.7, 7.0, null)); + builder.add(sb.stats(type, 2.2, 2.2, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 1.9, 2.32)); + builder.add(sb.stats(type, -21.0, 8.1)); + assertEquals(6, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + ColumnIndex columnIndex = builder.build(); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 0, 1, 2, 3, 0, 0); + assertCorrectNullPages(columnIndex, false, false, false, true, false, false); + assertCorrectValues(columnIndex.getMaxValues(), -4.1, 7.0, 2.2, null, 2.32, 8.1); + assertCorrectValues(columnIndex.getMinValues(), -4.2, -11.7, 2.2, null, 1.9, -21.0); + assertCorrectFiltering(columnIndex, eq(col, 0.0), 1, 5); + assertCorrectFiltering(columnIndex, eq(col, null), 1, 2, 3); + assertCorrectFiltering(columnIndex, notEq(col, 2.2), 0, 1, 2, 3, 4, 5); + assertCorrectFiltering(columnIndex, notEq(col, null), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, gt(col, 2.2), 1, 4, 5); + assertCorrectFiltering(columnIndex, gtEq(col, 2.2), 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, lt(col, -4.2), 1, 5); + assertCorrectFiltering(columnIndex, ltEq(col, -4.2), 0, 1, 5); + assertCorrectFiltering(columnIndex, userDefined(col, DoubleIsInteger.class), 1, 4, 5); + assertCorrectFiltering(columnIndex, invert(userDefined(col, DoubleIsInteger.class)), 0, 1, 2, 3, 4, 5); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, -532.3, -345.2, null, null)); + builder.add(sb.stats(type, -234.7, -234.6, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, -234.6, 2.99999)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 3.0, 42.83)); + builder.add(sb.stats(type, null, null)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 2, 1, 2, 3, 0, 2, 0, 2); + assertCorrectNullPages(columnIndex, true, false, false, true, true, false, true, false, true); + assertCorrectValues(columnIndex.getMaxValues(), null, -345.2, -234.6, null, null, 2.99999, null, 42.83, null); + assertCorrectValues(columnIndex.getMinValues(), null, -532.3, -234.7, null, null, -234.6, null, 3.0, null); + assertCorrectFiltering(columnIndex, eq(col, 0.0), 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 1, 2, 3, 4, 6, 8); + assertCorrectFiltering(columnIndex, notEq(col, 0.0), 0, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 2, 5, 7); + assertCorrectFiltering(columnIndex, gt(col, 2.99999), 7); + assertCorrectFiltering(columnIndex, gtEq(col, 2.99999), 5, 7); + assertCorrectFiltering(columnIndex, lt(col, -234.6), 1, 2); + assertCorrectFiltering(columnIndex, ltEq(col, -234.6), 1, 2, 5); + assertCorrectFiltering(columnIndex, userDefined(col, DoubleIsInteger.class), 1, 5, 7); + assertCorrectFiltering(columnIndex, invert(userDefined(col, DoubleIsInteger.class)), 0, 1, 2, 3, 4, 5, 6, 7, 8); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null, null, null, null)); + builder.add(sb.stats(type, 532.3, 345.2)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 234.7, 234.6, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 234.69, -2.99999)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, -3.0, -42.83)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 5, 0, 3, 1, 2, 0, 2, 2, 0); + assertCorrectNullPages(columnIndex, true, false, true, false, true, false, true, true, false); + assertCorrectValues(columnIndex.getMaxValues(), null, 532.3, null, 234.7, null, 234.69, null, null, -3.0); + assertCorrectValues(columnIndex.getMinValues(), null, 345.2, null, 234.6, null, -2.99999, null, null, -42.83); + assertCorrectFiltering(columnIndex, eq(col, 234.6), 3, 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 2, 3, 4, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, 2.2), 0, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 3, 5, 8); + assertCorrectFiltering(columnIndex, gt(col, 2.2), 1, 3, 5); + assertCorrectFiltering(columnIndex, gtEq(col, 234.69), 1, 3, 5); + assertCorrectFiltering(columnIndex, lt(col, -2.99999), 8); + assertCorrectFiltering(columnIndex, ltEq(col, -2.99999), 5, 8); + assertCorrectFiltering(columnIndex, userDefined(col, DoubleIsInteger.class), 1, 5, 8); + assertCorrectFiltering(columnIndex, invert(userDefined(col, DoubleIsInteger.class)), 0, 1, 2, 3, 4, 5, 6, 7, 8); + } + + @Test + public void testBuildDoubleZeroNaN() + { + PrimitiveType type = Types.required(DOUBLE).named("test_double"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, -1.0, -0.0)); + builder.add(sb.stats(type, 0.0, 1.0)); + builder.add(sb.stats(type, 1.0, 100.0)); + ColumnIndex columnIndex = builder.build(); + assertCorrectValues(columnIndex.getMinValues(), -1.0, -0.0, 1.0); + assertCorrectValues(columnIndex.getMaxValues(), 0.0, 1.0, 100.0); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + builder.add(sb.stats(type, -1.0, -0.0)); + builder.add(sb.stats(type, 0.0, Double.NaN)); + builder.add(sb.stats(type, 1.0, 100.0)); + assertNull(builder.build()); + } + + @Test + public void testStaticBuildDouble() + { + ColumnIndex columnIndex = ColumnIndexBuilder.build( + Types.required(DOUBLE).named("test_double"), + BoundaryOrder.UNORDERED, + asList(false, false, false, false, false, false), + asList(0L, 1L, 2L, 3L, 4L, 5L), + toBBList(-1.0, -2.0, -3.0, -4.0, -5.0, -6.0), + toBBList(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 0, 1, 2, 3, 4, 5); + assertCorrectNullPages(columnIndex, false, false, false, false, false, false); + assertCorrectValues(columnIndex.getMaxValues(), 1.0, 2.0, 3.0, 4.0, 5.0, 6.0); + assertCorrectValues(columnIndex.getMinValues(), -1.0, -2.0, -3.0, -4.0, -5.0, -6.0); + } + + @Test + public void testBuildFloat() + { + PrimitiveType type = Types.required(FLOAT).named("test_float"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + //assertThat(builder, instanceOf(FloatColumnIndexBuilder.class)); + assertNull(builder.build()); + Operators.FloatColumn col = floatColumn("test_col"); + + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, -4.2f, -4.1f)); + builder.add(sb.stats(type, -11.7f, 7.0f, null)); + builder.add(sb.stats(type, 2.2f, 2.2f, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 1.9f, 2.32f)); + builder.add(sb.stats(type, -21.0f, 8.1f)); + assertEquals(6, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + ColumnIndex columnIndex = builder.build(); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 0, 1, 2, 3, 0, 0); + assertCorrectNullPages(columnIndex, false, false, false, true, false, false); + assertCorrectValues(columnIndex.getMaxValues(), -4.1f, 7.0f, 2.2f, null, 2.32f, 8.1f); + assertCorrectValues(columnIndex.getMinValues(), -4.2f, -11.7f, 2.2f, null, 1.9f, -21.0f); + assertCorrectFiltering(columnIndex, eq(col, 0.0f), 1, 5); + assertCorrectFiltering(columnIndex, eq(col, null), 1, 2, 3); + assertCorrectFiltering(columnIndex, notEq(col, 2.2f), 0, 1, 2, 3, 4, 5); + assertCorrectFiltering(columnIndex, notEq(col, null), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, gt(col, 2.2f), 1, 4, 5); + assertCorrectFiltering(columnIndex, gtEq(col, 2.2f), 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, lt(col, 0.0f), 0, 1, 5); + assertCorrectFiltering(columnIndex, ltEq(col, 1.9f), 0, 1, 4, 5); + assertCorrectFiltering(columnIndex, userDefined(col, FloatIsInteger.class), 1, 4, 5); + assertCorrectFiltering(columnIndex, invert(userDefined(col, FloatIsInteger.class)), 0, 1, 2, 3, 4, 5); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, -532.3f, -345.2f, null, null)); + builder.add(sb.stats(type, -300.6f, -234.7f, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, -234.6f, 2.99999f)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 3.0f, 42.83f)); + builder.add(sb.stats(type, null, null)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 2, 1, 2, 3, 0, 2, 0, 2); + assertCorrectNullPages(columnIndex, true, false, false, true, true, false, true, false, true); + assertCorrectValues(columnIndex.getMaxValues(), null, -345.2f, -234.7f, null, null, 2.99999f, null, 42.83f, null); + assertCorrectValues(columnIndex.getMinValues(), null, -532.3f, -300.6f, null, null, -234.6f, null, 3.0f, null); + assertCorrectFiltering(columnIndex, eq(col, 0.0f), 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 1, 2, 3, 4, 6, 8); + assertCorrectFiltering(columnIndex, notEq(col, 2.2f), 0, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 2, 5, 7); + assertCorrectFiltering(columnIndex, gt(col, 2.2f), 5, 7); + assertCorrectFiltering(columnIndex, gtEq(col, -234.7f), 2, 5, 7); + assertCorrectFiltering(columnIndex, lt(col, -234.6f), 1, 2); + assertCorrectFiltering(columnIndex, ltEq(col, -234.6f), 1, 2, 5); + assertCorrectFiltering(columnIndex, userDefined(col, FloatIsInteger.class), 1, 2, 5, 7); + assertCorrectFiltering(columnIndex, invert(userDefined(col, FloatIsInteger.class)), 0, 1, 2, 3, 4, 5, 6, 7, 8); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null, null, null, null)); + builder.add(sb.stats(type, 532.3f, 345.2f)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 234.7f, 234.6f, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 234.6f, -2.99999f)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, -3.0f, -42.83f)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 5, 0, 3, 1, 2, 0, 2, 2, 0); + assertCorrectNullPages(columnIndex, true, false, true, false, true, false, true, true, false); + assertCorrectValues(columnIndex.getMaxValues(), null, 532.3f, null, 234.7f, null, 234.6f, null, null, -3.0f); + assertCorrectValues(columnIndex.getMinValues(), null, 345.2f, null, 234.6f, null, -2.99999f, null, null, -42.83f); + assertCorrectFiltering(columnIndex, eq(col, 234.65f), 3); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 2, 3, 4, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, 2.2f), 0, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 3, 5, 8); + assertCorrectFiltering(columnIndex, gt(col, 2.2f), 1, 3, 5); + assertCorrectFiltering(columnIndex, gtEq(col, 2.2f), 1, 3, 5); + assertCorrectFiltering(columnIndex, lt(col, 0.0f), 5, 8); + assertCorrectFiltering(columnIndex, ltEq(col, 0.0f), 5, 8); + assertCorrectFiltering(columnIndex, userDefined(col, FloatIsInteger.class), 1, 5, 8); + assertCorrectFiltering(columnIndex, invert(userDefined(col, FloatIsInteger.class)), 0, 1, 2, 3, 4, 5, 6, 7, 8); + } + + @Test + public void testBuildFloatZeroNaN() + { + PrimitiveType type = Types.required(FLOAT).named("test_float"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, -1.0f, -0.0f)); + builder.add(sb.stats(type, 0.0f, 1.0f)); + builder.add(sb.stats(type, 1.0f, 100.0f)); + ColumnIndex columnIndex = builder.build(); + assertCorrectValues(columnIndex.getMinValues(), -1.0f, -0.0f, 1.0f); + assertCorrectValues(columnIndex.getMaxValues(), 0.0f, 1.0f, 100.0f); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + builder.add(sb.stats(type, -1.0f, -0.0f)); + builder.add(sb.stats(type, 0.0f, Float.NaN)); + builder.add(sb.stats(type, 1.0f, 100.0f)); + assertNull(builder.build()); + } + + @Test + public void testStaticBuildFloat() + { + ColumnIndex columnIndex = ColumnIndexBuilder.build( + Types.required(FLOAT).named("test_float"), + BoundaryOrder.ASCENDING, + asList(true, true, true, false, false, false), + asList(9L, 8L, 7L, 6L, 0L, 0L), + toBBList(null, null, null, -3.0f, -2.0f, 0.1f), + toBBList(null, null, null, -2.0f, 0.0f, 6.0f)); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 9, 8, 7, 6, 0, 0); + assertCorrectNullPages(columnIndex, true, true, true, false, false, false); + assertCorrectValues(columnIndex.getMaxValues(), null, null, null, -2.0f, 0.0f, 6.0f); + assertCorrectValues(columnIndex.getMinValues(), null, null, null, -3.0f, -2.0f, 0.1f); + } + + @Test + public void testBuildInt32() + { + PrimitiveType type = Types.required(INT32).named("test_int32"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + //assertThat(builder, instanceOf(IntColumnIndexBuilder.class)); + assertNull(builder.build()); + Operators.IntColumn col = intColumn("test_col"); + + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, -4, 10)); + builder.add(sb.stats(type, -11, 7, null)); + builder.add(sb.stats(type, 2, 2, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 1, 2)); + builder.add(sb.stats(type, -21, 8)); + assertEquals(6, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + ColumnIndex columnIndex = builder.build(); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 0, 1, 2, 3, 0, 0); + assertCorrectNullPages(columnIndex, false, false, false, true, false, false); + assertCorrectValues(columnIndex.getMaxValues(), 10, 7, 2, null, 2, 8); + assertCorrectValues(columnIndex.getMinValues(), -4, -11, 2, null, 1, -21); + assertCorrectFiltering(columnIndex, eq(col, 2), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, eq(col, null), 1, 2, 3); + assertCorrectFiltering(columnIndex, notEq(col, 2), 0, 1, 2, 3, 4, 5); + assertCorrectFiltering(columnIndex, notEq(col, null), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, gt(col, 2), 0, 1, 5); + assertCorrectFiltering(columnIndex, gtEq(col, 2), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, lt(col, 2), 0, 1, 4, 5); + assertCorrectFiltering(columnIndex, ltEq(col, 2), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, userDefined(col, IntegerIsDivisableWith3.class), 0, 1, 5); + assertCorrectFiltering(columnIndex, invert(userDefined(col, IntegerIsDivisableWith3.class)), 0, 1, 2, 3, 4, 5); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, -532, -345, null, null)); + builder.add(sb.stats(type, -500, -42, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, -42, 2)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 3, 42)); + builder.add(sb.stats(type, null, null)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 2, 1, 2, 3, 0, 2, 0, 2); + assertCorrectNullPages(columnIndex, true, false, false, true, true, false, true, false, true); + assertCorrectValues(columnIndex.getMaxValues(), null, -345, -42, null, null, 2, null, 42, null); + assertCorrectValues(columnIndex.getMinValues(), null, -532, -500, null, null, -42, null, 3, null); + assertCorrectFiltering(columnIndex, eq(col, 2), 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 1, 2, 3, 4, 6, 8); + assertCorrectFiltering(columnIndex, notEq(col, 2), 0, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 2, 5, 7); + assertCorrectFiltering(columnIndex, gt(col, 2), 7); + assertCorrectFiltering(columnIndex, gtEq(col, 2), 5, 7); + assertCorrectFiltering(columnIndex, lt(col, 2), 1, 2, 5); + assertCorrectFiltering(columnIndex, ltEq(col, 2), 1, 2, 5); + assertCorrectFiltering(columnIndex, userDefined(col, IntegerIsDivisableWith3.class), 1, 2, 5, 7); + assertCorrectFiltering(columnIndex, invert(userDefined(col, IntegerIsDivisableWith3.class)), 0, 1, 2, 3, 4, 5, 6, 7, + 8); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null, null, null, null)); + builder.add(sb.stats(type, 532, 345)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 234, 42, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 42, -2)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, -3, -42)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 5, 0, 3, 1, 2, 0, 2, 2, 0); + assertCorrectNullPages(columnIndex, true, false, true, false, true, false, true, true, false); + assertCorrectValues(columnIndex.getMaxValues(), null, 532, null, 234, null, 42, null, null, -3); + assertCorrectValues(columnIndex.getMinValues(), null, 345, null, 42, null, -2, null, null, -42); + assertCorrectFiltering(columnIndex, eq(col, 2), 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 2, 3, 4, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, 2), 0, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 3, 5, 8); + assertCorrectFiltering(columnIndex, gt(col, 2), 1, 3, 5); + assertCorrectFiltering(columnIndex, gtEq(col, 2), 1, 3, 5); + assertCorrectFiltering(columnIndex, lt(col, 2), 5, 8); + assertCorrectFiltering(columnIndex, ltEq(col, 2), 5, 8); + assertCorrectFiltering(columnIndex, userDefined(col, IntegerIsDivisableWith3.class), 1, 3, 5, 8); + assertCorrectFiltering(columnIndex, invert(userDefined(col, IntegerIsDivisableWith3.class)), 0, 1, 2, 3, 4, 5, 6, 7, + 8); + } + + @Test + public void testStaticBuildInt32() + { + ColumnIndex columnIndex = ColumnIndexBuilder.build( + Types.required(INT32).named("test_int32"), + BoundaryOrder.DESCENDING, + asList(false, false, false, true, true, true), + asList(0L, 10L, 0L, 3L, 5L, 7L), + toBBList(10, 8, 6, null, null, null), + toBBList(9, 7, 5, null, null, null)); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 0, 10, 0, 3, 5, 7); + assertCorrectNullPages(columnIndex, false, false, false, true, true, true); + assertCorrectValues(columnIndex.getMaxValues(), 9, 7, 5, null, null, null); + assertCorrectValues(columnIndex.getMinValues(), 10, 8, 6, null, null, null); + } + + @Test + public void testBuildUInt8() + { + PrimitiveType type = Types.required(INT32).as(UINT_8).named("test_uint8"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + //assertThat(builder, instanceOf(IntColumnIndexBuilder.class)); + assertNull(builder.build()); + Operators.IntColumn col = intColumn("test_col"); + + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, 4, 10)); + builder.add(sb.stats(type, 11, 17, null)); + builder.add(sb.stats(type, 2, 2, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 1, 0xFF)); + builder.add(sb.stats(type, 0xEF, 0xFA)); + assertEquals(6, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + ColumnIndex columnIndex = builder.build(); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 0, 1, 2, 3, 0, 0); + assertCorrectNullPages(columnIndex, false, false, false, true, false, false); + assertCorrectValues(columnIndex.getMaxValues(), 10, 17, 2, null, 0xFF, 0xFA); + assertCorrectValues(columnIndex.getMinValues(), 4, 11, 2, null, 1, 0xEF); + assertCorrectFiltering(columnIndex, eq(col, 2), 2, 4); + assertCorrectFiltering(columnIndex, eq(col, null), 1, 2, 3); + assertCorrectFiltering(columnIndex, notEq(col, 2), 0, 1, 2, 3, 4, 5); + assertCorrectFiltering(columnIndex, notEq(col, null), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, gt(col, 2), 0, 1, 4, 5); + assertCorrectFiltering(columnIndex, gtEq(col, 2), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, lt(col, 0xEF), 0, 1, 2, 4); + assertCorrectFiltering(columnIndex, ltEq(col, 0xEF), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, userDefined(col, IntegerIsDivisableWith3.class), 0, 1, 4, 5); + assertCorrectFiltering(columnIndex, invert(userDefined(col, IntegerIsDivisableWith3.class)), 0, 1, 2, 3, 4, 5); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 0, 0, null, null)); + builder.add(sb.stats(type, 0, 42, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 42, 0xEE)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 0xEF, 0xFF)); + builder.add(sb.stats(type, null, null)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 2, 1, 2, 3, 0, 2, 0, 2); + assertCorrectNullPages(columnIndex, true, false, false, true, true, false, true, false, true); + assertCorrectValues(columnIndex.getMaxValues(), null, 0, 42, null, null, 0xEE, null, 0xFF, null); + assertCorrectValues(columnIndex.getMinValues(), null, 0, 0, null, null, 42, null, 0xEF, null); + assertCorrectFiltering(columnIndex, eq(col, 2), 2); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 1, 2, 3, 4, 6, 8); + assertCorrectFiltering(columnIndex, notEq(col, 2), 0, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 2, 5, 7); + assertCorrectFiltering(columnIndex, gt(col, 0xEE), 7); + assertCorrectFiltering(columnIndex, gtEq(col, 0xEE), 5, 7); + assertCorrectFiltering(columnIndex, lt(col, 42), 1, 2); + assertCorrectFiltering(columnIndex, ltEq(col, 42), 1, 2, 5); + assertCorrectFiltering(columnIndex, userDefined(col, IntegerIsDivisableWith3.class), 1, 2, 5, 7); + assertCorrectFiltering(columnIndex, invert(userDefined(col, IntegerIsDivisableWith3.class)), 0, 1, 2, 3, 4, 5, 6, 7, + 8); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null, null, null, null)); + builder.add(sb.stats(type, 0xFF, 0xFF)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 0xEF, 0xEA, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 0xEE, 42)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 41, 0)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 5, 0, 3, 1, 2, 0, 2, 2, 0); + assertCorrectNullPages(columnIndex, true, false, true, false, true, false, true, true, false); + assertCorrectValues(columnIndex.getMaxValues(), null, 0xFF, null, 0xEF, null, 0xEE, null, null, 41); + assertCorrectValues(columnIndex.getMinValues(), null, 0xFF, null, 0xEA, null, 42, null, null, 0); + assertCorrectFiltering(columnIndex, eq(col, 0xAB), 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 2, 3, 4, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, 0xFF), 0, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 3, 5, 8); + assertCorrectFiltering(columnIndex, gt(col, 0xFF)); + assertCorrectFiltering(columnIndex, gtEq(col, 0xFF), 1); + assertCorrectFiltering(columnIndex, lt(col, 42), 8); + assertCorrectFiltering(columnIndex, ltEq(col, 42), 5, 8); + assertCorrectFiltering(columnIndex, userDefined(col, IntegerIsDivisableWith3.class), 1, 3, 5, 8); + assertCorrectFiltering(columnIndex, invert(userDefined(col, IntegerIsDivisableWith3.class)), 0, 2, 3, 4, 5, 6, 7, + 8); + } + + @Test + public void testBuildInt64() + { + PrimitiveType type = Types.required(INT64).named("test_int64"); + ColumnIndexBuilder builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + //assertThat(builder, instanceOf(LongColumnIndexBuilder.class)); + assertNull(builder.build()); + Operators.LongColumn col = longColumn("test_col"); + + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(type, -4L, 10L)); + builder.add(sb.stats(type, -11L, 7L, null)); + builder.add(sb.stats(type, 2L, 2L, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 1L, 2L)); + builder.add(sb.stats(type, -21L, 8L)); + assertEquals(6, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + ColumnIndex columnIndex = builder.build(); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 0L, 1L, 2L, 3L, 0L, 0L); + assertCorrectNullPages(columnIndex, false, false, false, true, false, false); + assertCorrectValues(columnIndex.getMaxValues(), 10L, 7L, 2L, null, 2L, 8L); + assertCorrectValues(columnIndex.getMinValues(), -4L, -11L, 2L, null, 1L, -21L); + assertCorrectFiltering(columnIndex, eq(col, 0L), 0, 1, 5); + assertCorrectFiltering(columnIndex, eq(col, null), 1, 2, 3); + assertCorrectFiltering(columnIndex, notEq(col, 0L), 0, 1, 2, 3, 4, 5); + assertCorrectFiltering(columnIndex, notEq(col, null), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, gt(col, 2L), 0, 1, 5); + assertCorrectFiltering(columnIndex, gtEq(col, 2L), 0, 1, 2, 4, 5); + assertCorrectFiltering(columnIndex, lt(col, -21L)); + assertCorrectFiltering(columnIndex, ltEq(col, -21L), 5); + assertCorrectFiltering(columnIndex, userDefined(col, LongIsDivisableWith3.class), 0, 1, 5); + assertCorrectFiltering(columnIndex, invert(userDefined(col, LongIsDivisableWith3.class)), 0, 1, 2, 3, 4, 5); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, -532L, -345L, null, null)); + builder.add(sb.stats(type, -234L, -42L, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, -42L, 2L)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, -3L, 42L)); + builder.add(sb.stats(type, null, null)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.ASCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 2, 2, 1, 2, 3, 0, 2, 0, 2); + assertCorrectNullPages(columnIndex, true, false, false, true, true, false, true, false, true); + assertCorrectValues(columnIndex.getMaxValues(), null, -345L, -42L, null, null, 2L, null, 42L, null); + assertCorrectValues(columnIndex.getMinValues(), null, -532L, -234L, null, null, -42L, null, -3L, null); + assertCorrectFiltering(columnIndex, eq(col, -42L), 2, 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 1, 2, 3, 4, 6, 8); + assertCorrectFiltering(columnIndex, notEq(col, -42L), 0, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 2, 5, 7); + assertCorrectFiltering(columnIndex, gt(col, 2L), 7); + assertCorrectFiltering(columnIndex, gtEq(col, 2L), 5, 7); + assertCorrectFiltering(columnIndex, lt(col, -42L), 1, 2); + assertCorrectFiltering(columnIndex, ltEq(col, -42L), 1, 2, 5); + assertCorrectFiltering(columnIndex, userDefined(col, LongIsDivisableWith3.class), 1, 2, 5, 7); + assertCorrectFiltering(columnIndex, invert(userDefined(col, LongIsDivisableWith3.class)), 0, 1, 2, 3, 4, 5, 6, 7, + 8); + + builder = ColumnIndexBuilder.getBuilder(type, Integer.MAX_VALUE); + sb = new StatsBuilder(); + builder.add(sb.stats(type, null, null, null, null, null)); + builder.add(sb.stats(type, 532L, 345L)); + builder.add(sb.stats(type, null, null, null)); + builder.add(sb.stats(type, 234L, 42L, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, 42L, -2L)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, null, null)); + builder.add(sb.stats(type, -3L, -42L)); + assertEquals(9, builder.getPageCount()); + assertEquals(sb.getMinMaxSize(), builder.getMinMaxSize()); + columnIndex = builder.build(); + assertEquals(BoundaryOrder.DESCENDING, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 5, 0, 3, 1, 2, 0, 2, 2, 0); + assertCorrectNullPages(columnIndex, true, false, true, false, true, false, true, true, false); + assertCorrectValues(columnIndex.getMaxValues(), null, 532L, null, 234L, null, 42L, null, null, -3L); + assertCorrectValues(columnIndex.getMinValues(), null, 345L, null, 42L, null, -2L, null, null, -42L); + assertCorrectFiltering(columnIndex, eq(col, 0L), 5); + assertCorrectFiltering(columnIndex, eq(col, null), 0, 2, 3, 4, 6, 7); + assertCorrectFiltering(columnIndex, notEq(col, 0L), 0, 1, 2, 3, 4, 5, 6, 7, 8); + assertCorrectFiltering(columnIndex, notEq(col, null), 1, 3, 5, 8); + assertCorrectFiltering(columnIndex, gt(col, 2L), 1, 3, 5); + assertCorrectFiltering(columnIndex, gtEq(col, 2L), 1, 3, 5); + assertCorrectFiltering(columnIndex, lt(col, -42L)); + assertCorrectFiltering(columnIndex, ltEq(col, -42L), 8); + assertCorrectFiltering(columnIndex, userDefined(col, LongIsDivisableWith3.class), 1, 3, 5, 8); + assertCorrectFiltering(columnIndex, invert(userDefined(col, LongIsDivisableWith3.class)), 0, 1, 2, 3, 4, 5, 6, 7, + 8); + } + + @Test + public void testStaticBuildInt64() + { + ColumnIndex columnIndex = ColumnIndexBuilder.build( + Types.required(INT64).named("test_int64"), + BoundaryOrder.UNORDERED, + asList(true, false, true, false, true, false), + asList(1L, 2L, 3L, 4L, 5L, 6L), + toBBList(null, 2L, null, 4L, null, 9L), + toBBList(null, 3L, null, 15L, null, 10L)); + assertEquals(BoundaryOrder.UNORDERED, columnIndex.getBoundaryOrder()); + assertCorrectNullCounts(columnIndex, 1, 2, 3, 4, 5, 6); + assertCorrectNullPages(columnIndex, true, false, true, false, true, false); + assertCorrectValues(columnIndex.getMaxValues(), null, 3L, null, 15L, null, 10L); + assertCorrectValues(columnIndex.getMinValues(), null, 2L, null, 4L, null, 9L); + } + + @Test + public void testNoOpBuilder() + { + ColumnIndexBuilder builder = ColumnIndexBuilder.getNoOpBuilder(); + StatsBuilder sb = new StatsBuilder(); + builder.add(sb.stats(Types.required(BINARY).as(UTF8).named("test_binary_utf8"), stringBinary("Jeltz"), + stringBinary("Slartibartfast"), null, null)); + builder.add(sb.stats(Types.required(BOOLEAN).named("test_boolean"), true, true, null, null)); + builder.add(sb.stats(Types.required(DOUBLE).named("test_double"), null, null, null)); + builder.add(sb.stats(Types.required(INT32).named("test_int32"), null, null)); + builder.add(sb.stats(Types.required(INT64).named("test_int64"), -234L, -42L, null)); + assertEquals(0, builder.getPageCount()); + assertEquals(0, builder.getMinMaxSize()); + assertNull(builder.build()); + } + + private static List toBBList(Binary... values) + { + List buffers = new ArrayList<>(values.length); + for (Binary value : values) { + if (value == null) { + buffers.add(ByteBuffer.allocate(0)); + } + else { + buffers.add(value.toByteBuffer()); + } + } + return buffers; + } + + private static List toBBList(Boolean... values) + { + List buffers = new ArrayList<>(values.length); + for (Boolean value : values) { + if (value == null) { + buffers.add(ByteBuffer.allocate(0)); + } + else { + buffers.add(ByteBuffer.wrap(BytesUtils.booleanToBytes(value))); + } + } + return buffers; + } + + private static List toBBList(Double... values) + { + List buffers = new ArrayList<>(values.length); + for (Double value : values) { + if (value == null) { + buffers.add(ByteBuffer.allocate(0)); + } + else { + buffers.add(ByteBuffer.wrap(BytesUtils.longToBytes(Double.doubleToLongBits(value)))); + } + } + return buffers; + } + + private static List toBBList(Float... values) + { + List buffers = new ArrayList<>(values.length); + for (Float value : values) { + if (value == null) { + buffers.add(ByteBuffer.allocate(0)); + } + else { + buffers.add(ByteBuffer.wrap(BytesUtils.intToBytes(Float.floatToIntBits(value)))); + } + } + return buffers; + } + + private static List toBBList(Integer... values) + { + List buffers = new ArrayList<>(values.length); + for (Integer value : values) { + if (value == null) { + buffers.add(ByteBuffer.allocate(0)); + } + else { + buffers.add(ByteBuffer.wrap(BytesUtils.intToBytes(value))); + } + } + return buffers; + } + + private static List toBBList(Long... values) + { + List buffers = new ArrayList<>(values.length); + for (Long value : values) { + if (value == null) { + buffers.add(ByteBuffer.allocate(0)); + } + else { + buffers.add(ByteBuffer.wrap(BytesUtils.longToBytes(value))); + } + } + return buffers; + } + + private static Binary decimalBinary(String num) + { + return Binary.fromConstantByteArray(new BigDecimal(num).unscaledValue().toByteArray()); + } + + private static Binary stringBinary(String str) + { + return Binary.fromString(str); + } + + private static void assertCorrectValues(List values, Binary... expectedValues) + { + assertEquals(expectedValues.length, values.size()); + for (int i = 0; i < expectedValues.length; ++i) { + Binary expectedValue = expectedValues[i]; + ByteBuffer value = values.get(i); + if (expectedValue == null) { + assertFalse(value.hasRemaining(), "The byte buffer should be empty for null pages"); + } + else { + assertArrayEquals("Invalid value for page " + i, expectedValue.getBytesUnsafe(), value.array()); + } + } + } + + private static void assertCorrectValues(List values, Boolean... expectedValues) + { + assertEquals(expectedValues.length, values.size()); + for (int i = 0; i < expectedValues.length; ++i) { + Boolean expectedValue = expectedValues[i]; + ByteBuffer value = values.get(i); + if (expectedValue == null) { + assertFalse(value.hasRemaining(), "The byte buffer should be empty for null pages"); + } + else { + assertEquals(1, value.remaining(), "The byte buffer should be 1 byte long for boolean"); + assertEquals(expectedValue.booleanValue(), value.get(0) != 0, "Invalid value for page " + i); + } + } + } + + private static void assertCorrectValues(List values, Double... expectedValues) + { + assertEquals(expectedValues.length, values.size()); + for (int i = 0; i < expectedValues.length; ++i) { + Double expectedValue = expectedValues[i]; + ByteBuffer value = values.get(i); + if (expectedValue == null) { + assertFalse(value.hasRemaining(), "The byte buffer should be empty for null pages"); + } + else { + assertEquals(8, value.remaining(), "The byte buffer should be 8 bytes long for double"); + assertTrue(Double.compare(expectedValue.doubleValue(), value.getDouble(0)) == 0, "Invalid value for page " + i); + } + } + } + + private static void assertCorrectValues(List values, Float... expectedValues) + { + assertEquals(expectedValues.length, values.size()); + for (int i = 0; i < expectedValues.length; ++i) { + Float expectedValue = expectedValues[i]; + ByteBuffer value = values.get(i); + if (expectedValue == null) { + assertFalse(value.hasRemaining(), "The byte buffer should be empty for null pages"); + } + else { + assertEquals(4, value.remaining(), "The byte buffer should be 4 bytes long for double"); + assertTrue(Float.compare(expectedValue.floatValue(), value.getFloat(0)) == 0, "Invalid value for page " + i); + } + } + } + + private static void assertCorrectValues(List values, Integer... expectedValues) + { + assertEquals(expectedValues.length, values.size()); + for (int i = 0; i < expectedValues.length; ++i) { + Integer expectedValue = expectedValues[i]; + ByteBuffer value = values.get(i); + if (expectedValue == null) { + assertFalse(value.hasRemaining(), "The byte buffer should be empty for null pages"); + } + else { + assertEquals(4, value.remaining(), "The byte buffer should be 4 bytes long for int32"); + assertEquals(expectedValue.intValue(), value.getInt(0), "Invalid value for page " + i); + } + } + } + + private static void assertCorrectValues(List values, Long... expectedValues) + { + assertEquals(expectedValues.length, values.size()); + for (int i = 0; i < expectedValues.length; ++i) { + Long expectedValue = expectedValues[i]; + ByteBuffer value = values.get(i); + if (expectedValue == null) { + assertFalse(value.hasRemaining(), "The byte buffer should be empty for null pages"); + } + else { + assertEquals(8, value.remaining(), "The byte buffer should be 8 bytes long for int64"); + assertEquals(expectedValue.intValue(), value.getLong(0), "Invalid value for page " + i); + } + } + } + + private static void assertCorrectNullCounts(ColumnIndex columnIndex, long... expectedNullCounts) + { + List nullCounts = columnIndex.getNullCounts(); + assertEquals(expectedNullCounts.length, nullCounts.size()); + for (int i = 0; i < expectedNullCounts.length; ++i) { + assertEquals(expectedNullCounts[i], nullCounts.get(i).longValue(), "Invalid null count at page " + i); + } + } + + private static void assertCorrectNullPages(ColumnIndex columnIndex, boolean... expectedNullPages) + { + List nullPages = columnIndex.getNullPages(); + assertEquals(expectedNullPages.length, nullPages.size()); + for (int i = 0; i < expectedNullPages.length; ++i) { + assertEquals(expectedNullPages[i], nullPages.get(i).booleanValue(), "Invalid null pages at page " + i); + } + } + + private static class StatsBuilder + { + private long minMaxSize; + + Statistics stats(PrimitiveType type, Object... values) + { + Statistics stats = Statistics.createStats(type); + for (Object value : values) { + if (value == null) { + stats.incrementNumNulls(); + continue; + } + switch (type.getPrimitiveTypeName()) { + case BINARY: + case FIXED_LEN_BYTE_ARRAY: + case INT96: + stats.updateStats((Binary) value); + break; + case BOOLEAN: + stats.updateStats((boolean) value); + break; + case DOUBLE: + stats.updateStats((double) value); + break; + case FLOAT: + stats.updateStats((float) value); + break; + case INT32: + stats.updateStats((int) value); + break; + case INT64: + stats.updateStats((long) value); + break; + default: + fail("Unsupported value type for stats: " + value.getClass()); + } + } + if (stats.hasNonNullValue()) { + minMaxSize += stats.getMinBytes().length; + minMaxSize += stats.getMaxBytes().length; + } + return stats; + } + + long getMinMaxSize() + { + return minMaxSize; + } + } + + private static void assertCorrectFiltering(ColumnIndex ci, FilterPredicate predicate, int... expectedIndexes) + { + checkEquals(predicate.accept(ci), expectedIndexes); + } + + static void checkEquals(PrimitiveIterator.OfInt actualIt, int... expectedValues) + { + IntList actualList = new IntArrayList(); + actualIt.forEachRemaining((int value) -> actualList.add(value)); + int[] actualValues = actualList.toIntArray(); + assertArrayEquals("ExpectedValues: " + Arrays.toString(expectedValues) + " ActualValues: " + Arrays.toString(actualValues), + expectedValues, actualValues); + } +} diff --git a/presto-parquet/src/test/java/com/facebook/presto/parquet/reader/TestColumnIndexFilter.java b/presto-parquet/src/test/java/com/facebook/presto/parquet/reader/TestColumnIndexFilter.java new file mode 100644 index 0000000000000..63522ac6632e2 --- /dev/null +++ b/presto-parquet/src/test/java/com/facebook/presto/parquet/reader/TestColumnIndexFilter.java @@ -0,0 +1,510 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.parquet.reader; + +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongList; +import org.apache.parquet.bytes.BytesUtils; +import org.apache.parquet.filter2.compat.FilterCompat; +import org.apache.parquet.filter2.predicate.Statistics; +import org.apache.parquet.filter2.predicate.UserDefinedPredicate; +import org.apache.parquet.hadoop.metadata.ColumnPath; +import org.apache.parquet.internal.column.columnindex.BoundaryOrder; +import org.apache.parquet.internal.column.columnindex.ColumnIndex; +import org.apache.parquet.internal.column.columnindex.ColumnIndexBuilder; +import org.apache.parquet.internal.column.columnindex.OffsetIndex; +import org.apache.parquet.internal.column.columnindex.OffsetIndexBuilder; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexFilter; +import org.apache.parquet.internal.filter2.columnindex.ColumnIndexStore; +import org.apache.parquet.internal.filter2.columnindex.RowRanges; +import org.apache.parquet.schema.PrimitiveType; +import org.testng.annotations.Test; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.LongStream; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.parquet.filter2.predicate.FilterApi.and; +import static org.apache.parquet.filter2.predicate.FilterApi.binaryColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.booleanColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.doubleColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.eq; +import static org.apache.parquet.filter2.predicate.FilterApi.gt; +import static org.apache.parquet.filter2.predicate.FilterApi.gtEq; +import static org.apache.parquet.filter2.predicate.FilterApi.intColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.longColumn; +import static org.apache.parquet.filter2.predicate.FilterApi.lt; +import static org.apache.parquet.filter2.predicate.FilterApi.ltEq; +import static org.apache.parquet.filter2.predicate.FilterApi.notEq; +import static org.apache.parquet.filter2.predicate.FilterApi.or; +import static org.apache.parquet.filter2.predicate.FilterApi.userDefined; +import static org.apache.parquet.filter2.predicate.LogicalInverter.invert; +import static org.apache.parquet.internal.column.columnindex.BoundaryOrder.ASCENDING; +import static org.apache.parquet.internal.column.columnindex.BoundaryOrder.DESCENDING; +import static org.apache.parquet.internal.column.columnindex.BoundaryOrder.UNORDERED; +import static org.apache.parquet.internal.filter2.columnindex.ColumnIndexFilter.calculateRowRanges; +import static org.apache.parquet.io.api.Binary.fromString; +import static org.apache.parquet.schema.LogicalTypeAnnotation.stringType; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.BINARY; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.DOUBLE; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT32; +import static org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT64; +import static org.apache.parquet.schema.Types.optional; +import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; + +/** + * Unit tests of {@link ColumnIndexFilter} + */ +public class TestColumnIndexFilter +{ + private static class CIBuilder + { + private static final ByteBuffer EMPTY = ByteBuffer.wrap(new byte[0]); + private final PrimitiveType type; + private final BoundaryOrder order; + private List nullPages = new ArrayList<>(); + private List nullCounts = new ArrayList<>(); + private List minValues = new ArrayList<>(); + private List maxValues = new ArrayList<>(); + + CIBuilder(PrimitiveType type, BoundaryOrder order) + { + this.type = type; + this.order = order; + } + + CIBuilder addNullPage(long nullCount) + { + nullPages.add(true); + nullCounts.add(nullCount); + minValues.add(EMPTY); + maxValues.add(EMPTY); + return this; + } + + CIBuilder addPage(long nullCount, int min, int max) + { + nullPages.add(false); + nullCounts.add(nullCount); + minValues.add(ByteBuffer.wrap(BytesUtils.intToBytes(min))); + maxValues.add(ByteBuffer.wrap(BytesUtils.intToBytes(max))); + return this; + } + + CIBuilder addPage(long nullCount, String min, String max) + { + nullPages.add(false); + nullCounts.add(nullCount); + minValues.add(ByteBuffer.wrap(min.getBytes(UTF_8))); + maxValues.add(ByteBuffer.wrap(max.getBytes(UTF_8))); + return this; + } + + CIBuilder addPage(long nullCount, double min, double max) + { + nullPages.add(false); + nullCounts.add(nullCount); + minValues.add(ByteBuffer.wrap(BytesUtils.longToBytes(Double.doubleToLongBits(min)))); + maxValues.add(ByteBuffer.wrap(BytesUtils.longToBytes(Double.doubleToLongBits(max)))); + return this; + } + + ColumnIndex build() + { + return ColumnIndexBuilder.build(type, order, nullPages, nullCounts, minValues, maxValues); + } + } + + private static class OIBuilder + { + private final OffsetIndexBuilder builder = OffsetIndexBuilder.getBuilder(); + + OIBuilder addPage(long rowCount) + { + builder.add(1234, rowCount); + return this; + } + + OffsetIndex build() + { + return builder.build(); + } + } + + public static class AnyInt + extends UserDefinedPredicate + { + @Override + public boolean keep(Integer value) + { + return true; + } + + @Override + public boolean canDrop(Statistics statistics) + { + return false; + } + + @Override + public boolean inverseCanDrop(Statistics statistics) + { + return true; + } + } + + /** + *
+     * row     column1        column2        column3        column4        column5
+     *                                                 (no column index)
+     *      ------0------  ------0------  ------0------  ------0------  ------0------
+     * 0.   1              Zulu           2.03                          null
+     *      ------1------  ------1------  ------1------  ------1------  ------1------
+     * 1.   2              Yankee         4.67                          null
+     * 2.   3              Xray           3.42                          null
+     * 3.   4              Whiskey        8.71                          null
+     *                     ------2------                 ------2------
+     * 4.   5              Victor         0.56                          null
+     * 5.   6              Uniform        4.30                          null
+     *                                    ------2------  ------3------
+     * 6.   null           null           null                          null
+     *      ------2------                                ------4------
+     * 7.   7              Tango          3.50                          null
+     *                     ------3------
+     * 8.   7              null           3.14                          null
+     *      ------3------
+     * 9.   7              null           null                          null
+     *                                    ------3------
+     * 10.  null           null           9.99                          null
+     *                     ------4------
+     * 11.  8              Sierra         8.78                          null
+     *                                                   ------5------
+     * 12.  9              Romeo          9.56                          null
+     * 13.  10             Quebec         2.71                          null
+     *      ------4------
+     * 14.  11             Papa           5.71                          null
+     * 15.  12             Oscar          4.09                          null
+     *                     ------5------  ------4------  ------6------
+     * 16.  13             November       null                          null
+     * 17.  14             Mike           null                          null
+     * 18.  15             Lima           0.36                          null
+     * 19.  16             Kilo           2.94                          null
+     * 20.  17             Juliett        4.23                          null
+     *      ------5------  ------6------                 ------7------
+     * 21.  18             India          null                          null
+     * 22.  19             Hotel          5.32                          null
+     *                                    ------5------
+     * 23.  20             Golf           4.17                          null
+     * 24.  21             Foxtrot        7.92                          null
+     * 25.  22             Echo           7.95                          null
+     *                                   ------6------
+     * 26.  23             Delta          null                          null
+     *      ------6------
+     * 27.  24             Charlie        null                          null
+     *                                                   ------8------
+     * 28.  25             Bravo          null                          null
+     *                     ------7------
+     * 29.  26             Alfa           null                          null
+     * 
+ */ + private static final long TOTAL_ROW_COUNT = 30; + private static final ColumnIndex COLUMN1_CI = new CIBuilder(optional(INT32).named("column1"), ASCENDING) + .addPage(0, 1, 1) + .addPage(1, 2, 6) + .addPage(0, 7, 7) + .addPage(1, 7, 10) + .addPage(0, 11, 17) + .addPage(0, 18, 23) + .addPage(0, 24, 26) + .build(); + private static final OffsetIndex COLUMN1_OI = new OIBuilder() + .addPage(1) + .addPage(6) + .addPage(2) + .addPage(5) + .addPage(7) + .addPage(6) + .addPage(3) + .build(); + private static final ColumnIndex COLUMN2_CI = new CIBuilder(optional(BINARY).as(stringType()).named("column2"), DESCENDING) + .addPage(0, "Zulu", "Zulu") + .addPage(0, "Whiskey", "Yankee") + .addPage(1, "Tango", "Victor") + .addNullPage(3) + .addPage(0, "Oscar", "Sierra") + .addPage(0, "Juliett", "November") + .addPage(0, "Bravo", "India") + .addPage(0, "Alfa", "Alfa") + .build(); + private static final OffsetIndex COLUMN2_OI = new OIBuilder() + .addPage(1) + .addPage(3) + .addPage(4) + .addPage(3) + .addPage(5) + .addPage(5) + .addPage(8) + .addPage(1) + .build(); + private static final ColumnIndex COLUMN3_CI = new CIBuilder(optional(DOUBLE).named("column3"), UNORDERED) + .addPage(0, 2.03, 2.03) + .addPage(0, 0.56, 8.71) + .addPage(2, 3.14, 3.50) + .addPage(0, 2.71, 9.99) + .addPage(3, 0.36, 5.32) + .addPage(0, 4.17, 7.95) + .addNullPage(4) + .build(); + private static final OffsetIndex COLUMN3_OI = new OIBuilder() + .addPage(1) + .addPage(5) + .addPage(4) + .addPage(6) + .addPage(7) + .addPage(3) + .addPage(4) + .build(); + private static final ColumnIndex COLUMN4_CI = null; + private static final OffsetIndex COLUMN4_OI = new OIBuilder() + .addPage(1) + .addPage(3) + .addPage(2) + .addPage(1) + .addPage(5) + .addPage(4) + .addPage(5) + .addPage(7) + .addPage(2) + .build(); + private static final ColumnIndex COLUMN5_CI = new CIBuilder(optional(INT64).named("column5"), ASCENDING) + .addNullPage(1) + .addNullPage(29) + .build(); + private static final OffsetIndex COLUMN5_OI = new OIBuilder() + .addPage(1) + .addPage(29) + .build(); + private static final ColumnIndexStore STORE = new ColumnIndexStore() + { + @Override + public ColumnIndex getColumnIndex(ColumnPath column) + { + switch (column.toDotString()) { + case "column1": + return COLUMN1_CI; + case "column2": + return COLUMN2_CI; + case "column3": + return COLUMN3_CI; + case "column4": + return COLUMN4_CI; + case "column5": + return COLUMN5_CI; + default: + return null; + } + } + + @Override + public OffsetIndex getOffsetIndex(ColumnPath column) + { + switch (column.toDotString()) { + case "column1": + return COLUMN1_OI; + case "column2": + return COLUMN2_OI; + case "column3": + return COLUMN3_OI; + case "column4": + return COLUMN4_OI; + case "column5": + return COLUMN5_OI; + default: + throw new MissingOffsetIndexException(column); + } + } + }; + + private static Set paths(String... columns) + { + Set paths = new HashSet<>(); + for (String column : columns) { + paths.add(ColumnPath.fromDotString(column)); + } + return paths; + } + + private static void assertAllRows(RowRanges ranges, long rowCount) + { + LongList actualList = new LongArrayList(); + ranges.iterator().forEachRemaining((long value) -> actualList.add(value)); + LongList expectedList = new LongArrayList(); + LongStream.range(0, rowCount).forEach(expectedList::add); + assertArrayEquals(expectedList + " != " + actualList, expectedList.toLongArray(), actualList.toLongArray()); + } + + private static void assertRows(RowRanges ranges, long... expectedRows) + { + LongList actualList = new LongArrayList(); + ranges.iterator().forEachRemaining((long value) -> actualList.add(value)); + assertArrayEquals(Arrays.toString(expectedRows) + " != " + actualList, expectedRows, actualList.toLongArray()); + } + + @Test + public void testFiltering() + { + Set paths = paths("column1", "column2", "column3", "column4"); + + assertAllRows( + calculateRowRanges(FilterCompat.get( + userDefined(intColumn("column1"), AnyInt.class)), STORE, paths, TOTAL_ROW_COUNT), + TOTAL_ROW_COUNT); + assertRows(calculateRowRanges(FilterCompat.get( + and( + and( + eq(intColumn("column1"), null), + eq(binaryColumn("column2"), null)), + and( + eq(doubleColumn("column3"), null), + eq(booleanColumn("column4"), null)))), + STORE, paths, TOTAL_ROW_COUNT), + 6, 9); + assertRows(calculateRowRanges(FilterCompat.get( + and( + and( + notEq(intColumn("column1"), null), + notEq(binaryColumn("column2"), null)), + and( + notEq(doubleColumn("column3"), null), + notEq(booleanColumn("column4"), null)))), + STORE, paths, TOTAL_ROW_COUNT), + 0, 1, 2, 3, 4, 5, 6, 7, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25); + assertRows(calculateRowRanges(FilterCompat.get( + or( + and( + lt(intColumn("column1"), 20), + gtEq(binaryColumn("column2"), fromString("Quebec"))), + and( + gt(doubleColumn("column3"), 5.32), + ltEq(binaryColumn("column4"), fromString("XYZ"))))), + STORE, paths, TOTAL_ROW_COUNT), + 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 23, 24, 25); + assertRows(calculateRowRanges(FilterCompat.get( + and( + and( + gtEq(intColumn("column1"), 7), + gt(binaryColumn("column2"), fromString("India"))), + and( + eq(doubleColumn("column3"), null), + notEq(binaryColumn("column4"), null)))), + STORE, paths, TOTAL_ROW_COUNT), + 7, 16, 17, 18, 19, 20); + assertRows(calculateRowRanges(FilterCompat.get( + and( + or( + invert(userDefined(intColumn("column1"), AnyInt.class)), + eq(binaryColumn("column2"), fromString("Echo"))), + eq(doubleColumn("column3"), 6.0))), + STORE, paths, TOTAL_ROW_COUNT), + 23, 24, 25); + assertRows(calculateRowRanges(FilterCompat.get( + and( + and( + gtEq(intColumn("column1"), 7), + lt(intColumn("column1"), 11)), + and( + gt(binaryColumn("column2"), fromString("Romeo")), + ltEq(binaryColumn("column2"), fromString("Tango"))))), + STORE, paths, TOTAL_ROW_COUNT), + 7, 11, 12, 13); + } + + @Test + public void testFilteringOnMissingColumns() + { + Set paths = paths("column1", "column2", "column3", "column4"); + + // Missing column filter is always true + assertAllRows(calculateRowRanges(FilterCompat.get( + notEq(intColumn("missing_column"), 0)), + STORE, paths, TOTAL_ROW_COUNT), + TOTAL_ROW_COUNT); + assertRows(calculateRowRanges(FilterCompat.get( + and( + and( + gtEq(intColumn("column1"), 7), + lt(intColumn("column1"), 11)), + eq(binaryColumn("missing_column"), null))), + STORE, paths, TOTAL_ROW_COUNT), + 7, 8, 9, 10, 11, 12, 13); + + // Missing column filter is always false + assertRows(calculateRowRanges(FilterCompat.get( + or( + and( + gtEq(intColumn("column1"), 7), + lt(intColumn("column1"), 11)), + notEq(binaryColumn("missing_column"), null))), + STORE, paths, TOTAL_ROW_COUNT), + 7, 8, 9, 10, 11, 12, 13); + assertRows(calculateRowRanges(FilterCompat.get( + gt(intColumn("missing_column"), 0)), + STORE, paths, TOTAL_ROW_COUNT)); + } + + @Test + public void testFilteringWithMissingOffsetIndex() + { + Set paths = paths("column1", "column2", "column3", "column4", "column_wo_oi"); + + assertAllRows(calculateRowRanges(FilterCompat.get( + and( + and( + gtEq(intColumn("column1"), 7), + lt(intColumn("column1"), 11)), + and( + gt(binaryColumn("column2"), fromString("Romeo")), + ltEq(binaryColumn("column_wo_oi"), fromString("Tango"))))), + STORE, paths, TOTAL_ROW_COUNT), + TOTAL_ROW_COUNT); + } + + @Test + public void testFilteringWithAllNullPages() + { + Set paths = paths("column1", "column5"); + + assertAllRows(calculateRowRanges(FilterCompat.get( + notEq(longColumn("column5"), 1234567L)), + STORE, paths, TOTAL_ROW_COUNT), + TOTAL_ROW_COUNT); + assertAllRows(calculateRowRanges(FilterCompat.get( + or(gtEq(intColumn("column1"), 10), + notEq(longColumn("column5"), 1234567L))), + STORE, paths, TOTAL_ROW_COUNT), + TOTAL_ROW_COUNT); + assertRows(calculateRowRanges(FilterCompat.get( + eq(longColumn("column5"), 1234567L)), + STORE, paths, TOTAL_ROW_COUNT)); + assertRows(calculateRowRanges(FilterCompat.get( + and(lt(intColumn("column1"), 20), + gtEq(longColumn("column5"), 1234567L))), + STORE, paths, TOTAL_ROW_COUNT)); + } +} diff --git a/presto-parser/pom.xml b/presto-parser/pom.xml index b416f9689a033..060b736c565be 100644 --- a/presto-parser/pom.xml +++ b/presto-parser/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-parser diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java b/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java index d677404ba132a..406cafc7e19a1 100644 --- a/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java +++ b/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java @@ -123,7 +123,6 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; -import java.util.regex.Pattern; import java.util.stream.Collectors; import static com.facebook.presto.sql.ExpressionFormatter.formatExpression; @@ -138,7 +137,6 @@ public final class SqlFormatter { private static final String INDENT = " "; - private static final Pattern NAME_PATTERN = Pattern.compile("[a-z_][a-z0-9_]*"); private SqlFormatter() {} @@ -1079,12 +1077,10 @@ private String formatRoutineCharacteristicName(Enum characteristic) return characteristic.name().replace("_", " "); } - private static String formatName(String name) + private static String formatName(Identifier name) { - if (NAME_PATTERN.matcher(name).matches()) { - return name; - } - return "\"" + name.replace("\"", "\"\"") + "\""; + String delimiter = name.isDelimited() ? "\"" : ""; + return delimiter + name.getValue().replace("\"", "\"\"") + delimiter; } private static String formatName(QualifiedName name) diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java b/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java index e7d51af5a1604..e160e712dc690 100644 --- a/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java +++ b/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java @@ -2116,11 +2116,7 @@ private static LikeClause.PropertiesOption getPropertiesOption(Token token) private QualifiedName getQualifiedName(SqlBaseParser.QualifiedNameContext context) { - List parts = visit(context.identifier(), Identifier.class).stream() - .map(Identifier::getValue) // TODO: preserve quotedness - .collect(Collectors.toList()); - - return QualifiedName.of(parts); + return QualifiedName.of(visit(context.identifier(), Identifier.class)); } private static boolean isDistinct(SqlBaseParser.SetQuantifierContext setQuantifier) diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/tree/DereferenceExpression.java b/presto-parser/src/main/java/com/facebook/presto/sql/tree/DereferenceExpression.java index 351113137d229..ae9ec314dfb5a 100644 --- a/presto-parser/src/main/java/com/facebook/presto/sql/tree/DereferenceExpression.java +++ b/presto-parser/src/main/java/com/facebook/presto/sql/tree/DereferenceExpression.java @@ -15,9 +15,7 @@ import com.google.common.collect.ImmutableList; -import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.Objects; import java.util.Optional; @@ -76,7 +74,20 @@ public Identifier getField() */ public static QualifiedName getQualifiedName(DereferenceExpression expression) { - List parts = tryParseParts(expression.base, expression.field.getValue().toLowerCase(Locale.ENGLISH)); + List parts = null; + if (expression.base instanceof Identifier) { + parts = ImmutableList.of((Identifier) expression.base, expression.field); + } + else if (expression.base instanceof DereferenceExpression) { + QualifiedName baseQualifiedName = getQualifiedName((DereferenceExpression) expression.base); + if (baseQualifiedName != null) { + ImmutableList.Builder builder = ImmutableList.builder(); + builder.addAll(baseQualifiedName.getOriginalParts()); + builder.add(expression.field); + parts = builder.build(); + } + } + return parts == null ? null : QualifiedName.of(parts); } @@ -96,22 +107,6 @@ public static Expression from(QualifiedName name) return result; } - private static List tryParseParts(Expression base, String fieldName) - { - if (base instanceof Identifier) { - return ImmutableList.of(((Identifier) base).getValue(), fieldName); - } - else if (base instanceof DereferenceExpression) { - QualifiedName baseQualifiedName = getQualifiedName((DereferenceExpression) base); - if (baseQualifiedName != null) { - List newList = new ArrayList<>(baseQualifiedName.getParts()); - newList.add(fieldName); - return newList; - } - } - return null; - } - @Override public boolean equals(Object o) { diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/tree/Identifier.java b/presto-parser/src/main/java/com/facebook/presto/sql/tree/Identifier.java index 022daa1870994..f6a52f4a4431b 100644 --- a/presto-parser/src/main/java/com/facebook/presto/sql/tree/Identifier.java +++ b/presto-parser/src/main/java/com/facebook/presto/sql/tree/Identifier.java @@ -25,7 +25,7 @@ public class Identifier extends Expression { - private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z_]([a-zA-Z0-9_:@])*"); + private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z_]([a-zA-Z0-9_])*"); private final String value; private final boolean delimited; diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/tree/QualifiedName.java b/presto-parser/src/main/java/com/facebook/presto/sql/tree/QualifiedName.java index 1a9f17a048b13..8bd65d692691f 100644 --- a/presto-parser/src/main/java/com/facebook/presto/sql/tree/QualifiedName.java +++ b/presto-parser/src/main/java/com/facebook/presto/sql/tree/QualifiedName.java @@ -20,43 +20,43 @@ import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.Iterables.isEmpty; -import static com.google.common.collect.Iterables.transform; import static java.util.Locale.ENGLISH; import static java.util.Objects.requireNonNull; public class QualifiedName { private final List parts; - private final List originalParts; + private final List originalParts; public static QualifiedName of(String first, String... rest) { requireNonNull(first, "first is null"); - return of(ImmutableList.copyOf(Lists.asList(first, rest))); + return of(ImmutableList.copyOf(Lists.asList(first, rest).stream().map(Identifier::new).collect(Collectors.toList()))); } public static QualifiedName of(String name) { requireNonNull(name, "name is null"); - return of(ImmutableList.of(name)); + return of(ImmutableList.of(new Identifier(name))); } - public static QualifiedName of(Iterable originalParts) + public static QualifiedName of(Iterable originalParts) { requireNonNull(originalParts, "originalParts is null"); checkArgument(!isEmpty(originalParts), "originalParts is empty"); - List parts = ImmutableList.copyOf(transform(originalParts, part -> part.toLowerCase(ENGLISH))); - return new QualifiedName(ImmutableList.copyOf(originalParts), parts); + return new QualifiedName(ImmutableList.copyOf(originalParts)); } - private QualifiedName(List originalParts, List parts) + private QualifiedName(List originalParts) { this.originalParts = originalParts; - this.parts = parts; + this.parts = originalParts.stream().map(identifier -> identifier.getValue().toLowerCase(ENGLISH)).collect(toImmutableList()); } public List getParts() @@ -64,7 +64,7 @@ public List getParts() return parts; } - public List getOriginalParts() + public List getOriginalParts() { return originalParts; } @@ -85,8 +85,8 @@ public Optional getPrefix() return Optional.empty(); } - List subList = parts.subList(0, parts.size() - 1); - return Optional.of(new QualifiedName(subList, subList)); + List subList = originalParts.subList(0, originalParts.size() - 1); + return Optional.of(new QualifiedName(subList)); } public boolean hasSuffix(QualifiedName suffix) diff --git a/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java b/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java index ef659818d3ed5..fe2b64ce5d7db 100644 --- a/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java +++ b/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java @@ -157,6 +157,7 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import static com.facebook.presto.sql.QueryUtil.identifier; import static com.facebook.presto.sql.QueryUtil.query; @@ -617,7 +618,7 @@ public void testPrecedenceAndAssociativity() public void testAllowIdentifierColon() { SqlParser sqlParser = new SqlParser(new SqlParserOptions().allowIdentifierSymbol(COLON)); - sqlParser.createStatement("select * from foo:bar"); + sqlParser.createStatement("select * from \"foo:bar\""); } @SuppressWarnings("deprecation") @@ -625,7 +626,7 @@ public void testAllowIdentifierColon() public void testAllowIdentifierAtSign() { SqlParser sqlParser = new SqlParser(new SqlParserOptions().allowIdentifierSymbol(AT_SIGN)); - sqlParser.createStatement("select * from foo@bar"); + sqlParser.createStatement("select * from \"foo@bar\""); } @Test @@ -2285,7 +2286,7 @@ public void testShowStats() final String[] tableNames = {"t", "s.t", "c.s.t"}; for (String fullName : tableNames) { - QualifiedName qualifiedName = QualifiedName.of(Arrays.asList(fullName.split("\\."))); + QualifiedName qualifiedName = makeQualifiedName(fullName); assertStatement(format("SHOW STATS FOR %s", qualifiedName), new ShowStats(new Table(qualifiedName))); } } @@ -2296,7 +2297,7 @@ public void testShowStatsForQuery() final String[] tableNames = {"t", "s.t", "c.s.t"}; for (String fullName : tableNames) { - QualifiedName qualifiedName = QualifiedName.of(Arrays.asList(fullName.split("\\."))); + QualifiedName qualifiedName = makeQualifiedName(fullName); assertStatement(format("SHOW STATS FOR (SELECT * FROM %s)", qualifiedName), createShowStats(qualifiedName, ImmutableList.of(new AllColumns()), Optional.empty())); assertStatement(format("SHOW STATS FOR (SELECT * FROM %s WHERE field > 0)", qualifiedName), @@ -2320,6 +2321,14 @@ public void testShowStatsForQuery() } } + private QualifiedName makeQualifiedName(String tableName) + { + List parts = Arrays.stream(tableName.split("\\.")) + .map(Identifier::new) + .collect(Collectors.toList()); + return QualifiedName.of(parts); + } + private ShowStats createShowStats(QualifiedName name, List selects, Optional where) { return new ShowStats( diff --git a/presto-password-authenticators/pom.xml b/presto-password-authenticators/pom.xml index ce9fd723ab759..aa3c5b641916e 100644 --- a/presto-password-authenticators/pom.xml +++ b/presto-password-authenticators/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-password-authenticators diff --git a/presto-pinot-toolkit/pom.xml b/presto-pinot-toolkit/pom.xml index 03489162f4cb7..539a78a92f5d7 100644 --- a/presto-pinot-toolkit/pom.xml +++ b/presto-pinot-toolkit/pom.xml @@ -6,7 +6,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-pinot-toolkit diff --git a/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/PinotSegmentPageSource.java b/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/PinotSegmentPageSource.java index e3891c99ab4a9..2a37ded486a0a 100644 --- a/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/PinotSegmentPageSource.java +++ b/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/PinotSegmentPageSource.java @@ -494,6 +494,7 @@ private Slice getSlice(int rowIndex, int columnIndex) String[] stringArray = currentDataTable.getDataTable().getStringArray(rowIndex, columnIndex); return utf8Slice(Arrays.toString(stringArray)); case STRING: + case JSON: String field = currentDataTable.getDataTable().getString(rowIndex, columnIndex); if (field == null || field.isEmpty()) { return Slices.EMPTY_SLICE; diff --git a/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotQueryGenerator.java b/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotQueryGenerator.java index a264e5596d11f..b073d01711b2c 100644 --- a/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotQueryGenerator.java +++ b/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotQueryGenerator.java @@ -16,6 +16,7 @@ import com.facebook.airlift.log.Logger; import com.facebook.presto.common.type.BigintType; import com.facebook.presto.common.type.FixedWidthType; +import com.facebook.presto.common.type.JsonType; import com.facebook.presto.common.type.TypeManager; import com.facebook.presto.common.type.VarcharType; import com.facebook.presto.pinot.PinotColumnHandle; @@ -499,7 +500,7 @@ public PinotQueryGeneratorContext visitAggregation(AggregationNode node, PinotQu case GROUP_BY: { GroupByColumnNode groupByColumn = (GroupByColumnNode) expression; VariableReferenceExpression groupByInputColumn = getVariableReference(groupByColumn.getInputColumn()); - checkState(groupByInputColumn.getType() instanceof FixedWidthType || groupByInputColumn.getType() instanceof VarcharType); + checkState(groupByInputColumn.getType() instanceof FixedWidthType || groupByInputColumn.getType() instanceof VarcharType || groupByInputColumn.getType() instanceof JsonType); variablesInAggregation.add(groupByInputColumn); break; } diff --git a/presto-pinot/pom.xml b/presto-pinot/pom.xml index 50da7f72af62b..1bf803fa296f7 100644 --- a/presto-pinot/pom.xml +++ b/presto-pinot/pom.xml @@ -6,7 +6,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-pinot diff --git a/presto-plugin-toolkit/pom.xml b/presto-plugin-toolkit/pom.xml index cff6a704492cb..dcf596f3df15f 100644 --- a/presto-plugin-toolkit/pom.xml +++ b/presto-plugin-toolkit/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-plugin-toolkit diff --git a/presto-postgresql/pom.xml b/presto-postgresql/pom.xml index 283858f782449..2dca9aa983405 100644 --- a/presto-postgresql/pom.xml +++ b/presto-postgresql/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-postgresql diff --git a/presto-product-tests/pom.xml b/presto-product-tests/pom.xml index 185fd8c462f1f..af3c6168ed840 100644 --- a/presto-product-tests/pom.xml +++ b/presto-product-tests/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-product-tests diff --git a/presto-product-tests/src/main/java/com/facebook/presto/tests/cli/PrestoCliTests.java b/presto-product-tests/src/main/java/com/facebook/presto/tests/cli/PrestoCliTests.java index 2d3514fc894b4..fcd0d3b266e44 100644 --- a/presto-product-tests/src/main/java/com/facebook/presto/tests/cli/PrestoCliTests.java +++ b/presto-product-tests/src/main/java/com/facebook/presto/tests/cli/PrestoCliTests.java @@ -213,14 +213,14 @@ public void shouldHandleSession() presto.getProcessInput().println("show session;"); assertThat(squeezeLines(presto.readLinesUntilPrompt())) - .contains("join_distribution_type|PARTITIONED|PARTITIONED|varchar|The join method to use. Options are BROADCAST,PARTITIONED,AUTOMATIC"); + .contains("join_distribution_type|AUTOMATIC|AUTOMATIC|varchar|The join method to use. Options are BROADCAST,PARTITIONED,AUTOMATIC"); presto.getProcessInput().println("set session join_distribution_type = 'BROADCAST';"); assertThat(presto.readLinesUntilPrompt()).contains("SET SESSION"); presto.getProcessInput().println("show session;"); assertThat(squeezeLines(presto.readLinesUntilPrompt())) - .contains("join_distribution_type|BROADCAST|PARTITIONED|varchar|The join method to use. Options are BROADCAST,PARTITIONED,AUTOMATIC"); + .contains("join_distribution_type|BROADCAST|AUTOMATIC|varchar|The join method to use. Options are BROADCAST,PARTITIONED,AUTOMATIC"); } @Test(groups = CLI, timeOut = TIMEOUT) diff --git a/presto-prometheus/pom.xml b/presto-prometheus/pom.xml index 08ca1b197c625..c3a7fe3a4126d 100644 --- a/presto-prometheus/pom.xml +++ b/presto-prometheus/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-prometheus diff --git a/presto-proxy/pom.xml b/presto-proxy/pom.xml index de694c4630045..b8f4b096c9cb8 100644 --- a/presto-proxy/pom.xml +++ b/presto-proxy/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-proxy diff --git a/presto-raptor/pom.xml b/presto-raptor/pom.xml index ce34a8cddbda3..a4c9cbe17e343 100644 --- a/presto-raptor/pom.xml +++ b/presto-raptor/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-raptor diff --git a/presto-rcfile/pom.xml b/presto-rcfile/pom.xml index 5eafbc738f6cf..159f613382303 100644 --- a/presto-rcfile/pom.xml +++ b/presto-rcfile/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-rcfile diff --git a/presto-record-decoder/pom.xml b/presto-record-decoder/pom.xml index 3ac1efa5a7d6a..f76fb6c9b33f1 100644 --- a/presto-record-decoder/pom.xml +++ b/presto-record-decoder/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-record-decoder diff --git a/presto-redis/pom.xml b/presto-redis/pom.xml index 824c97cd40d8c..0738733c29f21 100644 --- a/presto-redis/pom.xml +++ b/presto-redis/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-redis diff --git a/presto-redshift/pom.xml b/presto-redshift/pom.xml index 718d2b46bd2dc..8fdaa842e6918 100644 --- a/presto-redshift/pom.xml +++ b/presto-redshift/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-redshift diff --git a/presto-resource-group-managers/pom.xml b/presto-resource-group-managers/pom.xml index 90e5d7352cf06..bb8e9265f3bca 100644 --- a/presto-resource-group-managers/pom.xml +++ b/presto-resource-group-managers/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-resource-group-managers diff --git a/presto-server-rpm/pom.xml b/presto-server-rpm/pom.xml index 788143a97f76f..3780d4ed01155 100644 --- a/presto-server-rpm/pom.xml +++ b/presto-server-rpm/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-server-rpm diff --git a/presto-server/pom.xml b/presto-server/pom.xml index bd0063064eb00..b2d18159f8959 100644 --- a/presto-server/pom.xml +++ b/presto-server/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-server diff --git a/presto-session-property-managers/pom.xml b/presto-session-property-managers/pom.xml index bea0c93d1b9a8..b53f83187a78a 100644 --- a/presto-session-property-managers/pom.xml +++ b/presto-session-property-managers/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-session-property-managers diff --git a/presto-spark-base/pom.xml b/presto-spark-base/pom.xml index f3cfbe908f08f..f9195f47c4319 100644 --- a/presto-spark-base/pom.xml +++ b/presto-spark-base/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-spark-base/src/main/java/com/facebook/presto/spark/PrestoSparkQueryExecutionFactory.java b/presto-spark-base/src/main/java/com/facebook/presto/spark/PrestoSparkQueryExecutionFactory.java index ec04cce1a97ee..369a21bfee041 100644 --- a/presto-spark-base/src/main/java/com/facebook/presto/spark/PrestoSparkQueryExecutionFactory.java +++ b/presto-spark-base/src/main/java/com/facebook/presto/spark/PrestoSparkQueryExecutionFactory.java @@ -153,6 +153,7 @@ import static com.facebook.presto.SystemSessionProperties.getQueryMaxBroadcastMemory; import static com.facebook.presto.SystemSessionProperties.getQueryMaxExecutionTime; import static com.facebook.presto.SystemSessionProperties.getQueryMaxRunTime; +import static com.facebook.presto.SystemSessionProperties.getQueryMaxTotalMemoryPerNode; import static com.facebook.presto.SystemSessionProperties.getWarningHandlingLevel; import static com.facebook.presto.common.type.BigintType.BIGINT; import static com.facebook.presto.execution.QueryState.FAILED; @@ -1166,6 +1167,7 @@ private RddAndMore createRdd(SubPlan subPla broadcastDependency = new PrestoSparkStorageBasedBroadcastDependency( childRdd, maxBroadcastMemory, + getQueryMaxTotalMemoryPerNode(session), queryCompletionDeadline, tempStorage, tempDataOperationContext, diff --git a/presto-spark-base/src/main/java/com/facebook/presto/spark/PrestoSparkStorageBasedBroadcastDependency.java b/presto-spark-base/src/main/java/com/facebook/presto/spark/PrestoSparkStorageBasedBroadcastDependency.java index 4ec95cf1dbf65..ca34eba1b86e7 100644 --- a/presto-spark-base/src/main/java/com/facebook/presto/spark/PrestoSparkStorageBasedBroadcastDependency.java +++ b/presto-spark-base/src/main/java/com/facebook/presto/spark/PrestoSparkStorageBasedBroadcastDependency.java @@ -27,10 +27,12 @@ import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeoutException; import static com.facebook.presto.ExceededMemoryLimitException.exceededLocalBroadcastMemoryLimit; +import static com.facebook.presto.ExceededMemoryLimitException.exceededLocalTotalMemoryLimit; import static com.facebook.presto.spark.SparkErrorCode.STORAGE_ERROR; import static com.facebook.presto.spark.util.PrestoSparkUtils.computeNextTimeout; import static io.airlift.units.DataSize.succinctBytes; @@ -46,6 +48,7 @@ public class PrestoSparkStorageBasedBroadcastDependency private RddAndMore broadcastDependency; private final DataSize maxBroadcastSize; + private final DataSize queryMaxTotalMemoryPerNode; private final long queryCompletionDeadline; private final TempStorage tempStorage; private final TempDataOperationContext tempDataOperationContext; @@ -53,10 +56,18 @@ public class PrestoSparkStorageBasedBroadcastDependency private Broadcast> broadcastVariable; - public PrestoSparkStorageBasedBroadcastDependency(RddAndMore broadcastDependency, DataSize maxBroadcastSize, long queryCompletionDeadline, TempStorage tempStorage, TempDataOperationContext tempDataOperationContext, Set waitTimeMetrics) + public PrestoSparkStorageBasedBroadcastDependency( + RddAndMore broadcastDependency, + DataSize maxBroadcastSize, + DataSize queryMaxTotalMemoryPerNode, + long queryCompletionDeadline, + TempStorage tempStorage, + TempDataOperationContext tempDataOperationContext, + Set waitTimeMetrics) { this.broadcastDependency = requireNonNull(broadcastDependency, "broadcastDependency cannot be null"); this.maxBroadcastSize = requireNonNull(maxBroadcastSize, "maxBroadcastSize cannot be null"); + this.queryMaxTotalMemoryPerNode = requireNonNull(queryMaxTotalMemoryPerNode, "queryMaxTotalMemoryPerNode cannot be null"); this.queryCompletionDeadline = queryCompletionDeadline; this.tempStorage = requireNonNull(tempStorage, "tempStorage cannot be null"); this.tempDataOperationContext = requireNonNull(tempDataOperationContext, "tempDataOperationContext cannot be null"); @@ -96,6 +107,14 @@ public Broadcast> executeBroadcast(JavaSparkConte throw exceededLocalBroadcastMemoryLimit(maxBroadcastSize, format("Uncompressed broadcast size: %s", succinctBytes(uncompressedBroadcastSizeInBytes))); } + if (compressedBroadcastSizeInBytes > queryMaxTotalMemoryPerNode.toBytes() || uncompressedBroadcastSizeInBytes > queryMaxTotalMemoryPerNode.toBytes()) { + throw exceededLocalTotalMemoryLimit( + queryMaxTotalMemoryPerNode, + format("Compressed broadcast size: %s; Uncompressed broadcast size: %s", succinctBytes(compressedBroadcastSizeInBytes), succinctBytes(uncompressedBroadcastSizeInBytes)), + false, + Optional.empty()); + } + broadcastVariable = sparkContext.broadcast(broadcastValue); return broadcastVariable; } diff --git a/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkBroadcastTableCacheManager.java b/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkBroadcastTableCacheManager.java index 2a6ec7ea7a8ae..fbbc46ea4e27e 100644 --- a/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkBroadcastTableCacheManager.java +++ b/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkBroadcastTableCacheManager.java @@ -60,7 +60,7 @@ public synchronized void cache(StageId stageId, PlanNodeId planNodeId, List> pageIterators; @GuardedBy("this") private int currentIteratorIndex; + @GuardedBy("this") + private long stagingBroadcastTableSizeInBytes; public PrestoSparkDiskPageInput( PagesSerde pagesSerde, @@ -81,15 +84,15 @@ public PrestoSparkDiskPageInput( } @Override - public Page getNextPage() + public Page getNextPage(UpdateMemory updateMemory) { Page page = null; synchronized (this) { while (page == null) { - if (currentIteratorIndex >= getPageIterators().size()) { + if (currentIteratorIndex >= getPageIterators(updateMemory).size()) { return null; } - Iterator currentIterator = getPageIterators().get(currentIteratorIndex); + Iterator currentIterator = getPageIterators(updateMemory).get(currentIteratorIndex); if (currentIterator.hasNext()) { page = currentIterator.next(); } @@ -101,10 +104,10 @@ public Page getNextPage() return page; } - private List> getPageIterators() + private List> getPageIterators(UpdateMemory updateMemory) { if (pageIterators == null) { - pageIterators = getPages(broadcastTableFilesInfo, tempStorage, tempDataOperationContext, prestoSparkBroadcastTableCacheManager, stageId, planNodeId); + pageIterators = getPages(broadcastTableFilesInfo, tempStorage, tempDataOperationContext, prestoSparkBroadcastTableCacheManager, stageId, planNodeId, updateMemory); } return pageIterators; } @@ -115,32 +118,35 @@ private List> getPages( TempDataOperationContext tempDataOperationContext, PrestoSparkBroadcastTableCacheManager prestoSparkBroadcastTableCacheManager, StageId stageId, - PlanNodeId planNodeId) + PlanNodeId planNodeId, + UpdateMemory updateMemory) { // Try to get table from cache List> pages = prestoSparkBroadcastTableCacheManager.getCachedBroadcastTable(stageId, planNodeId); if (pages == null) { pages = broadcastTableFilesInfo.stream() - .map(tableFiles -> { - List serializedPages = loadBroadcastTable(tableFiles, tempStorage, tempDataOperationContext); - return serializedPages.stream().map(serializedPage -> pagesSerde.deserialize(serializedPage)).collect(toImmutableList()); - }).collect(toImmutableList()); + .map(tableFiles -> loadBroadcastTable(tableFiles, tempStorage, tempDataOperationContext, updateMemory)) + .collect(toImmutableList()); // Cache deserialized pages prestoSparkBroadcastTableCacheManager.cache(stageId, planNodeId, pages); + + // Reset staging table size + stagingBroadcastTableSizeInBytes = 0; } return pages.stream().map(List::iterator).collect(toImmutableList()); } - private List loadBroadcastTable( + private List loadBroadcastTable( List broadcastTaskFilesInfo, TempStorage tempStorage, - TempDataOperationContext tempDataOperationContext) + TempDataOperationContext tempDataOperationContext, + UpdateMemory updateMemory) { try { CRC32 checksum = new CRC32(); - ImmutableList.Builder pages = ImmutableList.builder(); + ImmutableList.Builder pages = ImmutableList.builder(); List broadcastTaskFilesInfoCopy = new ArrayList<>(broadcastTaskFilesInfo); shuffle(broadcastTaskFilesInfoCopy); for (PrestoSparkTaskOutput taskFileInfo : broadcastTaskFilesInfoCopy) { @@ -152,10 +158,13 @@ private List loadBroadcastTable( InputStreamSliceInput inputStreamSliceInput = new InputStreamSliceInput(inputStream)) { Iterator pagesIterator = readSerializedPages(inputStreamSliceInput); while (pagesIterator.hasNext()) { - SerializedPage page = pagesIterator.next(); - checksum.update(page.getSlice().byteArray(), page.getSlice().byteArrayOffset(), page.getSlice().length()); - pages.add(page); + SerializedPage serializedPage = pagesIterator.next(); + checksum.update(serializedPage.getSlice().byteArray(), serializedPage.getSlice().byteArrayOffset(), serializedPage.getSlice().length()); + Page deserializedPage = pagesSerde.deserialize(serializedPage); + pages.add(deserializedPage); + stagingBroadcastTableSizeInBytes += deserializedPage.getRetainedSizeInBytes(); } + updateMemory.update(); } if (checksum.getValue() != prestoSparkStorageHandle.getChecksum()) { @@ -174,4 +183,9 @@ public long getRetainedSizeInBytes() { return prestoSparkBroadcastTableCacheManager.getBroadcastTableSizeInBytes(stageId, planNodeId); } + + public long getStagingBroadcastTableSizeInBytes() + { + return stagingBroadcastTableSizeInBytes; + } } diff --git a/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkPageInput.java b/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkPageInput.java index 8b856433d18fe..1b5efff60ef9f 100644 --- a/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkPageInput.java +++ b/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkPageInput.java @@ -14,6 +14,7 @@ package com.facebook.presto.spark.execution; import com.facebook.presto.common.Page; +import com.facebook.presto.operator.UpdateMemory; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -25,5 +26,5 @@ public interface PrestoSparkPageInput { @Nullable - Page getNextPage(); + Page getNextPage(UpdateMemory updateMemory); } diff --git a/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkRemoteSourceOperator.java b/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkRemoteSourceOperator.java index 236164b8fc42c..14a9b16bbf239 100644 --- a/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkRemoteSourceOperator.java +++ b/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkRemoteSourceOperator.java @@ -74,7 +74,10 @@ public Page getOutput() return null; } - Page page = pageInput.getNextPage(); + Page page = pageInput.getNextPage(() -> { + updateMemoryContext(); + return true; + }); updateMemoryContext(); if (page == null) { finished = true; @@ -121,10 +124,17 @@ public void close() private void updateMemoryContext() { - // Since the cache is shared, only the first PrestoSparkRemoteSourceOperator should report the cache memory - if (isFirstOperator && pageInput instanceof PrestoSparkDiskPageInput) { + if (pageInput instanceof PrestoSparkDiskPageInput) { + long memorySize = 0; PrestoSparkDiskPageInput diskPageInput = (PrestoSparkDiskPageInput) pageInput; - systemMemoryContext.setBytes(diskPageInput.getRetainedSizeInBytes()); + memorySize += diskPageInput.getStagingBroadcastTableSizeInBytes(); + + // Since the cache is shared, only the first PrestoSparkRemoteSourceOperator should report the cache memory + if (isFirstOperator) { + memorySize += diskPageInput.getRetainedSizeInBytes(); + } + + systemMemoryContext.setBytes(memorySize); } } diff --git a/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkSerializedPageInput.java b/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkSerializedPageInput.java index f02d303434f13..a72ebbe316a6b 100644 --- a/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkSerializedPageInput.java +++ b/presto-spark-base/src/main/java/com/facebook/presto/spark/execution/PrestoSparkSerializedPageInput.java @@ -14,6 +14,7 @@ package com.facebook.presto.spark.execution; import com.facebook.presto.common.Page; +import com.facebook.presto.operator.UpdateMemory; import com.facebook.presto.spark.classloader_interface.PrestoSparkSerializedPage; import com.facebook.presto.spi.page.PagesSerde; @@ -41,7 +42,7 @@ public PrestoSparkSerializedPageInput(PagesSerde pagesSerde, List presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-spark-common/pom.xml b/presto-spark-common/pom.xml index 09656fc5e4b7e..f89bb7c7d043d 100644 --- a/presto-spark-common/pom.xml +++ b/presto-spark-common/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-spark-common diff --git a/presto-spark-launcher/pom.xml b/presto-spark-launcher/pom.xml index a8311ff7de358..909ed1fe5ea1b 100644 --- a/presto-spark-launcher/pom.xml +++ b/presto-spark-launcher/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-spark-package/pom.xml b/presto-spark-package/pom.xml index 7998507fcd853..316984aacc1a9 100644 --- a/presto-spark-package/pom.xml +++ b/presto-spark-package/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-spark-package diff --git a/presto-spark-testing/pom.xml b/presto-spark-testing/pom.xml index 29abc6b2e769f..eb7c649d982cf 100644 --- a/presto-spark-testing/pom.xml +++ b/presto-spark-testing/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-spark/pom.xml b/presto-spark/pom.xml index c7a4736c1da42..4ba06d41fa5f6 100644 --- a/presto-spark/pom.xml +++ b/presto-spark/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-spi/pom.xml b/presto-spi/pom.xml index 80c69f1a69274..7e6e5fbc382f4 100644 --- a/presto-spi/pom.xml +++ b/presto-spi/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-spi diff --git a/presto-sqlserver/pom.xml b/presto-sqlserver/pom.xml index 102dab748674b..0820731793074 100644 --- a/presto-sqlserver/pom.xml +++ b/presto-sqlserver/pom.xml @@ -3,7 +3,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT 4.0.0 diff --git a/presto-teradata-functions/pom.xml b/presto-teradata-functions/pom.xml index fa2a2240abba0..b183ae2566c80 100644 --- a/presto-teradata-functions/pom.xml +++ b/presto-teradata-functions/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-teradata-functions diff --git a/presto-testing-docker/pom.xml b/presto-testing-docker/pom.xml index 4651fd48b00c8..4841513f491a2 100644 --- a/presto-testing-docker/pom.xml +++ b/presto-testing-docker/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-testing-docker diff --git a/presto-testing-server-launcher/pom.xml b/presto-testing-server-launcher/pom.xml index 58518443c9659..e50fc3e5f7ab0 100644 --- a/presto-testing-server-launcher/pom.xml +++ b/presto-testing-server-launcher/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-testing-server-launcher diff --git a/presto-testng-services/pom.xml b/presto-testng-services/pom.xml index 70223e89018a3..865061f8ddbcc 100644 --- a/presto-testng-services/pom.xml +++ b/presto-testng-services/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-testng-services diff --git a/presto-tests/pom.xml b/presto-tests/pom.xml index 34717ab7343b0..bbe762c8514ea 100644 --- a/presto-tests/pom.xml +++ b/presto-tests/pom.xml @@ -5,7 +5,7 @@ presto-root com.facebook.presto - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-tests diff --git a/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestVerboseMemoryExceededErrors.java b/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestVerboseMemoryExceededErrors.java index 07e7583c164b1..8eb0cca6f4980 100644 --- a/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestVerboseMemoryExceededErrors.java +++ b/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestVerboseMemoryExceededErrors.java @@ -26,8 +26,12 @@ import java.util.regex.Pattern; import static com.facebook.airlift.json.JsonCodec.listJsonCodec; +import static com.facebook.presto.SystemSessionProperties.JOIN_DISTRIBUTION_TYPE; +import static com.facebook.presto.SystemSessionProperties.JOIN_REORDERING_STRATEGY; import static com.facebook.presto.SystemSessionProperties.USE_MARK_DISTINCT; import static com.facebook.presto.SystemSessionProperties.VERBOSE_EXCEEDED_MEMORY_LIMIT_ERRORS_ENABLED; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinDistributionType.PARTITIONED; +import static com.facebook.presto.sql.analyzer.FeaturesConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS; import static java.util.regex.Pattern.DOTALL; import static org.assertj.core.api.Assertions.assertThat; import static org.testng.Assert.assertEquals; @@ -121,7 +125,10 @@ public void testWindow() private void assertMemoryExceededDetails(String sql, String expectedTopConsumerOperatorName, Optional expectedTopConsumerOperatorInfo) { try { - getQueryRunner().execute(getSession(), sql); + getQueryRunner().execute(Session.builder(getSession()) + .setSystemProperty(JOIN_REORDERING_STRATEGY, ELIMINATE_CROSS_JOINS.name()) + .setSystemProperty(JOIN_DISTRIBUTION_TYPE, PARTITIONED.name()) + .build(), sql); fail("query expected to fail"); } catch (RuntimeException e) { diff --git a/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java b/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java index d52104268943e..f56f256a7f435 100644 --- a/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java +++ b/presto-tests/src/main/java/com/facebook/presto/tests/DistributedQueryRunner.java @@ -197,6 +197,11 @@ private DistributedQueryRunner( extraCoordinatorProperties.putAll(extraProperties); extraCoordinatorProperties.putAll(coordinatorProperties); + if (resourceManagerEnabled) { + resourceManager = Optional.of(closer.register(createTestingPrestoServer(discoveryUrl, true, true, false, resourceManagerProperties, parserOptions, environment, baseDataDir, extraModules))); + servers.add(resourceManager.get()); + } + for (int i = 0; i < coordinatorCount; i++) { TestingPrestoServer coordinator = closer.register(createTestingPrestoServer(discoveryUrl, false, resourceManagerEnabled, true, extraCoordinatorProperties, parserOptions, environment, baseDataDir, extraModules)); servers.add(coordinator); @@ -204,11 +209,6 @@ private DistributedQueryRunner( extraCoordinatorProperties.remove("http-server.http.port"); } - if (resourceManagerEnabled) { - resourceManager = Optional.of(closer.register(createTestingPrestoServer(discoveryUrl, true, true, false, resourceManagerProperties, parserOptions, environment, baseDataDir, extraModules))); - servers.add(resourceManager.get()); - } - this.servers = servers.build(); this.coordinators = coordinators.build(); } @@ -430,6 +430,11 @@ public Optional getResourceManager() return resourceManager; } + public List getCoordinatorWorkers() + { + return getServers().stream().filter(server -> !server.isResourceManager()).collect(ImmutableList.toImmutableList()); + } + public List getServers() { return ImmutableList.copyOf(servers); diff --git a/presto-tests/src/test/java/com/facebook/presto/memory/TestMemoryManager.java b/presto-tests/src/test/java/com/facebook/presto/memory/TestMemoryManager.java index 3f290dbcee075..bfb3be2c58bf4 100644 --- a/presto-tests/src/test/java/com/facebook/presto/memory/TestMemoryManager.java +++ b/presto-tests/src/test/java/com/facebook/presto/memory/TestMemoryManager.java @@ -454,7 +454,7 @@ public void testClusterPoolsMultiCoordinator() try (DistributedQueryRunner queryRunner = createQueryRunner(properties, ImmutableMap.of(), properties, 2)) { // Reserve all the memory QueryId fakeQueryId = new QueryId("fake"); - for (TestingPrestoServer server : queryRunner.getServers()) { + for (TestingPrestoServer server : queryRunner.getCoordinatorWorkers()) { for (MemoryPool pool : server.getLocalMemoryManager().getPools()) { assertTrue(pool.tryReserve(fakeQueryId, "test", pool.getMaxBytes())); } @@ -513,7 +513,7 @@ public void testClusterPoolsMultiCoordinator() } // Release the memory in the reserved pool - for (TestingPrestoServer server : queryRunner.getServers()) { + for (TestingPrestoServer server : queryRunner.getCoordinatorWorkers()) { Optional reserved = server.getLocalMemoryManager().getReservedPool(); assertTrue(reserved.isPresent()); // Free up the entire pool @@ -534,7 +534,7 @@ public void testClusterPoolsMultiCoordinator() .forEach(info -> assertEquals(info.getState(), FINISHED)); // Make sure we didn't leak any memory on the workers - for (TestingPrestoServer worker : queryRunner.getServers()) { + for (TestingPrestoServer worker : queryRunner.getCoordinatorWorkers()) { Optional reserved = worker.getLocalMemoryManager().getReservedPool(); assertTrue(reserved.isPresent()); assertEquals(reserved.get().getMaxBytes(), reserved.get().getFreeBytes()); diff --git a/presto-tests/src/test/java/com/facebook/presto/server/TestServerInfoResource.java b/presto-tests/src/test/java/com/facebook/presto/server/TestServerInfoResource.java index 46168ba781996..e966adaf9a8b8 100644 --- a/presto-tests/src/test/java/com/facebook/presto/server/TestServerInfoResource.java +++ b/presto-tests/src/test/java/com/facebook/presto/server/TestServerInfoResource.java @@ -33,6 +33,7 @@ import static com.facebook.airlift.testing.Closeables.closeQuietly; import static com.facebook.presto.client.PrestoHeaders.PRESTO_USER; import static com.facebook.presto.tests.tpch.TpchQueryRunner.createQueryRunner; +import static com.facebook.presto.tests.tpch.TpchQueryRunner.createQueryRunnerWithNoClusterReadyCheck; import static org.testng.Assert.assertEquals; public class TestServerInfoResource @@ -73,11 +74,11 @@ public void testGetServerStateWithRequiredResourceManagerCoordinators() closeQuietly(server); } - @Test + @Test(timeOut = 30_000) public void testGetServerStateWithoutRequiredResourceManagers() throws Exception { - DistributedQueryRunner queryRunner = createQueryRunner( + DistributedQueryRunner queryRunner = createQueryRunnerWithNoClusterReadyCheck( ImmutableMap.of(), ImmutableMap.of("cluster.required-resource-managers-active", "2", "cluster.required-coordinators-active", "1"), ImmutableMap.of("query.client.timeout", "10s"), 2); @@ -93,11 +94,11 @@ public void testGetServerStateWithoutRequiredResourceManagers() closeQuietly(server); } - @Test + @Test(timeOut = 30_000) public void testGetServerStateWithoutRequiredCoordinators() throws Exception { - DistributedQueryRunner queryRunner = createQueryRunner( + DistributedQueryRunner queryRunner = createQueryRunnerWithNoClusterReadyCheck( ImmutableMap.of(), ImmutableMap.of("cluster.required-resource-managers-active", "1", "cluster.required-coordinators-active", "3"), ImmutableMap.of("query.client.timeout", "10s"), 2); diff --git a/presto-tests/src/test/java/com/facebook/presto/tests/TestBrutalShutdown.java b/presto-tests/src/test/java/com/facebook/presto/tests/TestBrutalShutdown.java index f362ef838620b..5f94d5a88e52e 100644 --- a/presto-tests/src/test/java/com/facebook/presto/tests/TestBrutalShutdown.java +++ b/presto-tests/src/test/java/com/facebook/presto/tests/TestBrutalShutdown.java @@ -42,7 +42,7 @@ @Test(singleThreaded = true) public class TestBrutalShutdown { - private static final long SHUTDOWN_TIMEOUT_MILLIS = 240_000; + private static final long SHUTDOWN_TIMEOUT_MILLIS = 600_000; private static final Session TINY_SESSION = testSessionBuilder() .setCatalog("tpch") .setSchema("tiny") diff --git a/presto-tests/src/test/java/com/facebook/presto/tests/tpch/TpchQueryRunner.java b/presto-tests/src/test/java/com/facebook/presto/tests/tpch/TpchQueryRunner.java index 14367e2d1d61b..af65af1c9042f 100644 --- a/presto-tests/src/test/java/com/facebook/presto/tests/tpch/TpchQueryRunner.java +++ b/presto-tests/src/test/java/com/facebook/presto/tests/tpch/TpchQueryRunner.java @@ -35,23 +35,41 @@ public static DistributedQueryRunner createQueryRunner(Map extra public static DistributedQueryRunner createQueryRunner(Map extraProperties, int coordinatorCount) throws Exception { - return TpchQueryRunnerBuilder.builder() + DistributedQueryRunner queryRunner = TpchQueryRunnerBuilder.builder() .setExtraProperties(extraProperties) .setResourceManagerEnabled(true) .setCoordinatorCount(coordinatorCount) .build(); + queryRunner.waitForClusterToGetReady(); + return queryRunner; } public static DistributedQueryRunner createQueryRunner(Map resourceManagerProperties, Map coordinatorProperties, Map extraProperties, int coordinatorCount) throws Exception { - return TpchQueryRunnerBuilder.builder() + return createQueryRunner(resourceManagerProperties, coordinatorProperties, extraProperties, coordinatorCount, false); + } + + public static DistributedQueryRunner createQueryRunnerWithNoClusterReadyCheck(Map resourceManagerProperties, Map coordinatorProperties, Map extraProperties, int coordinatorCount) + throws Exception + { + return createQueryRunner(resourceManagerProperties, coordinatorProperties, extraProperties, coordinatorCount, true); + } + + public static DistributedQueryRunner createQueryRunner(Map resourceManagerProperties, Map coordinatorProperties, Map extraProperties, int coordinatorCount, boolean skipClusterReadyCheck) + throws Exception + { + DistributedQueryRunner queryRunner = TpchQueryRunnerBuilder.builder() .setResourceManagerProperties(resourceManagerProperties) .setCoordinatorProperties(coordinatorProperties) .setExtraProperties(extraProperties) .setResourceManagerEnabled(true) .setCoordinatorCount(coordinatorCount) .build(); + if (!skipClusterReadyCheck) { + queryRunner.waitForClusterToGetReady(); + } + return queryRunner; } public static void main(String[] args) diff --git a/presto-thrift-api/pom.xml b/presto-thrift-api/pom.xml index a9f03431f0690..c51b2f346c0b6 100644 --- a/presto-thrift-api/pom.xml +++ b/presto-thrift-api/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-thrift-api diff --git a/presto-thrift-connector/pom.xml b/presto-thrift-connector/pom.xml index 1fc035fbe865d..6cdcac840f9e3 100644 --- a/presto-thrift-connector/pom.xml +++ b/presto-thrift-connector/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-thrift-connector diff --git a/presto-thrift-spec/pom.xml b/presto-thrift-spec/pom.xml index 95e17c1a502fb..9691a4e22dac4 100644 --- a/presto-thrift-spec/pom.xml +++ b/presto-thrift-spec/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-thrift-spec diff --git a/presto-thrift-testing-server/pom.xml b/presto-thrift-testing-server/pom.xml index c69eeec5ac268..fe041ca291bf6 100644 --- a/presto-thrift-testing-server/pom.xml +++ b/presto-thrift-testing-server/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-thrift-testing-server diff --git a/presto-thrift-testing-udf-server/pom.xml b/presto-thrift-testing-udf-server/pom.xml index 23e5cc27d246e..bff1c3b54bb48 100644 --- a/presto-thrift-testing-udf-server/pom.xml +++ b/presto-thrift-testing-udf-server/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-thrift-testing-udf-server diff --git a/presto-tpcds/pom.xml b/presto-tpcds/pom.xml index 373f99b24b275..caac45c7278b5 100644 --- a/presto-tpcds/pom.xml +++ b/presto-tpcds/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-tpcds diff --git a/presto-tpch/pom.xml b/presto-tpch/pom.xml index 1ee742e4e6548..967f7f3cdc4e6 100644 --- a/presto-tpch/pom.xml +++ b/presto-tpch/pom.xml @@ -4,7 +4,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-tpch diff --git a/presto-verifier/pom.xml b/presto-verifier/pom.xml index 1414870de411f..9a22bf6dce7f5 100644 --- a/presto-verifier/pom.xml +++ b/presto-verifier/pom.xml @@ -5,7 +5,7 @@ com.facebook.presto presto-root - 0.271-SNAPSHOT + 0.272-SNAPSHOT presto-verifier diff --git a/presto-verifier/src/main/java/com/facebook/presto/verifier/resolver/IgnoredFunctionsMismatchResolver.java b/presto-verifier/src/main/java/com/facebook/presto/verifier/resolver/IgnoredFunctionsMismatchResolver.java index a3424efac2e80..de20105100dec 100644 --- a/presto-verifier/src/main/java/com/facebook/presto/verifier/resolver/IgnoredFunctionsMismatchResolver.java +++ b/presto-verifier/src/main/java/com/facebook/presto/verifier/resolver/IgnoredFunctionsMismatchResolver.java @@ -16,18 +16,20 @@ import com.facebook.presto.common.CatalogSchemaName; import com.facebook.presto.sql.tree.AstVisitor; import com.facebook.presto.sql.tree.FunctionCall; +import com.facebook.presto.sql.tree.Identifier; import com.facebook.presto.sql.tree.Node; import com.facebook.presto.sql.tree.QualifiedName; import com.facebook.presto.verifier.framework.DataMatchResult; import com.facebook.presto.verifier.framework.QueryBundle; -import com.google.common.base.Splitter; import javax.inject.Inject; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import static com.facebook.presto.metadata.BuiltInTypeAndFunctionNamespaceManager.DEFAULT_NAMESPACE; import static com.facebook.presto.verifier.framework.DataMatchResult.MatchType.COLUMN_MISMATCH; @@ -87,7 +89,9 @@ protected Void visitFunctionCall(FunctionCall node, Set ignoredFunctions private static String normalizeFunctionName(String name) { - return normalizeFunctionName(QualifiedName.of(Splitter.on(".").splitToList(name))); + return normalizeFunctionName(QualifiedName.of(Arrays.stream(name.split("\\.")) + .map(Identifier::new) + .collect(Collectors.toList()))); } private static String normalizeFunctionName(QualifiedName name) diff --git a/presto-verifier/src/main/java/com/facebook/presto/verifier/rewrite/QueryRewriteConfig.java b/presto-verifier/src/main/java/com/facebook/presto/verifier/rewrite/QueryRewriteConfig.java index 9c524f959943a..8db59b7c3a1ff 100644 --- a/presto-verifier/src/main/java/com/facebook/presto/verifier/rewrite/QueryRewriteConfig.java +++ b/presto-verifier/src/main/java/com/facebook/presto/verifier/rewrite/QueryRewriteConfig.java @@ -15,16 +15,18 @@ import com.facebook.airlift.configuration.Config; import com.facebook.airlift.configuration.ConfigDescription; +import com.facebook.presto.sql.tree.Identifier; import com.facebook.presto.sql.tree.QualifiedName; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Splitter; import com.google.common.collect.ImmutableMap; import javax.validation.constraints.NotNull; import java.io.IOException; +import java.util.Arrays; import java.util.Map; +import java.util.stream.Collectors; public class QueryRewriteConfig { @@ -43,7 +45,9 @@ public QueryRewriteConfig setTablePrefix(String tablePrefix) { this.tablePrefix = tablePrefix == null ? null : - QualifiedName.of(Splitter.on(".").splitToList(tablePrefix)); + QualifiedName.of(Arrays.stream(tablePrefix.split("\\.")) + .map(Identifier::new) + .collect(Collectors.toList())); return this; } diff --git a/presto-verifier/src/main/java/com/facebook/presto/verifier/rewrite/QueryRewriter.java b/presto-verifier/src/main/java/com/facebook/presto/verifier/rewrite/QueryRewriter.java index 00c91700975d9..e9a0c68011f35 100644 --- a/presto-verifier/src/main/java/com/facebook/presto/verifier/rewrite/QueryRewriter.java +++ b/presto-verifier/src/main/java/com/facebook/presto/verifier/rewrite/QueryRewriter.java @@ -228,14 +228,14 @@ public QueryObjectBundle rewriteQuery(@Language("SQL") String query, ClusterType private QualifiedName generateTemporaryName(Optional originalName, QualifiedName prefix) { - List parts = new ArrayList<>(); + List parts = new ArrayList<>(); int originalSize = originalName.map(QualifiedName::getOriginalParts).map(List::size).orElse(0); int prefixSize = prefix.getOriginalParts().size(); if (originalName.isPresent() && originalSize > prefixSize) { parts.addAll(originalName.get().getOriginalParts().subList(0, originalSize - prefixSize)); } parts.addAll(prefix.getOriginalParts()); - parts.set(parts.size() - 1, prefix.getSuffix() + "_" + randomUUID().toString().replace("-", "")); + parts.set(parts.size() - 1, new Identifier(prefix.getSuffix() + "_" + randomUUID().toString().replace("-", ""))); return QualifiedName.of(parts); }