Skip to content

Conversation

LiamMcFall
Copy link
Contributor

Description

This PR creates the basis of what we need to target 14 day inactive windows 10 firefox users.

Related Tickets & Documents

Reviewer, please follow this checklist

@LiamMcFall LiamMcFall self-assigned this Sep 22, 2025
@LiamMcFall
Copy link
Contributor Author

I need to be able to to query moz-fx-data-shared-prod.accounts_db_external.fxa_emails_v1 in order to get the email addresses for FX accounts that don't already have an existing Braze user associated with it. As such, I can't currently run this query in full until I have that access.

@LiamMcFall
Copy link
Contributor Author

I will open a ticket to get myself access to workgroup:accounts-confidential so that I can get this query fully tested/productionalized.

@dataops-ci-bot

This comment has been minimized.

@LiamMcFall LiamMcFall changed the title feat: build win10 user targeting for braze [DO NOT MERGE]feat: build win10 user targeting for braze Sep 25, 2025
@dataops-ci-bot

This comment has been minimized.

@dataops-ci-bot

This comment has been minimized.

@dataops-ci-bot

This comment has been minimized.

@LiamMcFall
Copy link
Contributor Author

@chelseybeck

OKAY! I have made some changes.

Ultimately while I don't think we need an intermediate table, I decided that I would like to have one to separate the steps of what is happening:

  1. braze_derived.fxa_win10_users_daily_v1 looks at a single day based on submission date and builds the list of windows 10 users who have been inactive for 14 days. I removed the previous logic that looked at 14-21 days since this will likely run for multiple days before the first email is sent. Looking at a bigger window of days would just make the table less efficient to build on subsequent runs. This table will only have the inactive users for the most recent submission date.

  2. braze_derived.fxa_win10_users_historical_v1 will be our table that contains ALL users who have been added to the list. It will be partitioned by submission date and each day will look at braze_derived.fxa_win10_users_daily_v1 and add any new users to the list that are not already contained in the table based on their FxA id. This table will be our historical record of all users who will have been added to the email group. It also generates external ids for any users that do not already have one. If a user reactivates and then goes inactive for 14 days at any point they will still only show up in this table the FIRST time they go inactive. If we get approval for follow up emails, this logic can be adjusted. Additionally, this table is currently storing only locale en-US as that is the only locale we want to sync while doing IP warming. As we approach launch date for the full campaign, October 14 2025, we will add in the rest of the desired locales.

  3. braze_external.win10_users_sync_v1 will be the table that actually gets synced into Braze. Each day it will be overwritten with the users who have been added to braze_derived.fxa_win10_users_historical_v1 for that submission date.

The daily and historical tables could hypothetically be a single table, but I like the separation of their functions. I think it also allows us more flexibility in terms of what we will need to change if approval is granted to send follow up emails.

@LiamMcFall
Copy link
Contributor Author

  • braze_derived.test_fxa_win10_users_daily_v1
  • braze_derived.test_fxa_win10_users_historical_v1
  • braze_external.test_win10_users_sync_v1

The above tables can all be view in BQ. I ran a few days worth of backfill and made sure that we did not have duplicate in the historical table. test_fxa_win10_users_daily_v1 and test_win10_users_sync_v1 will be as of 9/29 submission date, and test_fxa_win10_users_historical_v1 has data for 9/27-9/29.

@LiamMcFall LiamMcFall requested a review from chelseybeck October 1, 2025 15:19
Copy link
Contributor

@chelseybeck chelseybeck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great work, @LiamMcFall 🙌

@LiamMcFall LiamMcFall enabled auto-merge October 2, 2025 16:45
@LiamMcFall LiamMcFall changed the title [DO NOT MERGE]feat: build win10 user targeting for braze feat: build win10 user targeting for braze to start ip warming Oct 2, 2025
@dataops-ci-bot

This comment has been minimized.

@dataops-ci-bot
Copy link

Integration report for "Merge branch 'main' into win10_users_activation"

sql.diff

Click to expand!
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/dags/bqetl_accounts_backend_external.py /tmp/workspace/generated-sql/dags/bqetl_accounts_backend_external.py
--- /tmp/workspace/main-generated-sql/dags/bqetl_accounts_backend_external.py	2025-10-02 17:02:19.000000000 +0000
+++ /tmp/workspace/generated-sql/dags/bqetl_accounts_backend_external.py	2025-10-02 17:04:00.000000000 +0000
@@ -79,6 +79,19 @@
         task_concurrency=1,
     )
 
+    with TaskGroup(
+        "accounts_backend_external__emails__v1_external",
+    ) as accounts_backend_external__emails__v1_external:
+        ExternalTaskMarker(
+            task_id="bqetl_braze__wait_for_accounts_backend_external__emails__v1",
+            external_dag_id="bqetl_braze",
+            external_task_id="wait_for_accounts_backend_external__emails__v1",
+        )
+
+        accounts_backend_external__emails__v1_external.set_upstream(
+            accounts_backend_external__emails__v1
+        )
+
     accounts_backend_external__nonprod_accounts__v1 = bigquery_etl_query(
         task_id="accounts_backend_external__nonprod_accounts__v1",
         destination_table="nonprod_accounts_v1",
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/dags/bqetl_accounts_derived.py /tmp/workspace/generated-sql/dags/bqetl_accounts_derived.py
--- /tmp/workspace/main-generated-sql/dags/bqetl_accounts_derived.py	2025-10-02 17:02:20.000000000 +0000
+++ /tmp/workspace/generated-sql/dags/bqetl_accounts_derived.py	2025-10-02 17:04:00.000000000 +0000
@@ -113,6 +113,19 @@
         depends_on_past=False,
     )
 
+    with TaskGroup(
+        "accounts_backend_derived__users_services_last_seen__v1_external",
+    ) as accounts_backend_derived__users_services_last_seen__v1_external:
+        ExternalTaskMarker(
+            task_id="bqetl_braze__wait_for_accounts_backend_derived__users_services_last_seen__v1",
+            external_dag_id="bqetl_braze",
+            external_task_id="wait_for_accounts_backend_derived__users_services_last_seen__v1",
+        )
+
+        accounts_backend_derived__users_services_last_seen__v1_external.set_upstream(
+            accounts_backend_derived__users_services_last_seen__v1
+        )
+
     checks__warn_accounts_backend_derived__users_services_daily__v1 = bigquery_dq_check(
         task_id="checks__warn_accounts_backend_derived__users_services_daily__v1",
         source_table="users_services_daily_v1",
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/dags/bqetl_braze.py /tmp/workspace/generated-sql/dags/bqetl_braze.py
--- /tmp/workspace/main-generated-sql/dags/bqetl_braze.py	2025-10-02 17:02:21.000000000 +0000
+++ /tmp/workspace/generated-sql/dags/bqetl_braze.py	2025-10-02 17:04:03.000000000 +0000
@@ -58,6 +58,66 @@
     catchup=False,
 ) as dag:
 
+    wait_for_accounts_backend_derived__users_services_last_seen__v1 = (
+        ExternalTaskSensor(
+            task_id="wait_for_accounts_backend_derived__users_services_last_seen__v1",
+            external_dag_id="bqetl_accounts_derived",
+            external_task_id="accounts_backend_derived__users_services_last_seen__v1",
+            check_existence=True,
+            mode="reschedule",
+            poke_interval=datetime.timedelta(minutes=5),
+            allowed_states=ALLOWED_STATES,
+            failed_states=FAILED_STATES,
+            pool="DATA_ENG_EXTERNALTASKSENSOR",
+        )
+    )
+
+    wait_for_accounts_backend_external__emails__v1 = ExternalTaskSensor(
+        task_id="wait_for_accounts_backend_external__emails__v1",
+        external_dag_id="bqetl_accounts_backend_external",
+        external_task_id="accounts_backend_external__emails__v1",
+        check_existence=True,
+        mode="reschedule",
+        poke_interval=datetime.timedelta(minutes=5),
+        allowed_states=ALLOWED_STATES,
+        failed_states=FAILED_STATES,
+        pool="DATA_ENG_EXTERNALTASKSENSOR",
+    )
+
+    wait_for_copy_deduplicate_all = ExternalTaskSensor(
+        task_id="wait_for_copy_deduplicate_all",
+        external_dag_id="copy_deduplicate",
+        external_task_id="copy_deduplicate_all",
+        check_existence=True,
+        mode="reschedule",
+        poke_interval=datetime.timedelta(minutes=5),
+        allowed_states=ALLOWED_STATES,
+        failed_states=FAILED_STATES,
+        pool="DATA_ENG_EXTERNALTASKSENSOR",
+    )
+
+    braze_derived__fxa_win10_users_daily__v1 = bigquery_etl_query(
+        task_id="braze_derived__fxa_win10_users_daily__v1",
+        destination_table="fxa_win10_users_daily_v1",
+        dataset_id="braze_derived",
+        project_id="moz-fx-data-shared-prod",
+        owner="[email protected]",
+        email=["[email protected]", "[email protected]"],
+        date_partition_parameter="submission_date",
+        depends_on_past=False,
+    )
+
+    braze_derived__fxa_win10_users_historical__v1 = bigquery_etl_query(
+        task_id="braze_derived__fxa_win10_users_historical__v1",
+        destination_table="fxa_win10_users_historical_v1",
+        dataset_id="braze_derived",
+        project_id="moz-fx-data-shared-prod",
+        owner="[email protected]",
+        email=["[email protected]", "[email protected]"],
+        date_partition_parameter="submission_date",
+        depends_on_past=False,
+    )
+
     braze_derived__newsletters__v1 = bigquery_etl_query(
         task_id="braze_derived__newsletters__v1",
         destination_table="newsletters_v1",
@@ -244,6 +304,17 @@
         sql_file_path="sql/moz-fx-data-shared-prod/braze_external/users_previous_day_snapshot_v1/script.sql",
     )
 
