Skip to content

Create modularized Analytics package. #4116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jan 21, 2021
Merged

Create modularized Analytics package. #4116

merged 16 commits into from
Jan 21, 2021

Conversation

hsubox76
Copy link
Contributor

Created "analytics-exp" modularized analytics package.

One question: logEvent has a lot of signature overloads in the public interface (convenient recommended param autocompletes for all the standard eventNames). I haven't added them here yet (they can be seen in the old packages/firebase/index.d.ts monolith). Is there a good place for me to put them that doesn't clutter up the code?

@changeset-bot
Copy link

changeset-bot bot commented Nov 24, 2020

⚠️ No Changeset found

Latest commit: 4ab7032

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Nov 24, 2020

Changeset File Check ✅

  • No modified packages are missing from the changeset file.
  • No changeset formatting errors detected.

"bugs": {
"url": "https://github.com/firebase/firebase-js-sdk/issues"
},
"typings": "dist/index.d.ts",
Copy link
Member

Choose a reason for hiding this comment

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

It's not pointing to the rollup d.ts file created by api-extractor.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

*
* @param options - Custom gtag and dataLayer names.
*/
export function settings(options: SettingsOptions): void {
Copy link
Member

Choose a reason for hiding this comment

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

Is the name approved in the API proposal? Feels a little weird for a standalone function( it sounds like a property name).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I neglected to include it in the API proposal. I changed it to analyticsSettings. Should I amend the API proposal?

Copy link
Member

Choose a reason for hiding this comment

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

I actually prefer settings to analyticsSettings since everything is already namespaced by the package name by default. I just thought a name with "verb + thing" pattern like updateSettings() feels more natural for a free function.

Yes, we should amend the API proposal. Let's start with settings(). We should be able to do everything via emails.

* Officially recommended event names for gtag.js
* Any other string is also allowed.
*/
export enum EventName {
Copy link
Member

Choose a reason for hiding this comment

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

Consider changing it to const enum to produce smaller bundle.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

// find the appId (if any) corresponding to this measurementId. If there is one, wait on
// that appId's initialization promise. If there is none, promise resolves and gtag
// call goes through.
const dynamicConfigResults = await Promise.all(dynamicConfigPromisesList);
Copy link
Member

Choose a reason for hiding this comment

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

We should use Promise.allSettled() instead of Promise.all(), because we should proceed to try to find a match even if some promises rejected.

Promise.allSettled() is a pretty new addition to the es spec, so we need to use a polyfill. We can create one ourselves:

const a = Promise.resolve(1);
const b = Promise.reject(new Error(2));
const c = Promise.resolve(3);

// allSettled polyfill code
Promise.all([a, b, c].map(p => p.catch(e => e)))
  .then(results => console.log(results)) // 1,Error: 2,3

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I made a polyfill function. It adds an extra tick to the async stack so this same function has to be used in tests (see helpers.test.ts).

const fidPromise: Promise<string | undefined> = validateIndexedDB().then(
envIsValid => {
if (envIsValid) {
return getId(installations);
Copy link
Member

Choose a reason for hiding this comment

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

The installations here is an internal installations instance where you can do installations.getId(). We never import/use functions from other Firebase SDKs directly. We rely entirely on the component framework for inter-SDK communication.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I was confused about how it works.

Copy link
Member

@Feiyang1 Feiyang1 left a comment

Choose a reason for hiding this comment

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

LGTM except for a few minor comments


export const GTAG_URL = 'https://www.googletagmanager.com/gtag/js';

export enum GtagCommand {
Copy link
Member

Choose a reason for hiding this comment

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

const enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

* Officially recommended event names for gtag.js
* Any other string is also allowed.
*/
export const enum EventName {
Copy link
Member

Choose a reason for hiding this comment

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

This seems to be only used in tests? Should it be moved to a test file instead of in the source file?

Copy link
Contributor Author

@hsubox76 hsubox76 Dec 1, 2020

Choose a reason for hiding this comment

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

I think we wanted to make the enum available to users so they could easily get a list of official EventNames that they can then put into logEvent. The string literals are already available as autocompletes because of the overloads but maybe they want to save it to a variable? Feel safer from typos?

It wasn't exported so I added it to exports from api.ts.

Basically, if you import the EventName enum you can do:

logEvent(analytics, EventName.LOGIN, { method: 'email' });

or

logEvent(analytics, 'login', { method: 'email' });

Also it gets the list into documentation with some deprecation comments on 2 of them?

Copy link
Member

Choose a reason for hiding this comment

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

If we want to export it, it has to be a normal enum instead of const enum because const enum only exists in compile time. Is it part of the API proposal? I'm okay exporting it since it's useful, but I don't think enums are tree-shakable, so it will be included in bundle even if not used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we should keep it especially as it's available in the current API. I'll add it to the API proposal and send an email.

@hsubox76 hsubox76 force-pushed the ch-analytics-exp branch 2 times, most recently from 03d2b0f to ac9e469 Compare January 13, 2021 18:27
@google-oss-bot
Copy link
Contributor

Size Analysis Report

Affected Products

  • @firebase/analytics-exp

    • getAnalytics

      Size Table

      TypeBase (762fa53)Head (63afde2)Diff
      size
      ?
      8.98 kB
      ? (?)
      size-with-ext-deps
      ?
      14.2 kB
      ? (?)

      Dependency Table

      TypeBase (762fa53)Head (63afde2)Diff
      functions
      ?

      22 dependencies

      attemptFetchDynamicConfigWithRetry
      factory
      fetchDynamicConfig
      fetchDynamicConfigWithRetry
      findGtagScriptOnPage
      getAnalytics
      getHeaders
      getOrCreateDataLayer
      gtagOnConfig
      gtagOnEvent
      initializeAnalytics
      insertScriptTag
      isRetriableError
      logEvent
      logEvent$1
      promiseAllSettled
      registerAnalytics
      setAbortableTimeout
      validateIndexedDB
      warnOnBrowserContextMismatch
      wrapGtag
      wrapOrCreateGtag
      

      ?
      classes
      ?

      AnalyticsAbortSignal
      AnalyticsService
      RetryData
      

      ?
      variables
      ?

      22 dependencies

      ANALYTICS_TYPE
      BASE_INTERVAL_MILLIS
      DYNAMIC_CONFIG_URL
      ERRORS
      ERROR_FACTORY
      FETCH_TIMEOUT_MILLIS
      GA_FID_KEY
      GTAG_URL
      LONG_RETRY_FACTOR
      ORIGIN_KEY
      dataLayerName
      defaultRetryData
      dynamicConfigPromisesList
      globalInitDone
      gtagCoreFunction
      gtagName
      initializationPromisesMap
      logger
      measurementIdToAppId
      name
      version
      wrappedGtagFunction
      

      ?
      enums
      ?
      ?

      External Dependency Table

      ModuleBase (762fa53)Head (63afde2)Diff
      @firebase/app-exp
      ?

      _getProvider
      _registerComponent
      registerVersion
      

      ?
      @firebase/logger
      ?

      Logger
      

      ?
      @firebase/util
      ?

      ErrorFactory
      FirebaseError
      areCookiesEnabled
      calculateBackoffMillis
      isBrowserExtension
      isIndexedDBAvailable
      validateIndexedDBOpenable
      

      ?
      @firebase/component
      ?

      Component
      

      ?
    • isSupported

      Size Table

      TypeBase (762fa53)Head (63afde2)Diff
      size
      ?
      9.03 kB
      ? (?)
      size-with-ext-deps
      ?
      14.3 kB
      ? (?)

      Dependency Table

      TypeBase (762fa53)Head (63afde2)Diff
      functions
      ?

      22 dependencies

      attemptFetchDynamicConfigWithRetry
      factory
      fetchDynamicConfig
      fetchDynamicConfigWithRetry
      findGtagScriptOnPage
      getHeaders
      getOrCreateDataLayer
      gtagOnConfig
      gtagOnEvent
      initializeAnalytics
      insertScriptTag
      isRetriableError
      isSupported
      logEvent
      logEvent$1
      promiseAllSettled
      registerAnalytics
      setAbortableTimeout
      validateIndexedDB
      warnOnBrowserContextMismatch
      wrapGtag
      wrapOrCreateGtag
      

      ?
      classes
      ?

      AnalyticsAbortSignal
      AnalyticsService
      RetryData
      

      ?
      variables
      ?

      22 dependencies

      ANALYTICS_TYPE
      BASE_INTERVAL_MILLIS
      DYNAMIC_CONFIG_URL
      ERRORS
      ERROR_FACTORY
      FETCH_TIMEOUT_MILLIS
      GA_FID_KEY
      GTAG_URL
      LONG_RETRY_FACTOR
      ORIGIN_KEY
      dataLayerName
      defaultRetryData
      dynamicConfigPromisesList
      globalInitDone
      gtagCoreFunction
      gtagName
      initializationPromisesMap
      logger
      measurementIdToAppId
      name
      version
      wrappedGtagFunction
      

      ?
      enums
      ?
      ?

      External Dependency Table

      ModuleBase (762fa53)Head (63afde2)Diff
      @firebase/app-exp
      ?

      _registerComponent
      registerVersion
      

      ?
      @firebase/logger
      ?

      Logger
      

      ?
      @firebase/util
      ?

      ErrorFactory
      FirebaseError
      areCookiesEnabled
      calculateBackoffMillis
      isBrowserExtension
      isIndexedDBAvailable
      validateIndexedDBOpenable
      

      ?
      @firebase/component
      ?

      Component
      

      ?
    • logEvent

      Size Table

      TypeBase (762fa53)Head (63afde2)Diff
      size
      ?
      8.89 kB
      ? (?)
      size-with-ext-deps
      ?
      14.1 kB
      ? (?)

      Dependency Table

      TypeBase (762fa53)Head (63afde2)Diff
      functions
      ?

      20 dependencies

      attemptFetchDynamicConfigWithRetry
      factory
      fetchDynamicConfig
      fetchDynamicConfigWithRetry
      findGtagScriptOnPage
      getHeaders
      getOrCreateDataLayer
      gtagOnConfig
      gtagOnEvent
      initializeAnalytics
      insertScriptTag
      isRetriableError
      logEvent
      promiseAllSettled
      registerAnalytics
      setAbortableTimeout
      validateIndexedDB
      warnOnBrowserContextMismatch
      wrapGtag
      wrapOrCreateGtag
      

      ?
      classes
      ?

      AnalyticsAbortSignal
      AnalyticsService
      RetryData
      

      ?
      variables
      ?

      22 dependencies

      ANALYTICS_TYPE
      BASE_INTERVAL_MILLIS
      DYNAMIC_CONFIG_URL
      ERRORS
      ERROR_FACTORY
      FETCH_TIMEOUT_MILLIS
      GA_FID_KEY
      GTAG_URL
      LONG_RETRY_FACTOR
      ORIGIN_KEY
      dataLayerName
      defaultRetryData
      dynamicConfigPromisesList
      globalInitDone
      gtagCoreFunction
      gtagName
      initializationPromisesMap
      logger
      measurementIdToAppId
      name
      version
      wrappedGtagFunction
      

      ?
      enums
      ?
      ?

      External Dependency Table

      ModuleBase (762fa53)Head (63afde2)Diff
      @firebase/app-exp
      ?

      _registerComponent
      registerVersion
      

      ?
      @firebase/logger
      ?

      Logger
      

      ?
      @firebase/util
      ?

      ErrorFactory
      FirebaseError
      areCookiesEnabled
      calculateBackoffMillis
      isBrowserExtension
      isIndexedDBAvailable
      validateIndexedDBOpenable
      

      ?
      @firebase/component
      ?

      Component
      

      ?
    • setAnalyticsCollectionEnabled

      Size Table

      TypeBase (762fa53)Head (63afde2)Diff
      size
      ?
      9.05 kB
      ? (?)
      size-with-ext-deps
      ?
      14.3 kB
      ? (?)

      Dependency Table

      TypeBase (762fa53)Head (63afde2)Diff
      functions
      ?

      22 dependencies

      attemptFetchDynamicConfigWithRetry
      factory
      fetchDynamicConfig
      fetchDynamicConfigWithRetry
      findGtagScriptOnPage
      getHeaders
      getOrCreateDataLayer
      gtagOnConfig
      gtagOnEvent
      initializeAnalytics
      insertScriptTag
      isRetriableError
      logEvent
      logEvent$1
      promiseAllSettled
      registerAnalytics
      setAbortableTimeout
      setAnalyticsCollectionEnabled
      validateIndexedDB
      warnOnBrowserContextMismatch
      wrapGtag
      wrapOrCreateGtag
      

      ?
      classes
      ?

      AnalyticsAbortSignal
      AnalyticsService
      RetryData
      

      ?
      variables
      ?

      22 dependencies

      ANALYTICS_TYPE
      BASE_INTERVAL_MILLIS
      DYNAMIC_CONFIG_URL
      ERRORS
      ERROR_FACTORY
      FETCH_TIMEOUT_MILLIS
      GA_FID_KEY
      GTAG_URL
      LONG_RETRY_FACTOR
      ORIGIN_KEY
      dataLayerName
      defaultRetryData
      dynamicConfigPromisesList
      globalInitDone
      gtagCoreFunction
      gtagName
      initializationPromisesMap
      logger
      measurementIdToAppId
      name
      version
      wrappedGtagFunction
      

      ?
      enums
      ?
      ?

      External Dependency Table

      ModuleBase (762fa53)Head (63afde2)Diff
      @firebase/app-exp
      ?

      _registerComponent
      registerVersion
      

      ?
      @firebase/logger
      ?

      Logger
      

      ?
      @firebase/util
      ?

      ErrorFactory
      FirebaseError
      areCookiesEnabled
      calculateBackoffMillis
      isBrowserExtension
      isIndexedDBAvailable
      validateIndexedDBOpenable
      

      ?
      @firebase/component
      ?

      Component
      

      ?
    • setCurrentScreen

      Size Table

      TypeBase (762fa53)Head (63afde2)Diff
      size
      ?
      9.13 kB
      ? (?)
      size-with-ext-deps
      ?
      14.4 kB
      ? (?)

      Dependency Table

      TypeBase (762fa53)Head (63afde2)Diff
      functions
      ?

      22 dependencies

      attemptFetchDynamicConfigWithRetry
      factory
      fetchDynamicConfig
      fetchDynamicConfigWithRetry
      findGtagScriptOnPage
      getHeaders
      getOrCreateDataLayer
      gtagOnConfig
      gtagOnEvent
      initializeAnalytics
      insertScriptTag
      isRetriableError
      logEvent
      logEvent$1
      promiseAllSettled
      registerAnalytics
      setAbortableTimeout
      setCurrentScreen
      validateIndexedDB
      warnOnBrowserContextMismatch
      wrapGtag
      wrapOrCreateGtag
      

      ?
      classes
      ?

      AnalyticsAbortSignal
      AnalyticsService
      RetryData
      

      ?
      variables
      ?

      22 dependencies

      ANALYTICS_TYPE
      BASE_INTERVAL_MILLIS
      DYNAMIC_CONFIG_URL
      ERRORS
      ERROR_FACTORY
      FETCH_TIMEOUT_MILLIS
      GA_FID_KEY
      GTAG_URL
      LONG_RETRY_FACTOR
      ORIGIN_KEY
      dataLayerName
      defaultRetryData
      dynamicConfigPromisesList
      globalInitDone
      gtagCoreFunction
      gtagName
      initializationPromisesMap
      logger
      measurementIdToAppId
      name
      version
      wrappedGtagFunction
      

      ?
      enums
      ?
      ?

      External Dependency Table

      ModuleBase (762fa53)Head (63afde2)Diff
      @firebase/app-exp
      ?

      _registerComponent
      registerVersion
      

      ?
      @firebase/logger
      ?

      Logger
      

      ?
      @firebase/util
      ?

      ErrorFactory
      FirebaseError
      areCookiesEnabled
      calculateBackoffMillis
      isBrowserExtension
      isIndexedDBAvailable
      validateIndexedDBOpenable
      

      ?
      @firebase/component
      ?

      Component
      

      ?
    • setUserId

      Size Table

      TypeBase (762fa53)Head (63afde2)Diff
      size
      ?
      9.12 kB
      ? (?)
      size-with-ext-deps
      ?
      14.4 kB
      ? (?)

      Dependency Table

      TypeBase (762fa53)Head (63afde2)Diff
      functions
      ?

      22 dependencies

      attemptFetchDynamicConfigWithRetry
      factory
      fetchDynamicConfig
      fetchDynamicConfigWithRetry
      findGtagScriptOnPage
      getHeaders
      getOrCreateDataLayer
      gtagOnConfig
      gtagOnEvent
      initializeAnalytics
      insertScriptTag
      isRetriableError
      logEvent
      logEvent$1
      promiseAllSettled
      registerAnalytics
      setAbortableTimeout
      setUserId
      validateIndexedDB
      warnOnBrowserContextMismatch
      wrapGtag
      wrapOrCreateGtag
      

      ?
      classes
      ?

      AnalyticsAbortSignal
      AnalyticsService
      RetryData
      

      ?
      variables
      ?

      22 dependencies

      ANALYTICS_TYPE
      BASE_INTERVAL_MILLIS
      DYNAMIC_CONFIG_URL
      ERRORS
      ERROR_FACTORY
      FETCH_TIMEOUT_MILLIS
      GA_FID_KEY
      GTAG_URL
      LONG_RETRY_FACTOR
      ORIGIN_KEY
      dataLayerName
      defaultRetryData
      dynamicConfigPromisesList
      globalInitDone
      gtagCoreFunction
      gtagName
      initializationPromisesMap
      logger
      measurementIdToAppId
      name
      version
      wrappedGtagFunction
      

      ?
      enums
      ?
      ?

      External Dependency Table

      ModuleBase (762fa53)Head (63afde2)Diff
      @firebase/app-exp
      ?

      _registerComponent
      registerVersion
      

      ?
      @firebase/logger
      ?

      Logger
      

      ?
      @firebase/util
      ?

      ErrorFactory
      FirebaseError
      areCookiesEnabled
      calculateBackoffMillis
      isBrowserExtension
      isIndexedDBAvailable
      validateIndexedDBOpenable
      

      ?
      @firebase/component
      ?

      Component
      

      ?
    • setUserProperties

      Size Table

      TypeBase (762fa53)Head (63afde2)Diff
      size
      ?
      9.19 kB
      ? (?)
      size-with-ext-deps
      ?
      14.4 kB
      ? (?)

      Dependency Table

      TypeBase (762fa53)Head (63afde2)Diff
      functions
      ?

      22 dependencies

      attemptFetchDynamicConfigWithRetry
      factory
      fetchDynamicConfig
      fetchDynamicConfigWithRetry
      findGtagScriptOnPage
      getHeaders
      getOrCreateDataLayer
      gtagOnConfig
      gtagOnEvent
      initializeAnalytics
      insertScriptTag
      isRetriableError
      logEvent
      logEvent$1
      promiseAllSettled
      registerAnalytics
      setAbortableTimeout
      setUserProperties
      validateIndexedDB
      warnOnBrowserContextMismatch
      wrapGtag
      wrapOrCreateGtag
      

      ?
      classes
      ?

      AnalyticsAbortSignal
      AnalyticsService
      RetryData
      

      ?
      variables
      ?

      22 dependencies

      ANALYTICS_TYPE
      BASE_INTERVAL_MILLIS
      DYNAMIC_CONFIG_URL
      ERRORS
      ERROR_FACTORY
      FETCH_TIMEOUT_MILLIS
      GA_FID_KEY
      GTAG_URL
      LONG_RETRY_FACTOR
      ORIGIN_KEY
      dataLayerName
      defaultRetryData
      dynamicConfigPromisesList
      globalInitDone
      gtagCoreFunction
      gtagName
      initializationPromisesMap
      logger
      measurementIdToAppId
      name
      version
      wrappedGtagFunction
      

      ?
      enums
      ?
      ?

      External Dependency Table

      ModuleBase (762fa53)Head (63afde2)Diff
      @firebase/app-exp
      ?

      _registerComponent
      registerVersion
      

      ?
      @firebase/logger
      ?

      Logger
      

      ?
      @firebase/util
      ?

      ErrorFactory
      FirebaseError
      areCookiesEnabled
      calculateBackoffMillis
      isBrowserExtension
      isIndexedDBAvailable
      validateIndexedDBOpenable
      

      ?
      @firebase/component
      ?

      Component
      

      ?
    • settings

      Size Table

      TypeBase (762fa53)Head (63afde2)Diff
      size
      ?
      9.02 kB
      ? (?)
      size-with-ext-deps
      ?
      14.3 kB
      ? (?)

      Dependency Table

      TypeBase (762fa53)Head (63afde2)Diff
      functions
      ?

      22 dependencies

      attemptFetchDynamicConfigWithRetry
      factory
      fetchDynamicConfig
      fetchDynamicConfigWithRetry
      findGtagScriptOnPage
      getHeaders
      getOrCreateDataLayer
      gtagOnConfig
      gtagOnEvent
      initializeAnalytics
      insertScriptTag
      isRetriableError
      logEvent
      logEvent$1
      promiseAllSettled
      registerAnalytics
      setAbortableTimeout
      settings
      validateIndexedDB
      warnOnBrowserContextMismatch
      wrapGtag
      wrapOrCreateGtag
      

      ?
      classes
      ?

      AnalyticsAbortSignal
      AnalyticsService
      RetryData
      

      ?
      variables
      ?

      22 dependencies

      ANALYTICS_TYPE
      BASE_INTERVAL_MILLIS
      DYNAMIC_CONFIG_URL
      ERRORS
      ERROR_FACTORY
      FETCH_TIMEOUT_MILLIS
      GA_FID_KEY
      GTAG_URL
      LONG_RETRY_FACTOR
      ORIGIN_KEY
      dataLayerName
      defaultRetryData
      dynamicConfigPromisesList
      globalInitDone
      gtagCoreFunction
      gtagName
      initializationPromisesMap
      logger
      measurementIdToAppId
      name
      version
      wrappedGtagFunction
      

      ?
      enums
      ?
      ?

      External Dependency Table

      ModuleBase (762fa53)Head (63afde2)Diff
      @firebase/app-exp
      ?

      _registerComponent
      registerVersion
      

      ?
      @firebase/logger
      ?

      Logger
      

      ?
      @firebase/util
      ?

      ErrorFactory
      FirebaseError
      areCookiesEnabled
      calculateBackoffMillis
      isBrowserExtension
      isIndexedDBAvailable
      validateIndexedDBOpenable
      

      ?
      @firebase/component
      ?

      Component
      

      ?

@hsubox76 hsubox76 merged commit 7aee62e into master Jan 21, 2021
@firebase firebase locked and limited conversation to collaborators Feb 20, 2021
@hsubox76 hsubox76 deleted the ch-analytics-exp branch April 12, 2021 19:46
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants