Sorry, make that LGTM2

On Wed, Mar 5, 2025 at 1:00 PM Chris Harrelson <chris...@chromium.org>
wrote:

> Thanks Dominic!
>
> LGTM1
>
> On Wed, Mar 5, 2025 at 12:57 PM Dominic Farolino <d...@chromium.org> wrote:
>
>> Thanks for the summary Jake. So from the perspective of API OWNERS, I
>> don't believe anything is blocking here. Folks agree that the ref-counted
>> producer design is the right way, consistent with the developer feedback,
>> and while you can hold the API in a way that appears surprising, (1) there
>> are more surprises/quirks with the non-ref-counted approach, and (2) our
>> design is consistent with the ways developers use Observables in the wild,
>> mitigating the consequences of any surprises—I believe we're making the
>> right trade-off.
>>
>> Given that, I believe we can proceed with the review.
>>
>> On Fri, Feb 28, 2025 at 12:32 PM Jake Archibald <jaffathec...@gmail.com>
>> wrote:
>>
>>> By missing the end, I mean this:
>>>
>>> const ob = new Observable((subscriber) => {
>>>   subscriber.next(1);
>>>   setTimeout(() => {
>>>     subscriber.next(2);
>>>     subscriber.complete();
>>>   }, 1000);
>>> });
>>>
>>> ob.toArray().then((vals) => {
>>>   // You're first, so you get things from the start.
>>>   console.log(vals); // [1, 2]
>>> });
>>>
>>> ob.toArray().then((vals) => {
>>>   // You missed the start, so you get the remaining values.
>>>   // I'd describe the model here as: too late, you miss out!
>>>   console.log(vals); // [2]
>>> });
>>>
>>> setTimeout(() => {
>>>   ob.toArray().then((vals) => {
>>>     // You missed the end, so we restart.
>>>     // I'd describe the model here as: we'll fix it so you don't miss out
>>>     console.log(vals); // [1, 2]
>>>   });
>>> }, 1500);
>>>
>>> The bit where it sometimes restarts the thing so you don't miss out, and
>>> sometimes doesn't, felt unusual to me. To be clear, I think the
>>> ref-counting approach is right, but it would have felt more consistent if
>>> the final log was [], since the thing had already completed.
>>>
>>> The other case I found inconsistent is:
>>>
>>> const ob = Observable.from([1, 2, 3]);
>>>
>>> ob.toArray().then((vals) => {
>>>   console.log(vals); // [1, 2, 3]
>>> });
>>>
>>> ob.toArray().then((vals) => {
>>>   console.log(vals); // [1, 2, 3]
>>> });
>>>
>>> vs
>>>
>>> const ob = Observable.from([1, 2, 3].values());
>>>
>>> ob.toArray().then((vals) => {
>>>   console.log(vals); // [1, 2, 3]
>>> });
>>>
>>> ob.toArray().then((vals) => {
>>>   console.log(vals); // []
>>> });
>>>
>>> I had a meeting with Dominic and I now understand why it happens. It
>>> still seems unusual, but given that this hasn't come up for anyone else
>>> looking at the API (people who have way more experience with observables
>>> than I do), I guess it's just that I'm unfamiliar with these patterns. It's
>>> certainly something I'd call out in developer documentation for others
>>> coming to this fresh.
>>>
>>> Thanks all!
>>> Jake.
>>>
>>> On Fri, 28 Feb 2025 at 15:32, Dominic Farolino <d...@chromium.org> wrote:
>>>
>>>> Responding to Jake:
>>>>
>>>> With the example in the codepen, as the holder of the observable, I
>>>>> don't think I have a way of knowing if I'm getting the start, or something
>>>>> in the middle. Isn't that a bit odd?
>>>>
>>>>
>>>> Hmm, I see how it can feel a little intuitive, but I think this
>>>> tradeoff is *less unintuitive* than it was without ref-counted
>>>> producers, where Observable doesn't really represent anything related to
>>>> the subscription, causing the footguns that led to us pursuing this path in
>>>> the first place. Regarding:
>>>>
>>>> If it's ok to miss the start, why isn't it ok to miss the end?
>>>>
>>>>
>>>> I don't think it is OK to miss the end, and I don't quite think our
>>>> proposal makes this possible? If you subscribe half-way through, you will
>>>> still get `complete()` notifications so you know that the stream has ended.
>>>> The closest example of "missing the end" I can think of would be the one
>>>> you mentioned over X/Twitter, which is if you subscribe to an async
>>>> iterator (not iterable that can be restarted), and you exhaust the
>>>> iterator, what do subsequent subscriptions do after the iterator is
>>>> exhausted?
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> *  async function* asyncNumbers() {    yield* [1,2,3,4];  }  const ob =
>>>> Observable.from(asyncNumbers());  await ob.toArray().then(result =>
>>>> console.log('one', result));  ob.subscribe({      next: v =>
>>>> console.log('second subscription: ', v),      complete: () =>
>>>> console.log('complete'),  })*
>>>>
>>>> By the time the second subscription rolls around, the iterator has been
>>>> exhausted. But you still don't "miss the end" since the `complete()`
>>>> handler fires. Hopefully that makes sense. Either way, it's entirely
>>>> possible this thread isn't the best place to hash all of this out :)
>>>>
>>>> On Fri, Feb 28, 2025 at 10:20 AM Dominic Farolino <d...@chromium.org>
>>>> wrote:
>>>>
>>>>> I was told that it would be good to clarify something here from the
>>>>> original email sent here, about *TC39's engagement* and *WebKit's
>>>>> standards position*.
>>>>>
>>>>> *WebKit*: Positive (
>>>>>> https://github.com/WebKit/standards-positions/issues/292)
>>>>>
>>>>>
>>>>> I marked WebKit's standards position as positive since Anne had
>>>>> mentioned WebKit folks were supportive and he recommended marking the 
>>>>> issue
>>>>> as `position: support`
>>>>> <https://github.com/WebKit/standards-positions/issues/292#issuecomment-2520739850>.
>>>>> However, he has since walked it back since the proposal has not been
>>>>> formally presented to TC39. Such a presentation is abnormal for web APIs
>>>>> not developing *within* TC39, however is still a reasonable idea that
>>>>> I am happy to do. (For what it's worth, I tried to present this proposal 
>>>>> to
>>>>> TC39 at the Tokyo virtual meeting in October 2024 after TPAC last year, 
>>>>> and
>>>>> unfortunately after staying up late to do, so I got bumped from the agenda
>>>>> last minute because other items went over time).
>>>>>
>>>>> Regarding my comment on *TC39 engagement*, I wrote:
>>>>>
>>>>> We've gotten good design feedback from TC39 members on many issues
>>>>>> which we have implemented accordingly.
>>>>>
>>>>>
>>>>> This is true—various ECMAScript editors have engaged with us on
>>>>> substantial design issues. However, since we have not formally presented 
>>>>> to
>>>>> TC39, I was made aware that this kind of engagement might not count as
>>>>> proper *TC39 engagement*. So I wanted to call out here that we have
>>>>> not yet sought or received any kind of formal "sign-off" by ECMAScript
>>>>> editors on our proposal.
>>>>>
>>>>> On Thu, Feb 27, 2025 at 1:00 AM Domenic Denicola <dome...@chromium.org>
>>>>> wrote:
>>>>>
>>>>>> I looked into
>>>>>> <https://github.com/WICG/observable/issues/177#issuecomment-2686242878> 
>>>>>> the
>>>>>> SuppressedError proposal a bit more. I'm now about 90% convinced
>>>>>> SuppressedError does not need to be used. (Or if there is a case for it,
>>>>>> it's in extreme edge cases that we could address after shipping.)
>>>>>>
>>>>>> Given how complete every other aspect of this Intent is, LGTM1,
>>>>>> conditional on Dominic agreeing with my reasoning that we don't want to 
>>>>>> use
>>>>>> SuppressedError for most callbacks. If I misunderstood, then we should
>>>>>> delay until that gets straightened out.
>>>>>>
>>>>>> On Thu, Feb 27, 2025 at 5:53 AM Jake Archibald <
>>>>>> jaffathec...@gmail.com> wrote:
>>>>>>
>>>>>>> On Wed, 26 Feb 2025 at 20:39, Dominic Farolino <d...@chromium.org>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> https://codepen.io/jaffathecake/pen/raNWMmK?editors=0012 - it
>>>>>>>>> seems inconsistent that two of the calls to ob.map create a new 
>>>>>>>>> subscriber,
>>>>>>>>> whereas the other picks up the observable half way through.
>>>>>>>>
>>>>>>>>
>>>>>>>> Right, the idea that a subscription doesn't have side effects if an
>>>>>>>> existing subscription is in-flight was essentially the outcome of
>>>>>>>> https://github.com/WICG/observable/issues/170 &
>>>>>>>> https://github.com/WICG/observable/issues/178. The alternative,
>>>>>>>> where producer:consumer are 1:1, made it easy to write
>>>>>>>> performance foot-guns where what you actually want is to tap into an
>>>>>>>> existing stream of values without paying the cost of setting it up each
>>>>>>>> time if it already exists. Many userland Observables inevitably get
>>>>>>>> `share()` slapped on them somewhere in the chain to alleviate this, 
>>>>>>>> but the
>>>>>>>> inconsistency made it hard to judge whether your subscription would 
>>>>>>>> have
>>>>>>>> side-effects or not. We also saw a lot of Observable learning material
>>>>>>>> was taking pains to caveat
>>>>>>>> <https://ronnieschaniel.com/rxjs/rxjs-mastery-hot-vs-cold-observables/#:~:text=Why%20do%20we%20need%20cold%20and%20hot%20Observables%20in%20RxJS%3F>
>>>>>>>>  right
>>>>>>>> away, this unintuitive idea that the Observable type itself doesn't
>>>>>>>> represent anything but a stateless subscription vendor. Now it 
>>>>>>>> basically
>>>>>>>> represents the producer, and I think that matches peoples' mental
>>>>>>>> models
>>>>>>>> <https://github.com/WICG/observable/issues/178#issuecomment-2480525113>
>>>>>>>> .
>>>>>>>>
>>>>>>>> I guess the rule is: A new subscriber is created if the observer
>>>>>>>>> has closed, but isn't this really inconsistent?
>>>>>>>>
>>>>>>>>
>>>>>>>> I think it is consistent though, no? It's true that it's neither
>>>>>>>> "only one call to the subscriber" nor "each call to the initial 
>>>>>>>> observable
>>>>>>>> initiates a new subscription". But it is similar to what you wrote 
>>>>>>>> above: a
>>>>>>>> subscriber is invoked/spun up if its subscription is closed (not 
>>>>>>>> observer).
>>>>>>>> The pay-off is that you know you're never going to have "extra" side
>>>>>>>> effects when subscribing. At most you will spin up a single producer 
>>>>>>>> (which
>>>>>>>> you're OK with since you're subscribing), and at best you will listen 
>>>>>>>> in on
>>>>>>>> an existing one.
>>>>>>>>
>>>>>>>
>>>>>>> I think where it gets confusing is when the observable has a
>>>>>>> beginning and an end. It's fine for event targets, because they don't 
>>>>>>> have
>>>>>>> that.
>>>>>>>
>>>>>>> For event target observables it's 'interested' (add the listener)
>>>>>>> and 'distinerested' (remove the listener). Whereas the underlying events
>>>>>>> are still continuing.
>>>>>>>
>>>>>>> With the example in the codepen, as the holder of the observable, I
>>>>>>> don't think I have a way of knowing if I'm getting the start, or 
>>>>>>> something
>>>>>>> in the middle. Isn't that a bit odd? If it's ok to miss the start, why
>>>>>>> isn't it ok to miss the end?
>>>>>>>
>>>>>>> Again it might be because I'm not used to the patterns, and they're
>>>>>>> well understood elsewhere.
>>>>>>>
>>>>>>>
>>>>>>>> If you need a new subscriber to be created on each subscription,
>>>>>>>> you'll need to basically take a closure over the Observable-vending 
>>>>>>>> API and
>>>>>>>> call each `subscribe()` on it, which I hope is not too burdensome.
>>>>>>>>
>>>>>>>> On Wed, Feb 26, 2025 at 2:55 PM Jake Archibald <
>>>>>>>> jaffathec...@gmail.com> wrote:
>>>>>>>>
>>>>>>>>> I'm struggling a little to get my head around how this works.
>>>>>>>>>
>>>>>>>>> https://codepen.io/jaffathecake/pen/raNWMmK?editors=0012 - it
>>>>>>>>> seems inconsistent that two of the calls to ob.map create a new 
>>>>>>>>> subscriber,
>>>>>>>>> whereas the other picks up the observable half way through.
>>>>>>>>>
>>>>>>>>> If I put the .complete call in a setTimeout, then there's only one
>>>>>>>>> subscriber created.
>>>>>>>>>
>>>>>>>>> I guess the rule is: A new subscriber is created if the observer
>>>>>>>>> has closed, but isn't this really inconsistent?
>>>>>>>>>
>>>>>>>>> I'd expect it to be one way or the other. As in:
>>>>>>>>>
>>>>>>>>> There's only one call to the subscriber.
>>>>>>>>> Or
>>>>>>>>> Each call to the initial observable is a new subscription.
>>>>>>>>>
>>>>>>>>> The way it's neither one or the other is confusing to me. But
>>>>>>>>> maybe that's totally normal for folks who are used to observables?
>>>>>>>>>
>>>>>>>>> On Friday, 21 February 2025 at 21:25:05 UTC Chromestatus wrote:
>>>>>>>>>
>>>>>>>>>> Contact emails d...@chromium.org
>>>>>>>>>>
>>>>>>>>>> Explainer https://github.com/WICG/observable
>>>>>>>>>>
>>>>>>>>>> Specification https://wicg.github.io/observable
>>>>>>>>>>
>>>>>>>>>> Summary
>>>>>>>>>>
>>>>>>>>>> Observables are a popular reactive-programming paradigm to handle
>>>>>>>>>> an asynchronous stream of push-based events. They can be thought of 
>>>>>>>>>> as
>>>>>>>>>> Promises but for multiple events, and aim to do what Promises did for
>>>>>>>>>> callbacks/nesting. That is, they allow ergonomic event handling by
>>>>>>>>>> providing an Observable object that represents the asynchronous flow 
>>>>>>>>>> of
>>>>>>>>>> events. You can "subscribe" to this object to receive events as they 
>>>>>>>>>> come
>>>>>>>>>> in, and call any of its operators/combinators to declaratively 
>>>>>>>>>> describe the
>>>>>>>>>> flow of transformations through which events go. This is in contrast 
>>>>>>>>>> with
>>>>>>>>>> the imperative version, which often requires complicated nesting with
>>>>>>>>>> things like `addEventListener()`. For more on this, see the examples 
>>>>>>>>>> in the
>>>>>>>>>> explainer. The big selling point for native Observables is their
>>>>>>>>>> integration with EventTarget — its proposed `when()` method that 
>>>>>>>>>> returns an
>>>>>>>>>> Observable which is a "better" `addEventListener()`. See
>>>>>>>>>> https://github.com/WICG/observable and
>>>>>>>>>> https://twitter.com/domfarolino/status/1684921351004430336. See
>>>>>>>>>> the spec https://wicg.github.io/observable/ and the design doc:
>>>>>>>>>> https://docs.google.com/document/d/1NEobxgiQO-fTSocxJBqcOOOVZRmXcTFg9Iqrhebb7bg/edit
>>>>>>>>>> .
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Blink component Blink>DOM
>>>>>>>>>> <https://issues.chromium.org/issues?q=customfield1222907:%22Blink%3EDOM%22>
>>>>>>>>>>
>>>>>>>>>> TAG review https://github.com/w3ctag/design-reviews/issues/902
>>>>>>>>>>
>>>>>>>>>> TAG review status Issues addressed
>>>>>>>>>>
>>>>>>>>>> Risks
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Interoperability and Compatibility
>>>>>>>>>>
>>>>>>>>>> Initially we proposed adding the `.on()` method to EventTarget,
>>>>>>>>>> which was found to conflict with userland versions of the same 
>>>>>>>>>> method. The
>>>>>>>>>> conflict was found to be too significant to justify shipping our 
>>>>>>>>>> native
>>>>>>>>>> version of this API (see
>>>>>>>>>> https://github.com/WICG/observable/issues/39) so we renamed it
>>>>>>>>>> to `.when()` and we strongly believe this resolves any naming 
>>>>>>>>>> collision
>>>>>>>>>> issues after searching through public libraries and performing 
>>>>>>>>>> developer
>>>>>>>>>> outreach on X. See the discussion on that issue.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> *Gecko*: No signal (
>>>>>>>>>> https://github.com/mozilla/standards-positions/issues/945)
>>>>>>>>>>
>>>>>>>>>> *WebKit*: Positive (
>>>>>>>>>> https://github.com/WebKit/standards-positions/issues/292)
>>>>>>>>>>
>>>>>>>>>> *Web developers*: Strongly positive (
>>>>>>>>>> https://twitter.com/domfarolino/status/1684921351004430336) Also
>>>>>>>>>> see https://foolip.github.io/spec-reactions/ and the developer
>>>>>>>>>> interest in the original WHATWG DOM issue.
>>>>>>>>>>
>>>>>>>>>> *Other signals*: We've gotten good design feedback from TC39
>>>>>>>>>> members on many issues which we have implemented accordingly. This 
>>>>>>>>>> has led
>>>>>>>>>> to positive feedback from Node.js, and luke-warm non-negative 
>>>>>>>>>> feedback from
>>>>>>>>>> WinterCG. See https://github.com/WICG/observable/issues/93;
>>>>>>>>>> specifically
>>>>>>>>>> https://github.com/nodejs/standards-positions/issues/1 &
>>>>>>>>>> https://github.com/WICG/observable/issues/30 for Node, and
>>>>>>>>>> https://github.com/wintercg/proposal-minimum-common-api/issues/72
>>>>>>>>>> for WinterCG.
>>>>>>>>>>
>>>>>>>>>> WebView application risks
>>>>>>>>>>
>>>>>>>>>> Does this intent deprecate or change behavior of existing APIs,
>>>>>>>>>> such that it has potentially high risk for Android WebView-based
>>>>>>>>>> applications?
>>>>>>>>>>
>>>>>>>>>> None
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Debuggability
>>>>>>>>>>
>>>>>>>>>> The developer experience of Observables might benefit from
>>>>>>>>>> Observable-specific DevTools tracking of events and streams (see
>>>>>>>>>> https://github.com/WICG/observable/issues/55). It is possible
>>>>>>>>>> that the existing DevTools work that assists asynchronous task 
>>>>>>>>>> tracking and
>>>>>>>>>> callstack tagging may be sufficient though. At the moment, however, 
>>>>>>>>>> our
>>>>>>>>>> effort is focused on the platform implementation of Observables.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Will this feature be supported on all six Blink platforms
>>>>>>>>>> (Windows, Mac, Linux, ChromeOS, Android, and Android WebView)?
>>>>>>>>>> Yes
>>>>>>>>>>
>>>>>>>>>> Is this feature fully tested by web-platform-tests
>>>>>>>>>> <https://chromium.googlesource.com/chromium/src/+/main/docs/testing/web_platform_tests.md>
>>>>>>>>>> ? Yes
>>>>>>>>>>
>>>>>>>>>> See https://wpt.fyi/results/dom/observable/tentative.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Flag name on about://flags observable-api
>>>>>>>>>>
>>>>>>>>>> Finch feature name ObservableAPI
>>>>>>>>>>
>>>>>>>>>> Requires code in //chrome? False
>>>>>>>>>>
>>>>>>>>>> Tracking bug
>>>>>>>>>> https://bugs.chromium.org/p/chromium/issues/detail?id=1485981
>>>>>>>>>>
>>>>>>>>>> Estimated milestones
>>>>>>>>>> Shipping on desktop 135
>>>>>>>>>>
>>>>>>>>>> Anticipated spec changes
>>>>>>>>>>
>>>>>>>>>> Open questions about a feature may be a source of future web
>>>>>>>>>> compat or interop issues. Please list open issues (e.g. links to 
>>>>>>>>>> known
>>>>>>>>>> github issues in the project for the feature specification) whose
>>>>>>>>>> resolution may introduce web compat/interop risk (e.g., changing to 
>>>>>>>>>> naming
>>>>>>>>>> or structure of the API in a non-backward-compatible way).
>>>>>>>>>> Issues with the "possible future enhancement" label [1] track
>>>>>>>>>> possible changes to the feature that may come after we ship the 
>>>>>>>>>> initial
>>>>>>>>>> API. One issue (https://github.com/WICG/observable/issues/200)
>>>>>>>>>> is identified to have behavior changes that theoretically pose a 
>>>>>>>>>> compat
>>>>>>>>>> risk, but only for developers that subclass the API. The behavior 
>>>>>>>>>> change
>>>>>>>>>> proposed puts the implementation more inline with what subclass 
>>>>>>>>>> users want:
>>>>>>>>>> the operators that return native Observable objects would instead 
>>>>>>>>>> return
>>>>>>>>>> objects of `this.constructor` type, as to return instances of the 
>>>>>>>>>> subclass
>>>>>>>>>> that the operators are called on. This is how JS built-ins like 
>>>>>>>>>> `Array`
>>>>>>>>>> work, however, no other web platform feature works like this and it 
>>>>>>>>>> likely
>>>>>>>>>> requires non-trivial Web IDL support. [1]:
>>>>>>>>>> https://github.com/WICG/observable/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22possible%20future%20enhancement%22
>>>>>>>>>>
>>>>>>>>>> Link to entry on the Chrome Platform Status
>>>>>>>>>> https://chromestatus.com/feature/5154593776599040?gate=5141110901178368
>>>>>>>>>>
>>>>>>>>>> Links to previous Intent discussions Intent to Prototype:
>>>>>>>>>> https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAP-uykBH1%3DUoLN6%3DBRSEZE%2B1iUq6UdcTpo3qtTQ5T%3DSRxwnu5Q%40mail.gmail.com
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> This intent message was generated by Chrome Platform Status
>>>>>>>>>> <https://chromestatus.com>.
>>>>>>>>>>
>>>>>>>>> --
>>>>>>> You received this message because you are subscribed to the Google
>>>>>>> Groups "blink-dev" group.
>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>> send an email to blink-dev+unsubscr...@chromium.org.
>>>>>>> To view this discussion visit
>>>>>>> https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAJ5xic-3d9ziBOmqHYiSGPxLmDzhu19vfbQHffqJSkprFcE%2Btg%40mail.gmail.com
>>>>>>> <https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAJ5xic-3d9ziBOmqHYiSGPxLmDzhu19vfbQHffqJSkprFcE%2Btg%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>>>>>> .
>>>>>>>
>>>>>> --
>> You received this message because you are subscribed to the Google Groups
>> "blink-dev" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to blink-dev+unsubscr...@chromium.org.
>> To view this discussion visit
>> https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAP-uykDqj_RgJ8xkPvkgxeGqVbj9vHbipMuzMjR35fH%3DpY-NJw%40mail.gmail.com
>> <https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAP-uykDqj_RgJ8xkPvkgxeGqVbj9vHbipMuzMjR35fH%3DpY-NJw%40mail.gmail.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"blink-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to blink-dev+unsubscr...@chromium.org.
To view this discussion visit 
https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAOMQ%2Bw_U3Wa45QJKUB-ned8EVoHCjKJgC5ECNjLsR7Or%3D_kv%3DQ%40mail.gmail.com.

Reply via email to