+    braze_external__win10_users_sync__v1 = bigquery_etl_query(
+        task_id="braze_external__win10_users_sync__v1",
+        destination_table="win10_users_sync_v1",
+        dataset_id="braze_external",
+        project_id="moz-fx-data-shared-prod",
+        owner="[email protected]",
+        email=["[email protected]", "[email protected]"],
+        date_partition_parameter="submission_date",
+        depends_on_past=False,
+    )
+
     checks__fail_braze_derived__newsletters__v1 = bigquery_dq_check(
         task_id="checks__fail_braze_derived__newsletters__v1",
         source_table="newsletters_v1",
@@ -445,6 +516,24 @@
         retries=0,
     )
 
+    braze_derived__fxa_win10_users_daily__v1.set_upstream(
+        wait_for_accounts_backend_derived__users_services_last_seen__v1
+    )
+
+    braze_derived__fxa_win10_users_daily__v1.set_upstream(
+        wait_for_accounts_backend_external__emails__v1
+    )
+
+    braze_derived__fxa_win10_users_daily__v1.set_upstream(
+        checks__fail_braze_derived__users__v1
+    )
+
+    braze_derived__fxa_win10_users_daily__v1.set_upstream(wait_for_copy_deduplicate_all)
+
+    braze_derived__fxa_win10_users_historical__v1.set_upstream(
+        braze_derived__fxa_win10_users_daily__v1
+    )
+
     braze_derived__newsletters__v1.set_upstream(checks__fail_braze_derived__users__v1)
 
     braze_derived__subscriptions__v1.set_upstream(
@@ -503,6 +592,10 @@
         braze_external__changed_users__v1
     )
 
+    braze_external__win10_users_sync__v1.set_upstream(
+        braze_derived__fxa_win10_users_historical__v1
+    )
+
     checks__fail_braze_derived__newsletters__v1.set_upstream(
         braze_derived__newsletters__v1
     )
