Improved Google Analytics integration (#11484)

- Enhanced Google Analytics API.
- Now published as a type with static methods not a module.
- Bump version and add Admin API.
- Moved the reading logic to Java from Enso.
- Add dependency on Standard Table allowing report to be built into a Java Table directly.
- New `Google_Credential.new` method.
![image](https://github.com/user-attachments/assets/54e3ad87-045f-4e40-b609-337d827c5d02)
- Ability to list accounts for a credential (`Google_Analytics.list_accounts`).
![image](https://github.com/user-attachments/assets/296c6dcc-3b24-43fa-b909-5e74c40d77a1)
- Ability to list properties (either for an account or for all) (`Google_Analytics.list_properties`).
![image](https://github.com/user-attachments/assets/e420c824-d08e-48d0-b21c-560b4c7c4809)
- Simple object structure of `Google_Analytics_Account`, `Google_Analytics_Property` and `Google_Analytics_Field` with some helper methods.
- Widget for `account`, `property` and `credentials`.
![image](https://github.com/user-attachments/assets/221c1450-964d-4fce-af8b-2273aa8739a1)
![image](https://github.com/user-attachments/assets/e1daf1dd-2ade-4c33-875c-4e3cb1544fe6)
![image](https://github.com/user-attachments/assets/cd37b018-4fad-4771-9f48-1448f0076ef9)
- Widget for `dimensions` and `metrics` with defaults and then reading from Admin API.
![image](https://github.com/user-attachments/assets/3a4b1d42-9555-499d-90da-04d7586ab4c1)
![image](https://github.com/user-attachments/assets/16efcb11-3547-4eaf-9f28-944fa21c4aa2)
- Added widget for `start_date` and `end_date` on `Google_Analytics.read`.
- Bug fix for `parse` with auto type by reordering to allow numeric dates to be parsed.
- **ToDo**: better exception handling.
This commit is contained in:
James Dunkerley 2024-11-05 10:11:42 +00:00 committed by GitHub
parent 35e5ed53d2
commit c5734a8fc8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
180 changed files with 990 additions and 462 deletions

View File

@ -122,6 +122,7 @@
- [Added `format` parameter to `Float.parse`.][11229]
- [Implemented a cache for HTTP data requests, as well as a per-file response
size limit.][11342]
- [Overhauled Google Analytics APIs.][11484]
[10614]: https://github.com/enso-org/enso/pull/10614
[10660]: https://github.com/enso-org/enso/pull/10660
@ -138,6 +139,7 @@
[11205]: https://github.com/enso-org/enso/pull/11205
[11229]: https://github.com/enso-org/enso/pull/11229
[11342]: https://github.com/enso-org/enso/pull/11342
[11484]: https://github.com/enso-org/enso/pull/11484
#### Enso Language & Runtime

View File

@ -586,7 +586,8 @@ val bouncyCastle = Seq(
// === Google =================================================================
val googleApiClientVersion = "2.2.0"
val googleApiServicesSheetsVersion = "v4-rev612-1.25.0"
val googleAnalyticsDataVersion = "0.44.0"
val googleAnalyticsAdminVersion = "0.62.0"
val googleAnalyticsDataVersion = "0.63.0"
// === Other ==================================================================
@ -4598,6 +4599,7 @@ lazy val `std-google-api` = project
libraryDependencies ++= Seq(
"com.google.api-client" % "google-api-client" % googleApiClientVersion exclude ("com.google.code.findbugs", "jsr305"),
"com.google.apis" % "google-api-services-sheets" % googleApiServicesSheetsVersion exclude ("com.google.code.findbugs", "jsr305"),
"com.google.analytics" % "google-analytics-admin" % googleAnalyticsAdminVersion exclude ("com.google.code.findbugs", "jsr305"),
"com.google.analytics" % "google-analytics-data" % googleAnalyticsDataVersion exclude ("com.google.code.findbugs", "jsr305")
),
Compile / packageBin := Def.task {
@ -4612,6 +4614,7 @@ lazy val `std-google-api` = project
result
}.value
)
.dependsOn(`std-table` % "provided")
lazy val `std-database` = project
.in(file("std-bits") / "database")

View File

@ -100,7 +100,7 @@ type Widget
## PRIVATE
make_single_choice : Vector -> Display -> Widget
make_single_choice values display=Display.Always =
make_single_choice values display:Display=..Always =
make_option value = case value of
_ : Vector -> Choice.Option value.first value.second
_ : Text -> Choice.Option value value.pretty

View File

@ -1,9 +1,14 @@
Enso
Copyright 2020 - 2024 New Byte Order sp. z o. o.
'google-analytics-admin', licensed under the Apache-2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.analytics.google-analytics-admin-0.62.0`.
'google-analytics-data', licensed under the Apache-2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.analytics.google-analytics-data-0.44.0`.
Copyright notices related to this dependency can be found in the directory `com.google.analytics.google-analytics-data-0.63.0`.
'annotations', licensed under the Apache 2.0, is distributed with the Google_Api.
@ -18,37 +23,47 @@ Copyright notices related to this dependency can be found in the directory `com.
'api-common', licensed under the BSD-3-Clause, is distributed with the Google_Api.
The license information can be found along with the copyright notices.
Copyright notices related to this dependency can be found in the directory `com.google.api.api-common-2.22.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.api-common-2.38.0`.
'gax', licensed under the BSD-3-Clause, is distributed with the Google_Api.
The license information can be found along with the copyright notices.
Copyright notices related to this dependency can be found in the directory `com.google.api.gax-2.39.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.gax-2.55.0`.
'gax-grpc', licensed under the BSD-3-Clause, is distributed with the Google_Api.
The license information can be found along with the copyright notices.
Copyright notices related to this dependency can be found in the directory `com.google.api.gax-grpc-2.39.0`.
The license file can be found at `licenses/BSD-3-Clause`.
Copyright notices related to this dependency can be found in the directory `com.google.api.gax-grpc-2.55.0`.
'gax-httpjson', licensed under the BSD-3-Clause, is distributed with the Google_Api.
The license information can be found along with the copyright notices.
Copyright notices related to this dependency can be found in the directory `com.google.api.gax-httpjson-2.39.0`.
The license file can be found at `licenses/BSD-3-Clause`.
Copyright notices related to this dependency can be found in the directory `com.google.api.gax-httpjson-2.55.0`.
'proto-google-analytics-admin-v1alpha', licensed under the Apache-2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.grpc.proto-google-analytics-admin-v1alpha-0.62.0`.
'proto-google-analytics-admin-v1beta', licensed under the Apache-2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.grpc.proto-google-analytics-admin-v1beta-0.62.0`.
'proto-google-analytics-data-v1alpha', licensed under the Apache-2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.grpc.proto-google-analytics-data-v1alpha-0.44.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.grpc.proto-google-analytics-data-v1alpha-0.63.0`.
'proto-google-analytics-data-v1beta', licensed under the Apache-2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.grpc.proto-google-analytics-data-v1beta-0.44.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.grpc.proto-google-analytics-data-v1beta-0.63.0`.
'proto-google-common-protos', licensed under the Apache-2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.grpc.proto-google-common-protos-2.30.0`.
Copyright notices related to this dependency can be found in the directory `com.google.api.grpc.proto-google-common-protos-2.46.0`.
'google-api-services-sheets', licensed under the The Apache Software License, Version 2.0, is distributed with the Google_Api.
@ -58,42 +73,42 @@ Copyright notices related to this dependency can be found in the directory `com.
'google-auth-library-credentials', licensed under the BSD New license, is distributed with the Google_Api.
The license file can be found at `licenses/BSD-3-Clause`.
Copyright notices related to this dependency can be found in the directory `com.google.auth.google-auth-library-credentials-1.21.0`.
Copyright notices related to this dependency can be found in the directory `com.google.auth.google-auth-library-credentials-1.28.0`.
'google-auth-library-oauth2-http', licensed under the BSD New license, is distributed with the Google_Api.
The license file can be found at `licenses/BSD-3-Clause`.
Copyright notices related to this dependency can be found in the directory `com.google.auth.google-auth-library-oauth2-http-1.21.0`.
Copyright notices related to this dependency can be found in the directory `com.google.auth.google-auth-library-oauth2-http-1.28.0`.
'auto-value-annotations', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.auto.value.auto-value-annotations-1.10.4`.
Copyright notices related to this dependency can be found in the directory `com.google.auto.value.auto-value-annotations-1.11.0`.
'gson', licensed under the Apache-2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.code.gson.gson-2.10.1`.
Copyright notices related to this dependency can be found in the directory `com.google.code.gson.gson-2.11.0`.
'error_prone_annotations', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.errorprone.error_prone_annotations-2.23.0`.
Copyright notices related to this dependency can be found in the directory `com.google.errorprone.error_prone_annotations-2.33.0`.
'failureaccess', licensed under the The Apache Software License, Version 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.guava.failureaccess-1.0.1`.
Copyright notices related to this dependency can be found in the directory `com.google.guava.failureaccess-1.0.2`.
'guava', licensed under the Apache License, Version 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.guava.guava-32.1.3-jre`.
Copyright notices related to this dependency can be found in the directory `com.google.guava.guava-33.3.1-jre`.
'google-http-client', licensed under the The Apache Software License, Version 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.http-client.google-http-client-1.43.3`.
Copyright notices related to this dependency can be found in the directory `com.google.http-client.google-http-client-1.45.0`.
'google-http-client-apache-v2', licensed under the The Apache Software License, Version 2.0, is distributed with the Google_Api.
@ -103,12 +118,12 @@ Copyright notices related to this dependency can be found in the directory `com.
'google-http-client-gson', licensed under the The Apache Software License, Version 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.http-client.google-http-client-gson-1.43.3`.
Copyright notices related to this dependency can be found in the directory `com.google.http-client.google-http-client-gson-1.45.0`.
'j2objc-annotations', licensed under the Apache License, Version 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `com.google.j2objc.j2objc-annotations-2.8`.
Copyright notices related to this dependency can be found in the directory `com.google.j2objc.j2objc-annotations-3.0.0`.
'google-oauth-client', licensed under the The Apache Software License, Version 2.0, is distributed with the Google_Api.
@ -118,12 +133,12 @@ Copyright notices related to this dependency can be found in the directory `com.
'protobuf-java', licensed under the BSD-3-Clause, is distributed with the Google_Api.
The license file can be found at `licenses/BSD-3-Clause`.
Copyright notices related to this dependency can be found in the directory `com.google.protobuf.protobuf-java-3.25.1`.
Copyright notices related to this dependency can be found in the directory `com.google.protobuf.protobuf-java-3.25.5`.
'protobuf-java-util', licensed under the BSD-3-Clause, is distributed with the Google_Api.
The license file can be found at `licenses/BSD-3-Clause`.
Copyright notices related to this dependency can be found in the directory `com.google.protobuf.protobuf-java-util-3.25.1`.
Copyright notices related to this dependency can be found in the directory `com.google.protobuf.protobuf-java-util-3.25.5`.
're2j', licensed under the Go License, is distributed with the Google_Api.
@ -133,7 +148,7 @@ Copyright notices related to this dependency can be found in the directory `com.
'commons-codec', licensed under the Apache-2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `commons-codec.commons-codec-1.16.0`.
Copyright notices related to this dependency can be found in the directory `commons-codec.commons-codec-1.17.1`.
'commons-logging', licensed under the The Apache Software License, Version 2.0, is distributed with the Google_Api.
@ -143,77 +158,77 @@ Copyright notices related to this dependency can be found in the directory `comm
'grpc-alts', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-alts-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-alts-1.67.1`.
'grpc-api', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-api-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-api-1.67.1`.
'grpc-auth', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-auth-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-auth-1.67.1`.
'grpc-context', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-context-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-context-1.67.1`.
'grpc-core', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-core-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-core-1.67.1`.
'grpc-googleapis', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-googleapis-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-googleapis-1.67.1`.
'grpc-grpclb', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-grpclb-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-grpclb-1.67.1`.
'grpc-inprocess', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-inprocess-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-inprocess-1.67.1`.
'grpc-netty-shaded', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-netty-shaded-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-netty-shaded-1.67.1`.
'grpc-protobuf', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-protobuf-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-protobuf-1.67.1`.
'grpc-protobuf-lite', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-protobuf-lite-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-protobuf-lite-1.67.1`.
'grpc-services', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-services-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-services-1.67.1`.
'grpc-stub', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-stub-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-stub-1.67.1`.
'grpc-util', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-util-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-util-1.67.1`.
'grpc-xds', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-xds-1.60.0`.
Copyright notices related to this dependency can be found in the directory `io.grpc.grpc-xds-1.67.1`.
'opencensus-api', licensed under the The Apache License, Version 2.0, is distributed with the Google_Api.
@ -226,14 +241,9 @@ The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.opencensus.opencensus-contrib-http-util-0.31.1`.
'opencensus-proto', licensed under the The Apache License, Version 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.opencensus.opencensus-proto-0.2.0`.
'perfmark-api', licensed under the Apache 2.0, is distributed with the Google_Api.
The license file can be found at `licenses/APACHE2.0`.
Copyright notices related to this dependency can be found in the directory `io.perfmark.perfmark-api-0.26.0`.
Copyright notices related to this dependency can be found in the directory `io.perfmark.perfmark-api-0.27.0`.
'javax.annotation-api', licensed under the CDDL + GPLv2 with classpath exception, is distributed with the Google_Api.
@ -253,12 +263,12 @@ Copyright notices related to this dependency can be found in the directory `org.
'checker-qual', licensed under the The MIT License, is distributed with the Google_Api.
The license information can be found along with the copyright notices.
Copyright notices related to this dependency can be found in the directory `org.checkerframework.checker-qual-3.40.0`.
Copyright notices related to this dependency can be found in the directory `org.checkerframework.checker-qual-3.47.0`.
'animal-sniffer-annotations', licensed under the MIT license, is distributed with the Google_Api.
The license file can be found at `licenses/MIT`.
Copyright notices related to this dependency can be found in the directory `org.codehaus.mojo.animal-sniffer-annotations-1.23`.
Copyright notices related to this dependency can be found in the directory `org.codehaus.mojo.animal-sniffer-annotations-1.24`.
'conscrypt-openjdk-uber', licensed under the Apache 2, is distributed with the Google_Api.
@ -268,5 +278,5 @@ Copyright notices related to this dependency can be found in the directory `org.
'threetenbp', licensed under the BSD-3-Clause, is distributed with the Google_Api.
The license information can be found along with the copyright notices.
Copyright notices related to this dependency can be found in the directory `org.threeten.threetenbp-1.6.8`.
Copyright notices related to this dependency can be found in the directory `org.threeten.threetenbp-1.7.0`.

View File

@ -29,7 +29,7 @@
*/
/*
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are

View File

@ -1,69 +0,0 @@
/*
* Copyright 2016 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright 2022 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
Copyright 2017 Google LLC
Copyright 2018 Google LLC
Copyright 2019 Google LLC
Copyright 2020 Google LLC
Copyright 2021 Google LLC

View File

@ -0,0 +1,21 @@
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Copyright 2016 Google LLC
Copyright 2017 Google LLC
Copyright 2018 Google LLC
Copyright 2019 Google LLC
Copyright 2020 Google LLC
Copyright 2021 Google LLC
Copyright 2022 Google LLC
Redistributions of source code must retain the above copyright
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
copyright notice, this list of conditions and the following disclaimer

View File

@ -1,33 +1,3 @@
/*
* Copyright 2017 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright 2023 Google LLC
*
@ -58,6 +28,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Copyright 2017 Google LLC
Copyright 2018 Google LLC
Copyright 2020 Google LLC
@ -65,3 +39,9 @@ Copyright 2020 Google LLC
Copyright 2021 Google LLC
Copyright 2022 Google LLC
Redistributions of source code must retain the above copyright
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
copyright notice, this list of conditions and the following disclaimer

View File

@ -1,15 +0,0 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

View File

@ -1,15 +0,0 @@
Copyright 2015 Google LLC
Copyright 2016 Google LLC
Copyright 2019 Google LLC.
Copyright 2020 Google LLC
Copyright 2021 Google LLC
Copyright 2021 Google LLC.
Copyright 2022 Google LLC
Copyright 2023 Google LLC

View File

@ -32,3 +32,7 @@
Copyright 2016, Google Inc. All rights reserved.
Copyright 2022 Google LLC
Copyright 2024 Google LLC
Copyright 2024, Google Inc. All rights reserved.

View File

@ -50,3 +50,5 @@ Copyright 2022, Google Inc. All rights reserved.
Copyright 2023 Google LLC
Copyright 2023, Google Inc. All rights reserved.
Copyright 2024 Google LLC

View File

@ -30,6 +30,22 @@
* limitations under the License.
*/
/*
* Copyright (C) 2018 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2021 Google Inc.
*
@ -54,6 +70,12 @@ Copyright (C) 2012 Google Inc.
Copyright (C) 2014 Google Inc.
Copyright (C) 2015 Google Inc.
Copyright (C) 2018 The Gson authors
Copyright (C) 2020 Google Inc.
Copyright (C) 2022 Google Inc.
Copyright 2008 Google LLC

View File

@ -60,6 +60,10 @@ Copyright (C) 2020 The Guava Authors
Copyright (C) 2021 The Guava Authors
Copyright (C) 2023 The Guava Authors
Copyright (C) 2024 The Guava Authors
Copyright 2011 Google Inc. All Rights Reserved.
Copyright 2019 The Guava Authors

View File

@ -1,2 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.

View File

@ -1,5 +1,5 @@
Apache Commons Codec
Copyright 2002-2023 The Apache Software Foundation
Copyright 2002-2024 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (https://www.apache.org/).

View File

@ -4,7 +4,7 @@
*/
/**
* Implementation of the MurmurHash2 32-bit and 64-bit hash functions.
* Implements the MurmurHash2 32-bit and 64-bit hash functions.
*
* <p>MurmurHash is a non-cryptographic hash function suitable for general
* hash-based lookup. The name comes from two basic operations, multiply (MU)
@ -34,7 +34,7 @@
*/
/**
* Implementation of the MurmurHash3 32-bit and 128-bit hash functions.
* Implements the MurmurHash3 32-bit and 128-bit hash functions.
*
* <p>
* MurmurHash is a non-cryptographic hash function suitable for general hash-based lookup. The name comes from two basic

View File

@ -33,3 +33,5 @@ Copyright 2021 The gRPC Authors
Copyright 2022 The gRPC Authors
Copyright 2023 The gRPC Authors
Copyright 2024 The gRPC Authors

View File

@ -31,3 +31,5 @@ Copyright 2020 The gRPC Authors
Copyright 2021 The gRPC Authors
Copyright 2023 The gRPC Authors
Copyright 2024 The gRPC Authors

View File

@ -1,17 +0,0 @@
/*
* Copyright 2014 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Copyright 2017 The gRPC Authors

View File

@ -0,0 +1,3 @@
Copyright 2014 The gRPC Authors
Copyright 2017 The gRPC Authors

View File

@ -23,3 +23,5 @@ Copyright 2021 The gRPC Authors
Copyright 2022 The gRPC Authors
Copyright 2023 The gRPC Authors
Copyright 2024 The gRPC Authors

View File

@ -1,38 +1,178 @@
from Standard.Base import all
import Standard.Base.Data.Array_Proxy.Array_Proxy
import Standard.Base.Metadata.Display
import Standard.Base.Errors.Common.Missing_Argument
from Standard.Base.Metadata import make_single_choice, Widget
from Standard.Base.Metadata.Widget import Single_Choice, Vector_Editor
from Standard.Base.Metadata.Choice import Option
from Standard.Base.Metadata.Widget import Single_Choice, Text_Input, Vector_Editor
from Standard.Table import Table
from Standard.Table import Data_Formatter, Table
import Standard.Table.Rows_To_Read.Rows_To_Read
from Standard.Table.Table import from_java_table
import project.Google_Credential.Google_Credential
from project.Internal.Google_Analytics_Internal import all
import project.Google_Analytics_Account.Google_Analytics_Account
import project.Google_Analytics_Account.Google_Analytics_Account_Filter
import project.Google_Analytics_Field.Google_Analytics_Field
import project.Google_Analytics_Property.Google_Analytics_Property
## PRIVATE
make_dimensions_vector_selector : Widget
make_dimensions_vector_selector =
item_editor = make_single_choice ['country', 'date', 'isConversionEvent', 'language', 'userAgeBracket', 'userGender']
Vector_Editor item_editor=item_editor item_default=item_editor.values.first.value display=Display.Always
polyglot java import org.enso.google.GoogleAnalyticsReader
## PRIVATE
make_metrics_vector_selector : Widget
make_metrics_vector_selector =
item_editor = make_single_choice ['activeUsers', 'bounceRate', 'conversions', 'newUsers', 'sessionsPerUser', 'userConversionRate']
Vector_Editor item_editor=item_editor item_default=item_editor.values.first.value display=Display.Always
## GROUP Standard.Base.Input
type Google_Analytics
## GROUP Standard.Base.Input
ICON data_input
Performs google analytics call
This method calls the google reporting v4 api.
Performs Google Analytics call
This method calls the Google Analytics Reporting v4 API.
Arguments:
- property_id: The Google Analytics property_id that is being queried
- start_date: The beginning date of the query. Default is 2020-03-31
- property: The Google Analytics property_id that is being queried
- dimensions: The dimensions being queried. Default is ['country'].
- metrics: The metrics being queried. Default is ['activeUsers'].
- start_date: The beginning date of the query. Default is start of the
current year.
- end_date: The end date being queried. Defaults to today.
@dimensions make_dimensions_vector_selector
@metrics make_metrics_vector_selector
read : Text -> (Vector Text) -> (Vector Text) -> Date -> Date -> Google_Credential -> Table
read property_id:Text dimensions:Vector=['country'] metrics:Vector=['activeUsers'] start_date:Date=(Date.today.previous Date_Period.Year) end_date:Date=Date.today credentials:Google_Credential=Google_Credential.Default -> Table =
- credentials: The Google credentials to use. Default is to use the
Google Application Default Credentials in the environment variables.
See https://cloud.google.com/docs/authentication/application-default-credentials
@property Google_Analytics_Property.default_widget
@dimensions _make_dimensions_vector_selector
@metrics _make_metrics_vector_selector
@start_date _make_start_date_widget
@end_date (Date.default_widget include_today=True)
@credentials Google_Credential.default_widget
read : Google_Analytics_Property -> (Vector Text) -> (Vector Text) -> Date -> Date -> Google_Credential -> Table
read property:Google_Analytics_Property=(Missing_Argument.throw "property") dimensions:Vector=['country'] metrics:Vector=['activeUsers'] start_date:Date=(Date.today.previous ..Year) end_date:Date=Date.today credentials:Google_Credential=..Default -> Table =
case credentials of
Google_Credential.Sample -> read_sample_data dimensions metrics start_date end_date
_ -> read_api_data property_id dimensions metrics start_date end_date credentials
Google_Credential.Sample -> _read_sample_data dimensions metrics start_date end_date
_ ->
java_credentials = credentials.as_java
java_table = _handle_google_error <| GoogleAnalyticsReader.runReport java_credentials property.java_record start_date end_date dimensions metrics
java_table.if_not_error <|
formatter = Data_Formatter.Value.with_datetime_formats date_formats=["yyyyMMdd"]
from_java_table java_table . parse format=formatter
## ICON data_input
Reads the set of accounts from Google Analytics Admin API.
Arguments:
- credentials: The Google credentials to use. Default is to use the
Google Application Default Credentials in the environment variables.
See https://cloud.google.com/docs/authentication/application-default-credentials
- limit: The maximum number of accounts to read. Default is 1000.
- include_deleted: Whether to include deleted accounts. Default is false.
@credentials Google_Credential.default_widget
@limit Rows_To_Read.default_widget
list_accounts : Google_Credential -> Rows_To_Read -> Boolean -> Vector
list_accounts credentials:Google_Credential=..Default (limit : Rows_To_Read = ..First_With_Warning 1000) include_deleted:Boolean=False -> Vector =
java_credentials = credentials.as_java
to_read = limit.rows_to_read.if_nothing 0
array = _handle_google_error <| GoogleAnalyticsReader.listAccounts java_credentials to_read include_deleted
array.if_not_error <|
vector = array.map a-> Google_Analytics_Account.Value a
limit.attach_warning_vector vector
## ICON data_input
Reads the set of properties from Google Analytics Admin API.
Arguments:
- account: The Google Analytics account(s) to read properties from or all
accounts. Default is all accounts.
- credentials: The Google credentials to use. Default is to use the
Google Application Default Credentials in the environment variables.
See https://cloud.google.com/docs/authentication/application-default-credentials
- limit: The maximum number of accounts to read. Default is 1000.
- include_deleted: Whether to include deleted accounts. Default is false.
@account Google_Analytics_Account_Filter.default_widget
@credentials Google_Credential.default_widget
@limit Rows_To_Read.default_widget
list_properties : Google_Analytics_Account_Filter -> Google_Credential -> Rows_To_Read -> Boolean -> Vector
list_properties account:Google_Analytics_Account_Filter=..All_Accounts credentials:Google_Credential=..Default (limit : Rows_To_Read = ..First_With_Warning 1000) include_deleted:Boolean=False -> Vector =
java_credentials = credentials.as_java
to_read = limit.rows_to_read.if_nothing 0
filter = account.as_java
array = _handle_google_error <| GoogleAnalyticsReader.listProperties java_credentials filter to_read include_deleted
array.if_not_error <|
vector = array.map a-> Google_Analytics_Property.Value a
limit.attach_warning_vector vector
## ICON data_input
Reads the set of metrics from Google Analytics for a property.
Arguments:
- property: The Google Analytics property to read metrics from.
- credentials: The Google credentials to use. Default is to use the
Google Application Default Credentials in the environment variables.
See https://cloud.google.com/docs/authentication/application-default-credentials
@property Google_Analytics_Property.default_widget
@credentials Google_Credential.default_widget
list_metrics : Google_Analytics_Property -> Google_Credential -> Vector
list_metrics property:Google_Analytics_Property=(Missing_Argument.throw "property") credentials:Google_Credential=..Default -> Vector =
java_credentials = credentials.as_java
array = _handle_google_error <| GoogleAnalyticsReader.listMetrics java_credentials property.java_record
array.if_not_error <| array.map record-> Google_Analytics_Field.Metric record
## ICON data_input
Reads the set of dimensions from Google Analytics for a property.
Arguments:
- property: The Google Analytics property to read metrics from.
- credentials: The Google credentials to use. Default is to use the
Google Application Default Credentials in the environment variables.
See https://cloud.google.com/docs/authentication/application-default-credentials
@property Google_Analytics_Property.default_widget
@credentials Google_Credential.default_widget
list_dimensions : Google_Analytics_Property -> Google_Credential -> Vector
list_dimensions property:Google_Analytics_Property=(Missing_Argument.throw "property") credentials:Google_Credential=..Default -> Vector =
java_credentials = credentials.as_java
array = _handle_google_error <| GoogleAnalyticsReader.listDimensions java_credentials property.java_record
array.if_not_error <| array.map record-> Google_Analytics_Field.Dimension record
## PRIVATE
private _make_metrics_vector_selector self_arg cache -> Widget =
_ = self_arg
items = Panic.catch Any handler=p->[p.payload.to_display_text] <|
property = cache.if_not_nothing <| cache "property"
property.if_not_nothing <|
credentials = cache.if_not_nothing <| cache "credentials"
Google_Analytics.list_metrics property credentials . map f-> Option (f.apiName + " (" + f.category + ")") f.apiName.pretty
item_editor = make_single_choice (items.if_nothing ['activeUsers', 'bounceRate', 'conversions', 'newUsers', 'sessionsPerUser', 'userConversionRate'])
Vector_Editor item_editor=item_editor item_default=item_editor.values.first.value display=..Always
## PRIVATE
private _make_dimensions_vector_selector self_arg cache -> Widget =
_ = self_arg
items = Panic.catch Any handler=p->[p.payload.to_display_text] <|
property = cache.if_not_nothing <| cache "property"
property.if_not_nothing <|
credentials = cache.if_not_nothing <| cache "credentials"
Google_Analytics.list_dimensions property credentials . map f-> Option (f.api_name + " (" + f.category + ")") f.api_name.pretty
item_editor = make_single_choice (items.if_nothing ['country', 'year', 'month', 'date', 'userAgeBracket', 'userGender'])
Vector_Editor item_editor=item_editor item_default=item_editor.values.first.value display=..Always
## PRIVATE
private _make_start_date_widget -> Widget =
options = [Option "<Fixed Date>" "Date.new", Option "<Start of Period>" "Date.today.previous"]
Widget.Single_Choice values=options display=..When_Modified
## PRIVATE
private _read_sample_data dimensions:Vector metrics:Vector start_date:Date end_date:Date -> Table =
_ = [dimensions, metrics, start_date, end_date]
Data.read ((Project_Description.new Standard.Google_Api . data) / "Google_Analytics_Sample.csv") (..Delimited value_formatter=Standard.Base.Nothing)
## PRIVATE
private _handle_google_error ~action =
Panic.catch Any action handler=c->
payload = c.payload
Error.throw (Google_Analytics_Error.Value payload.getMessage payload)
## PRIVATE
type Google_Analytics_Error
## PRIVATE
private Value message:Text payload
## PRIVATE
to_text : Text
to_text self = "Error: " + self.message
## PRIVATE
to_display_text : Text
to_display_text self = self.to_text

View File

@ -0,0 +1,109 @@
from Standard.Base import all
from Standard.Base.Metadata import make_single_choice, Widget
from Standard.Base.Metadata.Choice import Option
from Standard.Base.Metadata.Widget import Text_Input, Vector_Editor
import Standard.Table.Rows_To_Read.Rows_To_Read
import project.Google_Analytics.Google_Analytics
import project.Google_Credential.Google_Credential
polyglot java import org.enso.google.GoogleAnalyticsReader.AnalyticsAccount
## Type describing a Google Analytics account.
type Google_Analytics_Account
private Value java_record
## Account ID.
id : Text
id self = self.java_record.id
## Account display name.
name : Text
name self = self.java_record.displayName
## Account creation time.
create_time : Date_Time
create_time self = self.java_record.created
## Account region code.
region_code : Text
region_code self = self.java_record.regionCode
## Has the account been deleted?
is_deleted : Boolean
is_deleted self = self.java_record.deleted
## PRIVATE
to_text : Text
to_text self = "Google_Analytics_Account " + self.name + " (" + self.id + ")"
## PRIVATE
to_display_text : Text
to_display_text self = "GA Account {" + self.name + " (" + self.id + ")}"
## ICON data_input
List of all properties of the account.
Arguments:
- credentials: The Google credentials to use. Default is the default
credentials.
- limit: The maximum number of accounts to read. Default is 1000.
- include_deleted: Whether to include deleted accounts. Default is false.
@credentials Google_Credential.default_widget
@limit Rows_To_Read.default_widget
properties : Google_Credential -> Rows_To_Read -> Boolean -> Vector
properties self credential:Google_Credential=..Default (limit : Rows_To_Read = ..First_With_Warning 1000) include_deleted:Boolean=False =
Google_Analytics.list_properties self credential limit include_deleted
## Filter for Google Analytics accounts.
type Google_Analytics_Account_Filter
All_Accounts
## Filter to a single account
@account (Text_Input display=..Always)
Account account:Text|Google_Analytics_Account
## Filter to set of accounts
@accounts (Vector_Editor item_editor=Text_Input item_default="''")
Accounts accounts:Vector
## PRIVATE
default_widget : Any -> Any -> Widget
default_widget self_arg cache =
_ = self_arg
default = [Option "<All>" "..All_Accounts", Option "<Account>" "..Account", Option "<Multiple Accounts>" "..Accounts"]
Panic.catch Any handler=_->(make_single_choice default) <|
credentials = cache.if_not_nothing <| cache "credentials"
options = Google_Analytics.list_accounts credentials=(credentials.if_nothing Google_Credential.Default) limit=(..First 10) . map p->(Option (p.name + " (" + p.id + ")") "..Account "+p.id.pretty)
make_single_choice default+options display=..Always
## PRIVATE
private as_java self -> Array | Nothing = case self of
Google_Analytics_Account_Filter.All_Accounts -> Nothing
Google_Analytics_Account_Filter.Account acc -> case acc of
_ : Google_Analytics_Account -> [acc.java_record].to_array
_ : Text -> [_create_analytics_account_from_text acc].to_array
Google_Analytics_Account_Filter.Accounts accounts ->
vec = accounts.map acc-> case acc of
_ : Google_Analytics_Account -> acc.java_record
_ : Text -> _create_analytics_account_from_text acc
vec.to_array
## PRIVATE
Creates a Google Analytics account from a text ID.
Most values are defaulted.
private _create_analytics_account_from_text account:Text -> AnalyticsAccount =
id = if account.starts_with "accounts/" then account else "accounts/" + account
display = id.replace (regex "^accounts/") ""
AnalyticsAccount.new id display False Date_Time.now Nothing
## PRIVATE
Google_Analytics_Account_Filter.from (that:Google_Analytics_Account) = Google_Analytics_Account_Filter.Account that
## PRIVATE
Google_Analytics_Account_Filter.from (that:Text) = Google_Analytics_Account_Filter.Account that
## PRIVATE
Google_Analytics_Account_Filter.from (that:Vector) = Google_Analytics_Account_Filter.Accounts that

View File

@ -0,0 +1,35 @@
from Standard.Base import all
## Type describing a Google Analytics dimension or metric.
type Google_Analytics_Field
private Dimension java_record
private Metric java_record
## Dimension API Name.
api_name : Text
api_name self = self.java_record.apiName
## Dimension display name.
name : Text
name self = self.java_record.displayName
## Dimension category.
category : Text
category self = self.java_record.category
## Dimension description.
description : Text
description self = self.java_record.description
## PRIVATE
to_text : Text
to_text self = case self of
Google_Analytics_Field.Dimension _ -> self.api_name + " (Dimension)"
Google_Analytics_Field.Metric _ -> self.api_name + " (Metric)"
## PRIVATE
to_display_text : Text
to_display_text self = case self of
Google_Analytics_Field.Dimension _ -> "GA Dimension { " + self.api_name + " (" + self.category + ")}"
Google_Analytics_Field.Metric _ -> "GA Metric { " + self.api_name + " (" + self.category + ")}"

View File

@ -0,0 +1,90 @@
from Standard.Base import all
import Standard.Base.Errors.Illegal_Argument.Illegal_Argument
from Standard.Base.Metadata import make_single_choice, Widget
from Standard.Base.Metadata.Choice import Option
import project.Google_Analytics.Google_Analytics
import project.Google_Credential.Google_Credential
polyglot java import org.enso.google.GoogleAnalyticsReader.AnalyticsProperty
## Type describing a Google Analytics property.
type Google_Analytics_Property
private Value java_record
## Property ID.
id : Text
id self = self.java_record.id
## Property display name.
name : Text
name self = self.java_record.displayName
## Property creation time.
create_time : Date_Time
create_time self = self.java_record.created
## Parent account
account : Text
account self = self.java_record.account
## Property currency.
currency : Text
currency self = self.java_record.currency
## Property time zone.
time_zone : Time_Zone
time_zone self = self.java_record.timeZone
## PRIVATE
to_text : Text
to_text self = "Google Analytics Property: " + self.name + " (" + self.id + ")"
## PRIVATE
to_display_text : Text
to_display_text self = self.to_text
## ICON data_input
List of all metrics of the property.
Arguments:
- credentials: The Google credentials to use. Default is the default
credentials.
metrics : Google_Credential -> Vector
metrics self credentials:Google_Credential=..Default =
Google_Analytics.list_metrics self credentials
## ICON data_input
List of all dimensions of the property.
Arguments:
- credentials: The Google credentials to use. Default is the default
credentials.
dimensions : Google_Credential -> Vector
dimensions self credentials:Google_Credential=..Default =
Google_Analytics.list_dimensions self credentials
## PRIVATE
default_widget : Any -> Any -> Widget
default_widget self_arg cache =
_ = self_arg
Panic.catch Any handler=_->(Widget.Text_Input display=..Always) <|
credentials = cache.if_not_nothing <| cache "credentials"
options = Google_Analytics.list_properties account=..All_Accounts credentials=(credentials.if_nothing Google_Credential.Default) limit=(..First 10) . map p->(Option (p.name + " (" + p.id + ")") p.id.pretty)
make_single_choice options display=..Always
## PRIVATE
Google_Analytics_Property.from (that:Text) =
id = if that.starts_with "properties/" then that else "properties/" + that
display = id.replace (regex "^properties/") ""
java_value = AnalyticsProperty.new id display False Date_Time.now "XXX" "XXX" Nothing
Google_Analytics_Property.Value java_value
## PRIVATE
Google_Analytics_Property.from (that:Vector) =
if that.length != 1 then Error.throw (Illegal_Argument.Error "Expected exactly one property ID.") else
first = that.first
case first of
_ : Text -> Google_Analytics_Property.from first
_ : Google_Analytics_Property -> first
_ -> Error.throw (Illegal_Argument.Error "Expected a property ID or a property.")

View File

@ -1,19 +1,56 @@
from Standard.Base import all
from Standard.Base.Metadata import make_single_choice, Widget
import Standard.Base.Errors.Common.Missing_Argument
from Standard.Base.Metadata import make_single_choice, Choice, Widget
from Standard.Base.Metadata.Choice import Option
polyglot java import com.google.api.gax.core.CredentialsProvider
polyglot java import com.google.api.gax.core.FixedCredentialsProvider
polyglot java import com.google.auth.oauth2.GoogleCredentials
type Google_Credential
## ICON key
Creates a Google credential either from a json file or the default environment variables.
Arguments:
- file: Path to the json credentials file or `Nothing` for the default.
@file (make_single_choice [Choice.Option "File" "File.new", Choice.Option "Default" "Nothing"])
new : File | Nothing -> Google_Credential
new file:(File | Nothing)=Nothing = case file of
_ : File -> Google_Credential.From_File file
Nothing -> Google_Credential.Default
## ICON key
Access using a json credentials file downloaded from your Google account.
Arguments:
- file: Path to the json credentials file.
From_File file:File
From_File file:File=(Missing_Argument.throw "file")
## ICON key
Access using the defaults provided by the environment variables.
Default
## ICON key
Feeding this into supporting components will give sample data for that commponent.
Feeding this into supporting components will give sample data for that component.
Sample
## PRIVATE
Gets the Java version of the credentials.
private as_java self -> CredentialsProvider | Nothing = case self of
Google_Credential.From_File file ->
google_credentials = file.with_input_stream [File_Access.Read] stream->
stream.with_java_stream is->
GoogleCredentials.fromStream is
FixedCredentialsProvider.create google_credentials
Google_Credential.Default -> Nothing
## PRIVATE
default_widget : Widget
default_widget =
make_single_choice [Option "File" "..From_File", Option "Default" "..Default"]
## PRIVATE
Google_Credential.from (that:File) = Google_Credential.From_File that
## PRIVATE
Google_Credential.from (that:Text) = Google_Credential.From_File (File.new that)

View File

@ -1,55 +0,0 @@
private
from Standard.Base import all
import Standard.Base.Runtime.Managed_Resource.Managed_Resource
from Standard.Table import Table
import project.Google_Credential.Google_Credential
from project.Internal.Google_Credential_Internal import all
polyglot java import com.google.analytics.data.v1beta.BetaAnalyticsDataClient
polyglot java import com.google.analytics.data.v1beta.BetaAnalyticsDataSettings
polyglot java import com.google.analytics.data.v1beta.DateRange
polyglot java import com.google.analytics.data.v1beta.Dimension
polyglot java import com.google.analytics.data.v1beta.Metric
polyglot java import com.google.analytics.data.v1beta.RunReportRequest
read_api_data property_id:Text dimensions:Vector metrics:Vector start_date:Date end_date:Date credentials:Google_Credential -> Table =
managed_analytics_data = case credentials of
Google_Credential.Default -> Managed_Resource.register (BetaAnalyticsDataClient.create) r-> r.close
Google_Credential.From_File _ ->
betaAnalyticsDataSettings = BetaAnalyticsDataSettings.newBuilder
. setCredentialsProvider credentials.as_java
. build
Managed_Resource.register (BetaAnalyticsDataClient.create betaAnalyticsDataSettings) r-> r.close
request_builder = RunReportRequest.newBuilder
. setProperty ("properties/"+property_id)
. addDateRanges (DateRange.newBuilder.setStartDate start_date.to_text . setEndDate end_date.to_text)
dimensions.distinct.each dimension->
request_builder.addDimensions (Dimension.newBuilder.setName dimension)
metrics.distinct.each metric->
request_builder.addMetrics (Metric.newBuilder.setName metric)
request = request_builder.build
response = managed_analytics_data.with (analytics_data-> analytics_data.runReport request)
managed_analytics_data.finalize
dimension_count = response.getDimensionHeadersCount
dimension_headers = 0.up_to dimension_count . map i-> response.getDimensionHeaders i . getName
metric_count = response.getMetricHeadersCount
metric_headers = 0.up_to metric_count . map i-> response.getMetricHeaders i . getName
headers = dimension_headers + metric_headers
row_count = response.getRowCount
rows = Vector.new row_count i->
row = response.getRows i
dimension_values = 0.up_to dimension_count . map i-> row.getDimensionValues i . getValue
metric_values = 0.up_to metric_count . map i-> row.getMetricValues i . getValue
dimension_values + metric_values
Table.from_rows headers rows
read_sample_data dimensions:Vector metrics:Vector start_date:Date end_date:Date -> Table =
_ = [dimensions, metrics, start_date, end_date]
Data.read ((Project_Description.new Standard.Google_Api . data) / "Google_Analytics_Sample.csv") (..Delimited value_formatter=Standard.Base.Nothing)

View File

@ -1,17 +0,0 @@
private
from Standard.Base import all
from project.Google_Credential import all
polyglot java import com.google.api.gax.core.CredentialsProvider
polyglot java import com.google.api.gax.core.FixedCredentialsProvider
polyglot java import com.google.auth.oauth2.GoogleCredentials
Google_Credential.as_java : CredentialsProvider
Google_Credential.as_java self = case self of
Google_Credential.From_File file ->
google_credentials = file.with_input_stream [File_Access.Read] stream->
stream.with_java_stream is->
GoogleCredentials.fromStream is
FixedCredentialsProvider.create google_credentials
Google_Credential.Default -> Nothing

View File

@ -1,4 +1,4 @@
export project.Google_Analytics
export project.Google_Analytics.Google_Analytics
export project.Google_Credential.Google_Credential
export project.Google_Sheets.Google_Sheets

View File

@ -247,6 +247,9 @@ type Data_Formatter
## PRIVATE
get_specific_type_parsers self =
## Have to do date parsing first to allow for pure numeric formats.
date_parsers = [self.make_date_time_parser, self.make_date_parser, self.make_time_of_day_parser]
try_us_parsers_first = self.decimal_point == Auto && self.thousand_separator != "."
preferred_auto_parsers = case try_us_parsers_first of
## If we are in auto mode, we will first try parsing US integers,
@ -264,8 +267,8 @@ type Data_Formatter
## However, if the `decimal_point` is set to something else,
we don't do auto inference, so this extra logic is not needed.
False -> []
remaining_parsers = [self.make_integer_parser auto_mode=True, self.make_decimal_parser auto_mode=True, self.make_date_time_parser, self.make_date_parser, self.make_time_of_day_parser, self.make_boolean_parser]
parsers = preferred_auto_parsers + remaining_parsers
remaining_parsers = [self.make_integer_parser auto_mode=True, self.make_decimal_parser auto_mode=True, self.make_boolean_parser]
parsers = date_parsers + preferred_auto_parsers + remaining_parsers
## Unfortunately, the [] literal allows to create a vector containing
dataflow errors. That is not handled well later by Polyglot. So we
ensure all errors surface here.

View File

@ -36,6 +36,13 @@ type Rows_To_Read
Rows_To_Read.First rows -> rows
Rows_To_Read.First_With_Warning rows -> rows
## PRIVATE
attach_warning_vector self input:Vector -> Vector = case self of
Rows_To_Read.First_With_Warning rows -> if input.length <= rows then input else
Problem_Behavior.Report_Warning.attach_problem_after (input.take (..First rows)) <|
Not_All_Rows_Downloaded.Warning rows
_ -> input
## PRIVATE
attach_warning self input:Table -> Table = case self of
Rows_To_Read.First_With_Warning rows -> if input.row_count <= rows then input else

View File

@ -3877,3 +3877,7 @@ make_fill_nothing_default_widget table cache=Nothing =
real_columns = table.columns_helper.select_columns columns case_sensitivity=..Sensitive reorder=False error_on_missing_columns=False on_problems=..Ignore error_on_empty=False
if real_columns.length == 0 then [Value_Type.Mixed] else real_columns.map .value_type
Widget_Helpers.make_fill_default_value_selector table value_types=types
## PRIVATE
Helper method for internal use to make a Table from a Java Table.
from_java_table java_table = Table.Value java_table

View File

@ -0,0 +1,310 @@
package org.enso.google;
import com.google.analytics.admin.v1beta.AnalyticsAdminServiceClient;
import com.google.analytics.admin.v1beta.AnalyticsAdminServiceSettings;
import com.google.analytics.admin.v1beta.ListAccountsRequest;
import com.google.analytics.admin.v1beta.ListPropertiesRequest;
import com.google.analytics.data.v1beta.BetaAnalyticsDataClient;
import com.google.analytics.data.v1beta.BetaAnalyticsDataSettings;
import com.google.analytics.data.v1beta.DateRange;
import com.google.analytics.data.v1beta.Dimension;
import com.google.analytics.data.v1beta.GetMetadataRequest;
import com.google.analytics.data.v1beta.Metadata;
import com.google.analytics.data.v1beta.Metric;
import com.google.analytics.data.v1beta.RunReportRequest;
import com.google.api.gax.core.CredentialsProvider;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.stream.IntStream;
import org.enso.table.data.column.builder.Builder;
import org.enso.table.data.column.builder.StringBuilder;
import org.enso.table.data.column.storage.type.TextType;
import org.enso.table.data.table.Column;
import org.enso.table.data.table.Table;
public class GoogleAnalyticsReader {
private static final Map<String, Metadata> metadataCache = new HashMap<>();
public record AnalyticsAccount(
String id, String displayName, boolean deleted, ZonedDateTime created, String regionCode) {}
public record AnalyticsProperty(
String id,
String displayName,
boolean deleted,
ZonedDateTime created,
String account,
String currency,
TimeZone timeZone) {}
public record AnalyticDimension(
String apiName, String displayName, String category, String description) {}
private static AnalyticsAdminServiceClient createAdminClient(
CredentialsProvider credentialsProvider) throws IOException {
if (credentialsProvider == null) {
// Default Credentials Path
return AnalyticsAdminServiceClient.create();
}
var settings =
AnalyticsAdminServiceSettings.newBuilder()
.setCredentialsProvider(credentialsProvider)
.build();
return AnalyticsAdminServiceClient.create(settings);
}
private static BetaAnalyticsDataClient createDataClient(CredentialsProvider credentialsProvider)
throws IOException {
if (credentialsProvider == null) {
// Default Credentials Path
return BetaAnalyticsDataClient.create();
}
var settings =
BetaAnalyticsDataSettings.newBuilder().setCredentialsProvider(credentialsProvider).build();
return BetaAnalyticsDataClient.create(settings);
}
/** Lists all Google Analytics accounts. */
public static AnalyticsAccount[] listAccounts(
CredentialsProvider credentialsProvider, int limit, boolean includeDeleted)
throws IOException {
int pageSize = getPageSize(limit);
var request =
ListAccountsRequest.newBuilder()
.setPageSize(pageSize)
.setShowDeleted(includeDeleted)
.build();
try (var client = createAdminClient(credentialsProvider)) {
var response = client.listAccounts(request);
var output = new ArrayList<AnalyticsAccount>(pageSize);
for (var page : response.iteratePages()) {
for (var account : page.iterateAll()) {
var ensoAccount =
new AnalyticsAccount(
account.getName(),
account.getDisplayName(),
account.getDeleted(),
Instant.ofEpochSecond(
account.getCreateTime().getSeconds(), account.getCreateTime().getNanos())
.atZone(ZoneId.systemDefault()),
account.getRegionCode());
output.add(ensoAccount);
if (limit != 0 && output.size() == limit) {
break;
}
}
}
return output.toArray(new AnalyticsAccount[0]);
}
}
private static int getPageSize(int limit) {
return (limit == 0 || limit > 1000) ? 1000 : limit;
}
/**
* Lists all properties of a given account.
*
* @param credentialsProvider the credentials provider
* @param parents the parent accounts or null for all properties (e.g. "accounts/123" for account
* with ID 123)
* @param limit the maximum number of properties to return (0 for all properties, up to 1000)
* @param includeDeleted whether to include deleted properties
* @return an array of properties
*/
public static AnalyticsProperty[] listProperties(
CredentialsProvider credentialsProvider,
AnalyticsAccount[] parents,
int limit,
boolean includeDeleted)
throws IOException {
if (parents == null) {
parents = listAccounts(credentialsProvider, 0, false);
}
if (parents.length == 0) {
return new AnalyticsProperty[0];
}
int pageSize = getPageSize(limit);
var output = new ArrayList<AnalyticsProperty>(pageSize);
try (var client = createAdminClient(credentialsProvider)) {
for (var parent : parents) {
var request =
ListPropertiesRequest.newBuilder()
.setPageSize(pageSize)
.setShowDeleted(includeDeleted)
.setFilter("parent: " + parent.id());
var response = client.listProperties(request.build());
for (var page : response.iteratePages()) {
for (var property : page.iterateAll()) {
var ensoProperty =
new AnalyticsProperty(
property.getName(),
property.getDisplayName(),
property.hasDeleteTime(),
Instant.ofEpochSecond(
property.getCreateTime().getSeconds(),
property.getCreateTime().getNanos())
.atZone(ZoneId.systemDefault()),
property.getAccount(),
property.getCurrencyCode(),
TimeZone.getTimeZone(property.getTimeZone()));
output.add(ensoProperty);
}
}
}
return output.toArray(new AnalyticsProperty[0]);
}
}
/**
* Lists all metrics available in a Google Analytics property.
*
* @param credentialsProvider the credentials provider (null for default credentials)
* @param property the property to list metrics for
* @return an array of metrics
*/
public static AnalyticDimension[] listMetrics(
CredentialsProvider credentialsProvider, AnalyticsProperty property) throws IOException {
var metadata = getMetadata(credentialsProvider, property.id());
return metadata.getMetricsList().stream()
.map(
metric ->
new AnalyticDimension(
metric.getApiName(),
metric.getUiName(),
metric.getCategory(),
metric.getDescription()))
.toArray(AnalyticDimension[]::new);
}
/**
* Lists all dimensions available in Google Analytics.
*
* @return an array of dimensions
*/
public static AnalyticDimension[] listDimensions(
CredentialsProvider credentialsProvider, AnalyticsProperty property) throws IOException {
var metadata = getMetadata(credentialsProvider, property.id());
return metadata.getDimensionsList().stream()
.map(
dimension ->
new AnalyticDimension(
dimension.getApiName(),
dimension.getUiName(),
dimension.getCategory(),
dimension.getDescription()))
.toArray(AnalyticDimension[]::new);
}
/** Caches metadata requests for Google Analytics properties. */
private static synchronized Metadata getMetadata(
CredentialsProvider credentialsProvider, String propertyId) throws IOException {
if (metadataCache.containsKey(propertyId)) {
return metadataCache.get(propertyId);
}
var request = GetMetadataRequest.newBuilder().setName(propertyId + "/metadata").build();
try (var client = createDataClient(credentialsProvider)) {
var metadata = client.getMetadata(request);
metadataCache.put(propertyId, metadata);
return metadata;
}
}
/** Clears the metadata cache. */
public static void clearMetadataCache() {
metadataCache.clear();
}
/**
* Runs a report in Google Analytics.
*
* @param credentialsProvider the credentials provider
* @param property the property to run the report on
* @param startDate the start date of the report
* @param endDate the end date of the report
* @param dimensions the dimensions to include in the report
* @param metrics the metrics to include in the report
* @return a Table with the report data
*/
public static Table runReport(
CredentialsProvider credentialsProvider,
AnalyticsProperty property,
LocalDate startDate,
LocalDate endDate,
List<String> dimensions,
List<String> metrics)
throws IOException {
var dateRange =
DateRange.newBuilder()
.setStartDate(startDate.format(DateTimeFormatter.ISO_LOCAL_DATE))
.setEndDate(endDate.format(DateTimeFormatter.ISO_LOCAL_DATE))
.build();
var request =
RunReportRequest.newBuilder()
.setProperty(property.id())
.addDateRanges(dateRange)
.addAllDimensions(
dimensions.stream().map(n -> Dimension.newBuilder().setName(n).build()).toList())
.addAllMetrics(
metrics.stream().map(n -> Metric.newBuilder().setName(n).build()).toList())
.build();
try (var client = createDataClient(credentialsProvider)) {
var response = client.runReport(request);
int rowCount = response.getRowCount();
var builders = new Builder[dimensions.size() + metrics.size()];
for (int i = 0; i < dimensions.size() + metrics.size(); i++) {
builders[i] = new StringBuilder(rowCount, TextType.VARIABLE_LENGTH);
}
// Load the data
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < dimensions.size(); col++) {
builders[col].append(response.getRows(row).getDimensionValues(col).getValue());
}
for (int col = 0; col < metrics.size(); col++) {
builders[dimensions.size() + col].append(
response.getRows(row).getMetricValues(col).getValue());
}
}
// Convert to Java Table
var columns =
IntStream.range(0, builders.length)
.mapToObj(
i ->
new Column(
i < dimensions.size()
? dimensions.get(i)
: metrics.get(i - dimensions.size()),
builders[i].seal()))
.toArray(Column[]::new);
return new Table(columns);
}
}
}

View File

@ -124,6 +124,7 @@ spec_with suite_builder name create_new_datetime parse_datetime nanoseconds_loss
create_new_datetime 1970 . pretty . should_equal "Date_Time.new 1970 1 1"
create_new_datetime 1923 9 24 . pretty . should_equal "Date_Time.new 1923 9 24"
create_new_datetime 1923 9 24 12 20 44 . pretty . should_equal "Date_Time.new 1923 9 24 12 20 44"
create_new_datetime 1923 9 24 12 0 44 . pretty . should_equal "Date_Time.new 1923 9 24 12 second=44"
if nanoseconds_loss_in_precision.not then
create_new_datetime 1923 9 24 12 20 nanosecond=500000000 . pretty . should_equal "Date_Time.new 1923 9 24 12 20 millisecond=500"
create_new_datetime 1923 9 24 12 20 nanosecond=500000 . pretty . should_equal "Date_Time.new 1923 9 24 12 20 microsecond=500"

View File

@ -626,6 +626,23 @@ add_specs suite_builder =
r8.to_vector . should_equal [Nothing, Nothing, Nothing]
Problems.assume_no_problems r8
group_builder.specify "should be able to parse numeric date formats with a Data_Formatter" <|
formatter = Data_Formatter.Value . with_datetime_formats date_formats=["yyyyMMdd"]
c1 = Column.from_vector "A" ["20241018", "20240315", "20240917"]
r1 = c1.parse format=formatter
r1.value_type.should_equal Value_Type.Date
r1.to_vector.should_equal [Date.new 2024 10 18, Date.new 2024 3 15, Date.new 2024 9 17]
r1b = c1.parse
r1b.value_type.should_equal Value_Type.Integer
r1b.to_vector.should_equal [20241018, 20240315, 20240917]
c2 = Column.from_vector "A" ["20241018", "2024", "20240917"]
r2 = c2.parse format=formatter
r2.value_type.should_equal Value_Type.Integer
r2.to_vector.should_equal [20241018, 2024, 20240917]
group_builder.specify "should error if invalid target type is provided" <|
c1 = Column.from_vector "A" ["1", "2", "3"]
Test.expect_panic Type_Error (c1.parse type=Nothing)

View File

@ -0,0 +1 @@
Copyright 2024 Google LLC

View File

@ -0,0 +1 @@
Copyright 2024 Google LLC

View File

@ -1,27 +0,0 @@
Copyright 2016, Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,27 +0,0 @@
Copyright 2016, Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,2 +1,2 @@
Copyright 2016 Google LLC
Copyright 2023 Google LLC
Copyright 2024 Google LLC

View File

@ -1,5 +0,0 @@
Copyright 2017 Google LLC
Copyright 2018 Google LLC
Copyright 2019 Google LLC
Copyright 2020 Google LLC
Copyright 2021 Google LLC

View File

@ -1,2 +0,0 @@
Copyright 2016 Google LLC
Copyright 2022 Google LLC

View File

@ -1,27 +0,0 @@
Copyright 2016, Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,4 +1,11 @@
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Redistributions of source code must retain the above copyright
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Copyright 2016 Google LLC
Copyright 2017 Google LLC
Copyright 2018 Google LLC
Copyright 2019 Google LLC
Copyright 2020 Google LLC
Copyright 2021 Google LLC
Copyright 2022 Google LLC
copyright notice, this list of conditions and the following disclaimer
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Redistributions of source code must retain the above copyright

View File

@ -1,4 +0,0 @@
Copyright 2018 Google LLC
Copyright 2020 Google LLC
Copyright 2021 Google LLC
Copyright 2022 Google LLC

View File

@ -1,2 +0,0 @@
Copyright 2017 Google LLC
Copyright 2023 Google LLC

View File

@ -1,27 +0,0 @@
Copyright 2016, Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,4 +1,9 @@
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Copyright 2017 Google LLC
Copyright 2018 Google LLC
Copyright 2020 Google LLC
Copyright 2021 Google LLC
Copyright 2022 Google LLC
Redistributions of source code must retain the above copyright
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
copyright notice, this list of conditions and the following disclaimer

Some files were not shown because too many files have changed in this diff Show More