Only in /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived: fxa_win10_users_daily_v1
Only in /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived: fxa_win10_users_historical_v1
Only in /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_external: win10_users_sync_v1
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_daily_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_daily_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_daily_v1/metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_daily_v1/metadata.yaml	2025-10-02 16:58:01.000000000 +0000
@@ -0,0 +1,28 @@
+friendly_name: Fxa Win10 Users Daily
+description: |-
+  This query identifies Firefox Accounts users on Windows 10 who have been inactive for exactly 14 days and
+  prepares their records for Braze by assigning an external ID and email.
+owners:
+- [email protected]
+labels:
+  schedule: daily
+  owner: lmcfall
+  dag: bqetl_braze
+  owner1: lmcfall
+scheduling:
+  dag_name: bqetl_braze
+bigquery: null
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:braze
+- role: roles/bigquery.dataEditor
+  members:
+  - workgroup:braze/data-developers
+references:
+  query.sql:
+  - moz-fx-data-shared-prod.accounts_backend_derived.users_services_last_seen_v1
+  - moz-fx-data-shared-prod.accounts_backend_external.emails_v1
+  - moz-fx-data-shared-prod.braze_derived.users_v1
+  - moz-fx-data-shared-prod.firefox_desktop.fx_accounts
+require_column_descriptions: false
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_daily_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_daily_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_daily_v1/query.sql	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_daily_v1/query.sql	2025-10-02 16:55:13.000000000 +0000
@@ -0,0 +1,77 @@
+WITH win10_users AS (
+  SELECT DISTINCT
+    TO_HEX(SHA256(metrics.string.client_association_uid)) AS fxa_id_sha256,
+    FIRST_VALUE(DATE(submission_timestamp)) OVER (
+      PARTITION BY
+        TO_HEX(SHA256(metrics.string.client_association_uid))
+      ORDER BY
+        submission_timestamp DESC
+    ) AS submission_date,
+    FIRST_VALUE(client_info.os) OVER (
+      PARTITION BY
+        TO_HEX(SHA256(metrics.string.client_association_uid))
+      ORDER BY
+        submission_timestamp DESC
+    ) AS os,
+    FIRST_VALUE(client_info.os_version) OVER (
+      PARTITION BY
+        TO_HEX(SHA256(metrics.string.client_association_uid))
+      ORDER BY
+        submission_timestamp DESC
+    ) AS os_version,
+    FIRST_VALUE(client_info.locale) OVER (
+      PARTITION BY
+        TO_HEX(SHA256(metrics.string.client_association_uid))
+      ORDER BY
+        submission_timestamp DESC
+    ) AS locale
+  FROM
+    `moz-fx-data-shared-prod.firefox_desktop.fx_accounts`
+  WHERE
+    DATE(submission_timestamp) = @submission_date
+    AND client_info.os = 'Windows'
+    AND client_info.os_version = '10.0'
+),
+last_seen_14_days AS (
+  SELECT DISTINCT
+    user_id_sha256
+  FROM
+    `moz-fx-data-shared-prod.accounts_backend_derived.users_services_last_seen_v1`
+  WHERE
+    submission_date = @submission_date
+    -- bit pattern 100000000000000, last seen 14 days from submission date
+    AND days_seen_bits = 16384
+),
+inactive_win10_users AS (
+  SELECT
+    win10.submission_date,
+    last_seen.user_id_sha256,
+    win10.os,
+    win10.os_version,
+    win10.locale
+  FROM
+    last_seen_14_days AS last_seen
+  LEFT JOIN
+    win10_users AS win10
+    ON last_seen.user_id_sha256 = win10.fxa_id_sha256
+  -- filter out users that don't have an FX account
+  WHERE
+    win10.fxa_id_sha256 IS NOT NULL
+)
+SELECT
+  inactive.submission_date,
+  braze_users.external_id AS external_id,
+  -- if user is in our braze users table use their email, otherwise use the email associated with their fxa_id
+  IFNULL(braze_users.email, fxa_emails.normalizedEmail) AS email,
+  inactive.user_id_sha256,
+  inactive.locale
+FROM
+  inactive_win10_users AS inactive
+LEFT JOIN
+  `moz-fx-data-shared-prod.braze_derived.users_v1` AS braze_users
+  ON inactive.user_id_sha256 = braze_users.fxa_id_sha256
+LEFT JOIN
+  `moz-fx-data-shared-prod.accounts_backend_external.emails_v1` AS fxa_emails
+  ON inactive.user_id_sha256 = TO_HEX(SHA256(fxa_emails.uid))
+  -- some users have multiple email addresses in this table, only use primary
+  AND fxa_emails.isPrimary = TRUE
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/metadata.yaml	2025-10-02 16:58:01.000000000 +0000
@@ -0,0 +1,33 @@
+friendly_name: Fxa Win10 Users Historical
+description: |-
+  This query compiles the full list of Win10 users who have reached 14 days of inactivity.
+owners:
+- [email protected]
+labels:
+  incremental: true
+  schedule: daily
+  owner: lmcfall
+  dag: bqetl_braze
+  owner1: lmcfall
+scheduling:
+  dag_name: bqetl_braze
+bigquery:
+  time_partitioning:
+    type: day
+    field: submission_date
+    require_partition_filter: false
+    expiration_days: null
+  range_partitioning: null
+  clustering: null
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:braze
+- role: roles/bigquery.dataEditor
+  members:
+  - workgroup:braze/data-developers
+references:
+  query.sql:
+  - moz-fx-data-shared-prod.braze_derived.fxa_win10_users_daily_v1
+  - moz-fx-data-shared-prod.braze_derived.fxa_win10_users_historical_v1
+require_column_descriptions: false
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/query.sql	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_derived/fxa_win10_users_historical_v1/query.sql	2025-10-02 16:55:13.000000000 +0000
@@ -0,0 +1,25 @@
+WITH current_list AS (
+  SELECT
+    fxa_id_sha256
+  FROM
+    `moz-fx-data-shared-prod.braze_derived.fxa_win10_users_historical_v1`
+)
+SELECT
+  daily.submission_date,
+  IFNULL(daily.external_id, TO_HEX(SHA256(GENERATE_UUID()))) AS external_id,
+  daily.email,
+  daily.locale,
+  daily.user_id_sha256 AS fxa_id_sha256
+FROM
+  `moz-fx-data-shared-prod.braze_derived.fxa_win10_users_daily_v1` AS daily
+LEFT JOIN
+  current_list AS historical
+  ON historical.fxa_id_sha256 = daily.user_id_sha256
+WHERE
+  submission_date = @submission_date
+  AND daily.email IS NOT NULL
+  -- FILTER OUT USERS ALREADY IN THE LIST
+  AND historical.fxa_id_sha256 IS NULL
+  -- ONLY FOR EMAIL WARMING IN en-US LOCALE
+  -- REMOVE THIS FILTER BEFORE 10/14/2025 WHEN FULL CAMPAIGN STARTS
+  AND daily.locale = 'en-US'
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_external/win10_users_sync_v1/metadata.yaml /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_external/win10_users_sync_v1/metadata.yaml
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_external/win10_users_sync_v1/metadata.yaml	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_external/win10_users_sync_v1/metadata.yaml	2025-10-02 16:58:00.000000000 +0000
@@ -0,0 +1,26 @@
+friendly_name: Win10 Users Sync
+description: |-
+  This table will sync inactive Windows 10 Firefox users to Braze to be contacted
+  in the Win10 Inactive User Campaign.
+owners:
+- [email protected]
+labels:
+  incremental: true
+  owner1: lmcfall
+  dag: bqetl_braze
+scheduling:
+  dag_name: bqetl_braze
+bigquery: null
+workgroup_access:
+- role: roles/bigquery.dataViewer
+  members:
+  - workgroup:braze
+  - workgroup:braze/ingestion-firefox
+  - workgroup:braze/ingestion-mozilla-dev
+- role: roles/bigquery.dataEditor
+  members:
+  - workgroup:braze/data-developers
+references:
+  query.sql:
+  - moz-fx-data-shared-prod.braze_derived.fxa_win10_users_historical_v1
+require_column_descriptions: false
diff -bur --no-dereference --new-file /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_external/win10_users_sync_v1/query.sql /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_external/win10_users_sync_v1/query.sql
--- /tmp/workspace/main-generated-sql/sql/moz-fx-data-shared-prod/braze_external/win10_users_sync_v1/query.sql	1970-01-01 00:00:00.000000000 +0000
+++ /tmp/workspace/generated-sql/sql/moz-fx-data-shared-prod/braze_external/win10_users_sync_v1/query.sql	2025-10-02 16:55:13.000000000 +0000
@@ -0,0 +1,19 @@
+SELECT
+  CURRENT_TIMESTAMP() AS updated_at,
+  external_id,
+  TO_JSON(
+    STRUCT(
+      email AS email,
+      "subscribed" AS email_subscribe,
+      STRUCT(
+        "718eea53-371c-4cc6-9fdc-1260b1311bd8" AS subscription_group_id,
+        "subscribed" AS subscription_state
+      ) AS subscription_groups,
+      locale AS locale,
+      fxa_id_sha256
+    )
+  ) AS payload
+FROM
+  `moz-fx-data-shared-prod.braze_derived.fxa_win10_users_historical_v1`
+WHERE
+  submission_date = @submission_date

Link to full diff

@LiamMcFall LiamMcFall added this pull request to the merge queue Oct 2, 2025
Merged via the queue into main with commit 072c456 Oct 2, 2025
20 of 21 checks passed
@LiamMcFall LiamMcFall deleted the win10_users_activation branch October 2, 2025 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants