Intent to Ship: Push API

963 views
Skip to first unread message

John Mellor

unread,
Feb 6, 2015, 1:20:49 PM2/6/15
to blink-dev

Intent to Ship: Push API


Contact emails

joh...@chromium.org, mvanou...@chromium.org, pe...@chromium.org, mlam...@chromium.org (eng)

owe...@chromium.org (PM)


Spec

https://w3c.github.io/push-api/


Summary

This enables developers to send a push message to their Service Worker even after a tab has been closed so they can display a notification and perform additional background tasks such as updating caches.


This intent is for a cohesive subset of the full Push API and we intend to expand our implementation over time as we receive feedback and observe data from users and developers. See limitations section below for more details.


Link to “Intent to Implement” blink-dev discussion

https://groups.google.com/a/chromium.org/d/msg/blink-dev/GLXyXABvA_0/MYPeVxxfGfcJ


Link to demo

https://johnme-gcm.appspot.com/chat/


Is this feature supported on all five Blink platforms (Windows, Mac, Linux, Chrome OS, WebView, Android)?

It will initially support everything but WebView. On Android we will only support 4.1 and up, since this feature depends on the Web Notifications API, which in turn depends on notification support introduced in Android 4.1.


Compatibility Risk

Medium to large; this is a new large feature and Chrome is the first to ship it.


We currently require sites to display a Web Notification in response to an incoming message (a notification will be created on the app’s behalf if it fails to do so). This helps ensure they are aware of background execution.


Developers need to specify the "gcm_user_visible_only" key in their Manifest file to indicate that they understand this requirement.


Limitations

1) Chrome’s implementation uses Google Cloud Messaging (GCM) as the push service to which messages have to be pushed by the developer. We participate in the standardization of an app-server to push-service protocol at the IETF, in order to minimize differences between push services from the developer’s perspective.


For now, the site must specify their GCM sender ID (obtained via the Google Developer Console) in their Manifest file using the "gcm_sender_id" key.


2) Due to security concerns, incoming push messages will not yet support payloads. Until we do, developers can use the fetch() method to check the latest state with their server when they receive a push message.


OWP launch tracking bug?

https://crbug.com/349474


Link to entry on the feature dashboard

https://www.chromestatus.com/feature/5416033485586432

Alex Russell

unread,
Feb 6, 2015, 1:45:07 PM2/6/15
to John Mellor, blink-dev

I'm grateful that this has been developed with an eye for removing the GCM specific bits and with a credible plan for getting it done. Iteration matters a ton, and I'm also excited the team is committing to that aspect and shipping stable bits now.

To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.

Chris Harrelson

unread,
Feb 6, 2015, 7:36:05 PM2/6/15
to Alex Russell, John Mellor, blink-dev
Can you point to positive signals from other vendors?

Alex Russell

unread,
Feb 6, 2015, 10:03:42 PM2/6/15
to Chris Harrelson, blink-dev, John Mellor, Jonas Sicking

This has been developed in close collaboration with Mozilla. Their requirements have led to many changes, including dropping message bodies.

I'm not aware of public statements regarding implementation status, however. +Sicking

Philip Jägenstedt

unread,
Feb 10, 2015, 2:46:33 AM2/10/15
to John Mellor, blink-dev
Hi John, this sounds like good stuff!

https://crbug.com/349474 is 403 Forbidden, can you make it public?

I've compared the IDL interfaces in spec and implementation, and the
big difference is PushEvent.data, as you explained. By the way, what
are the security concerns?

The other difference is that the pushsubscriptionchange event is
missing. Will this be implemented, or doesn't it make sense for GCM?

About "gcm_user_visible_only", I tried to follow it in the code and I
think the only effect it has is in
PushMessagingServiceImpl::RegisterFromDocument, where we reach
PUSH_REGISTRATION_STATUS_PERMISSION_DENIED if it's not set. If this is
all it does, it risks becomes de-facto required boilerplate of the
format even though it doesn't do anything. What bad things are
expected to happen if this requirement were removed?

Finally, since this is implemented using a Google service (GCM), will
there be any restrictions, quotas or licensing required for non-Google
browsers like Opera for Android? (I know next to nothing about GCM.)

Philip

John Mellor

unread,
Feb 10, 2015, 11:56:58 AM2/10/15
to Philip Jägenstedt, blink-dev
On 10 February 2015 at 07:46, Philip Jägenstedt <phi...@opera.com> wrote:
Hi John, this sounds like good stuff!

https://crbug.com/349474 is 403 Forbidden, can you make it public?

I'm looking into this (it's a launch bug, where Privacy/Legal/etc signoff, and these are traditionally confidential). In the meantime, our implementation bug is https://crbug.com/350378 and our bug label is Fizz-Push.

I've compared the IDL interfaces in spec and implementation, and the
big difference is PushEvent.data, as you explained. By the way, what
are the security concerns?
 
Our security team would like to require push message payloads to be end-to-end encrypted, but standardizing a suitable encryption protocol for this is a multi-month(/year?) endeavour. We'd like to do that eventually, but in the short term a safe option is for the push message to have no payload, and instead let the Service Worker request the payload over HTTPS using the fetch method. It's a little less efficient, and it may require the web app's server to store a queue of recently sent messages (instead of being stateless), but on the plus side it's probably easier for server developers than implementing encryption with key rotation would have been.

The other difference is that the pushsubscriptionchange event is
missing. Will this be implemented, or doesn't it make sense for GCM?

Currently, it's very rare for GCM to invalidate a push subscription (and if it does, it doesn't communicate this to the device anyway). Once payloads can be encrypted, this event might become used for key rotation, but for now it seems that implementing a placeholder event that we never fire would have no benefit (and cause unnecessary compatibility problems later if that part of the spec changes).

About "gcm_user_visible_only", I tried to follow it in the code and I
think the only effect it has is in
PushMessagingServiceImpl::RegisterFromDocument, where we reach
PUSH_REGISTRATION_STATUS_PERMISSION_DENIED if it's not set. If this is
all it does, it risks becomes de-facto required boilerplate of the
format even though it doesn't do anything. What bad things are
expected to happen if this requirement were removed?

I mentioned above that we

currently require sites to display a Web Notification in response to an incoming message. However we're actively working on also supporting silent push messaging use cases (e.g. syncing without any notification when a shared document was edited remotely). Once we support those, this manifest property will no longer be required (it's there to make sure developers understand the current notification requirement).


Finally, since this is implemented using a Google service (GCM), will
there be any restrictions, quotas or licensing required for non-Google
browsers like Opera for Android? (I know next to nothing about GCM.)

GCM is free to use for all Android apps, with no global quota (indeed Android apps are strongly encouraged to use it rather than other push services, since holding additional persistent network connections would waste battery).

Dimitri Glazkov

unread,
Feb 10, 2015, 3:38:41 PM2/10/15
to John Mellor, Philip Jägenstedt, blink-dev
LGTM.

:DG<

Philip Rogers

unread,
Feb 10, 2015, 5:56:31 PM2/10/15
to Dimitri Glazkov, John Mellor, Philip Jägenstedt, blink-dev
LGTM

This will let us build incredibly useful webapps like chat, and Alex assures me at the product level we have safeguards against spam behavior.

On Tue, Feb 10, 2015 at 12:38 PM, Dimitri Glazkov <dgla...@chromium.org> wrote:
LGTM.

:DG<

b.ke...@samsung.com

unread,
Feb 10, 2015, 10:51:32 PM2/10/15
to blin...@chromium.org, phi...@opera.com, joh...@google.com
 
About "gcm_user_visible_only", I tried to follow it in the code and I
think the only effect it has is in
PushMessagingServiceImpl::RegisterFromDocument, where we reach
PUSH_REGISTRATION_STATUS_PERMISSION_DENIED if it's not set. If this is
all it does, it risks becomes de-facto required boilerplate of the
format even though it doesn't do anything. What bad things are
expected to happen if this requirement were removed?

I mentioned above that we

currently require sites to display a Web Notification in response to an incoming message. However we're actively working on also supporting silent push messaging use cases (e.g. syncing without any notification when a shared document was edited remotely). Once we support those, this manifest property will no longer be required (it's there to make sure developers understand the current notification requirement).



Could you elaborate on how this is actually enforced? My understanding is that the push message awakes the service-worker and the ball is passed to js. How is the script enforced to display a notification and not doing something else?

Another thing I'm wondering about is this: if eventually the service-worker will be allowed to do background work, how can we still provide the user control over when and for what extent background networking should happen (letting alone cpu and power use)? I.e. I can imagine a news site wants to amaze me with super fast loading by informing it's service worker every time there is an update which in turn keeps my data connection busy - and potentially burning my money - by pre-caching the new content every once in a while.

Cool feature btw.

Best regards,
  Balazs

Philip Jägenstedt

unread,
Feb 10, 2015, 11:28:46 PM2/10/15
to John Mellor, blink-dev
On Tue, Feb 10, 2015 at 11:56 PM, 'John Mellor' via blink-dev
<blin...@chromium.org> wrote:
> On 10 February 2015 at 07:46, Philip Jägenstedt <phi...@opera.com> wrote:
>>
>> Hi John, this sounds like good stuff!
>>
>> https://crbug.com/349474 is 403 Forbidden, can you make it public?
>
>
> I'm looking into this (it's a launch bug, where Privacy/Legal/etc signoff,
> and these are traditionally confidential). In the meantime, our
> implementation bug is https://crbug.com/350378 and our bug label is
> Fizz-Push.

Thanks, I trust there's nothing relevant to the API itself in the
launch bug then :)

>> I've compared the IDL interfaces in spec and implementation, and the
>> big difference is PushEvent.data, as you explained. By the way, what
>> are the security concerns?
>
>
> Our security team would like to require push message payloads to be
> end-to-end encrypted, but standardizing a suitable encryption protocol for
> this is a multi-month(/year?) endeavour. We'd like to do that eventually,
> but in the short term a safe option is for the push message to have no
> payload, and instead let the Service Worker request the payload over HTTPS
> using the fetch method. It's a little less efficient, and it may require the
> web app's server to store a queue of recently sent messages (instead of
> being stateless), but on the plus side it's probably easier for server
> developers than implementing encryption with key rotation would have been.

I see. I suppose this will put Web apps at a disadvantage compared to
native apps as it adds an extra RTT, but it's sure better than not
having push notifications at all!

>> The other difference is that the pushsubscriptionchange event is
>> missing. Will this be implemented, or doesn't it make sense for GCM?
>
>
> Currently, it's very rare for GCM to invalidate a push subscription (and if
> it does, it doesn't communicate this to the device anyway). Once payloads
> can be encrypted, this event might become used for key rotation, but for now
> it seems that implementing a placeholder event that we never fire would have
> no benefit (and cause unnecessary compatibility problems later if that part
> of the spec changes).

I very much agree, adding the onpushsubscriptionchange attribute when
the event can never be fired would be terrible for feature detection.

>> About "gcm_user_visible_only", I tried to follow it in the code and I
>> think the only effect it has is in
>> PushMessagingServiceImpl::RegisterFromDocument, where we reach
>> PUSH_REGISTRATION_STATUS_PERMISSION_DENIED if it's not set. If this is
>> all it does, it risks becomes de-facto required boilerplate of the
>> format even though it doesn't do anything. What bad things are
>> expected to happen if this requirement were removed?
>
>
> I mentioned above that we
>
> currently require sites to display a Web Notification in response to an
> incoming message. However we're actively working on also supporting silent
> push messaging use cases (e.g. syncing without any notification when a
> shared document was edited remotely). Once we support those, this manifest
> property will no longer be required (it's there to make sure developers
> understand the current notification requirement).

I don't know, this seems rather odd to me. Will the property continue
to do nothing once it's not required, or will it preserve the current
behavior?

API owners, what do you think about this required bit of boilerplate?

>> Finally, since this is implemented using a Google service (GCM), will
>> there be any restrictions, quotas or licensing required for non-Google
>> browsers like Opera for Android? (I know next to nothing about GCM.)
>
>
> GCM is free to use for all Android apps, with no global quota (indeed
> Android apps are strongly encouraged to use it rather than other push
> services, since holding additional persistent network connections would
> waste battery).
> https://developer.android.com/google/gcm/

Great, LGTM!

Philip

John Mellor

unread,
Feb 11, 2015, 12:59:53 PM2/11/15
to b.ke...@samsung.com, blink-dev, Philip Jägenstedt
On 11 February 2015 at 03:51, <b.ke...@samsung.com> wrote:
On Tue, Feb 10, 2015 at 11:56 PM, John Mellor wrote: 
I mentioned above that we

currently require sites to display a Web Notification in response to an incoming message.


Could you elaborate on how this is actually enforced? My understanding is that the push message awakes the service-worker and the ball is passed to js. How is the script enforced to display a notification and not doing something else?

If the Service Worker doesn't show a notification before resolving the promise passed to event.waitUntil, we show a generic notification on its behalf (current wording: "foo.example.com has updated in the background"). Since we make it easy to revoke permission from a notification (a cog button deep links into the website settings for that origin), developers are incentivized to always show a useful notification instead of the generic one, and to not send a push message at all if there is nothing useful to tell the user. 

Another thing I'm wondering about is this: if eventually the service-worker will be allowed to do background work, how can we still provide the user control over when and for what extent background networking should happen (letting alone cpu and power use)? I.e. I can imagine a news site wants to amaze me with super fast loading by informing it's service worker every time there is an update which in turn keeps my data connection busy - and potentially burning my money - by pre-caching the new content every once in a while.

Our tentative plan for silent push messaging is that we would show a permission prompt that makes it clear that background activity will take place, combined with additional per-device throttling.

On 11 February 2015 at 04:28, Philip Jägenstedt <phi...@opera.com> wrote:
On Tue, Feb 10, 2015 at 11:56 PM, 'John Mellor' via blink-dev
<blin...@chromium.org> wrote:
> On 10 February 2015 at 07:46, Philip Jägenstedt <phi...@opera.com> wrote:
>> About "gcm_user_visible_only",

>
> I mentioned above that we
> currently require sites to display a Web Notification in response to an
> incoming message. However we're actively working on also supporting silent
> push messaging use cases (e.g. syncing without any notification when a
> shared document was edited remotely). Once we support those, this manifest
> property will no longer be required (it's there to make sure developers
> understand the current notification requirement).

I don't know, this seems rather odd to me. Will the property continue
to do nothing once it's not required, or will it preserve the current
behavior?

Because the notification requirement derives from the specification (in a way that cannot be feature-detected), we decided to use the gcm_user_visible_only property as a way for developers to say "Yes, I understand the limitation".

For this reason, but also for enabling the more advanced use-cases, removing this requirement is very high on our TODO list. Exactly what happens to the "gcm_user_visible_only" key depends on how we resolve the outstanding privacy/UX questions for silent push messaging: it'll either be ignored immediately, or deprecated and gradually replaced with a standardised way for developers to opt in to always showing a notification.

TAMURA, Kent

unread,
Feb 11, 2015, 8:21:57 PM2/11/15
to John Mellor, blink-dev
LGTM to ship.

--
TAMURA Kent
Software Engineer, Google


Philip Jägenstedt

unread,
Feb 11, 2015, 9:43:58 PM2/11/15
to John Mellor, Balazs Kelemen, blink-dev
On Thu, Feb 12, 2015 at 12:59 AM, John Mellor <joh...@google.com> wrote:
> On 11 February 2015 at 04:28, Philip Jägenstedt <phi...@opera.com> wrote:
>>
>> On Tue, Feb 10, 2015 at 11:56 PM, 'John Mellor' via blink-dev
>> <blin...@chromium.org> wrote:
>> > On 10 February 2015 at 07:46, Philip Jägenstedt <phi...@opera.com>
>> > wrote:
>> >> About "gcm_user_visible_only",
>> >
>> > I mentioned above that we
>> > currently require sites to display a Web Notification in response to an
>> > incoming message. However we're actively working on also supporting
>> > silent
>> > push messaging use cases (e.g. syncing without any notification when a
>> > shared document was edited remotely). Once we support those, this
>> > manifest
>> > property will no longer be required (it's there to make sure developers
>> > understand the current notification requirement).
>>
>> I don't know, this seems rather odd to me. Will the property continue
>> to do nothing once it's not required, or will it preserve the current
>> behavior?
>
>
> Because the notification requirement derives from the specification (in a
> way that cannot be feature-detected), we decided to use the
> gcm_user_visible_only property as a way for developers to say "Yes, I
> understand the limitation".

There are many APIs which aren't quite per spec or with limitations,
and AFAIK we never ask Web developers to confirm that they understand
this with some mandatory bit of markup. Anything mandatory just
becomes boilerplate to be copied from examples, so it seems unlikely
to be very effective.

But if no one else thinks this seems more harmful than useful, very well.

Philip

Alex Russell

unread,
Feb 11, 2015, 10:16:02 PM2/11/15
to Philip Jägenstedt, John Mellor, Balazs Kelemen, blink-dev
I'm dubious of its value, but until we figure out some better way to communicate to developers what's going on ("why can't I send pushes that don't have notifications?") I think it's something we'll need in the short run.

PhistucK

unread,
Feb 12, 2015, 2:07:37 AM2/12/15
to Philip Jägenstedt, John Mellor, Balazs Kelemen, blink-dev
I also think it is useless. It would be a simple, "oh, in order to work in Chrome, add this property. Nevermind it, though".


PhistucK

b.ke...@samsung.com

unread,
Feb 12, 2015, 12:16:07 PM2/12/15
to blin...@chromium.org, phi...@opera.com, joh...@google.com, b.ke...@samsung.com
This is not the only requirement that doesn't come from the spec. With the current implementation you need a manifest file, and you need 2 properties: gcm_sender_id and gcm_user_visible_only. Afaik the gcm_sender_id is your google API key or something derives from that. So the thing is that gcm-ism is already shines through the implementation (not a critic, just noting). I guess people who want to use this api are likely already familiar with gcm. Now it happens to be that the user_visible_only attribute in gcm has similar semantics than what the web api provides at the moment. Along the lines of this way of thought I can understand that requiring gcm_user_visible_only might add some value since people will likely think about the api in it's current form as a direct bridge to gcm.

Imho in an ideal word none of those properties as well as the manifest file should be mandatory, and the push platform would be just an implementation detail. In the real word it is quite understandable that an api key is required to use this api though, as it gives some defend against spamming.

I guess my conclusion is that this user_visible attribute is kind of ok, however long term it might be desirable to make this api less platform specific although it's clearly a hard thing to do.

PhistucK

unread,
Feb 13, 2015, 7:55:56 AM2/13/15
to Balazs Kelemen, blink-dev, Philip Jägenstedt, John Mellor
What is this manifest?
Is there a complete example with full source code, including this manifest anywhere?

The specification does not mention any manifest, Google Cloud Messaging for Android (or for Chrome) also does not mention a manifest, as far as I read.
Where does this manifest come into play?


PhistucK

PhistucK

unread,
Feb 13, 2015, 8:06:59 AM2/13/15
to Balazs Kelemen, blink-dev, Philip Jägenstedt, John Mellor
Nevermind, I just found -

This really needs some documentation. :(

I do not understand the need for a manifest. It makes sense to me to just include whatever you need to authenticate to the push server in the message you send to the endpoint...
This makes more sense to me -
When the user permits the web application to use the push API and the ID is sent to the application server, the application server submits a registration message (with any authentication details) or something to the push server in order to make sure the push server is fine with this and reply to the web application that the push registration has succeeded (or failed).


PhistucK

Alex Russell

unread,
Feb 13, 2015, 1:28:19 PM2/13/15
to PhistucK, Balazs Kelemen, John Mellor, Philip Jägenstedt, blink-dev

Documentation will come. I'm personally quite unhappy about using the manifest as the place for this extra (temporary) metadata, but Mozilla et al strenuously objected to including an extra object in the API.

The manifest is being spec'd elsewhere and explicitly allows extensions. Not ideal, but it preserves the properties that other vendors have constrained us to uphold.

I really wish it wasn't this way, but these properties, as noted before, will go away in a matter of quarters.

PhistucK

unread,
Feb 13, 2015, 1:32:59 PM2/13/15
to Alex Russell, Balazs Kelemen, John Mellor, Philip Jägenstedt, blink-dev
Both of them? So eventually the project ID (as an example of a needed implementation detail) will have an API counterpart?
I do not really understand the need of a client API (manifest or not) for that, why not let the application server communicate that to the endpoint? Is this a security measure of some sort that I do not understand?...


PhistucK

Michael van Ouwerkerk

unread,
Feb 13, 2015, 1:42:18 PM2/13/15
to PhistucK, Alex Russell, Balazs Kelemen, John Mellor, Philip Jägenstedt, blink-dev
PhistucK: setting up the push subscription must be done from a device, because the subscription is for that device. The sender id is (salted hashed) part of the subscription id and is used for authentication and abuse prevention such as blacklisting or throttling.

Regards,

Michael

Balazs Kelemen

unread,
Feb 13, 2015, 3:26:37 PM2/13/15
to Alex Russell, PhistucK, John Mellor, Philip Jägenstedt, blink-dev
On 02/13/2015 01:28 PM, Alex Russell wrote:

Documentation will come. I'm personally quite unhappy about using the manifest as the place for this extra (temporary) metadata, but Mozilla et al strenuously objected to including an extra object in the API.

The manifest is being spec'd elsewhere and explicitly allows extensions. Not ideal, but it preserves the properties that other vendors have constrained us to uphold.

I really wish it wasn't this way, but these properties, as noted before, will go away in a matter of quarters.


This last statement sounds good on paper but I is it really feasible? As long as the push backend needs an app specific id I don't see how this requirement can be removed.

The bigger picture is that push technology as a whole - including server and client side - is not standardized, so it's quite understandable that browser implementations require some platform specific bits. I think it's much better to put those bits in the manifest file than trying to bake it into the api.

I'd like to think that with standard api and custom manifest attributes, a web developer can add the platform bits to the manifest for different vendors (at the same time) but don't necessarily have to ua-sniff and write different code for each browser.

BR
Balazs

Alex Russell

unread,
Feb 15, 2015, 5:13:00 PM2/15/15
to Balazs Kelemen, PhistucK, blink-dev, Philip Jägenstedt, John Mellor

Yes, it is, and the team is moving heaven and earth to make it so, including standardising parts of the protocol between app server and push server that have been purely proprietary until now.

This is the start of a more open push ecosystem, not and endpoint.

Regards

Mounir Lamouri

unread,
Feb 18, 2015, 12:13:01 PM2/18/15
to blin...@chromium.org
A quick follow-up to say that we decided to remove the hasPermission()
method from the Push API that is going to be in M42. It was never
entirely clear whether this method should be exposed and we ended up
deciding to hide it in favour of exposing the information in the
Permissions API that should ship in M43. You can follow changes in
https://crbug.com/449178.

-- Mounir
> >> ☆*PhistucK*
> >>
> >> On Fri, Feb 13, 2015 at 2:55 PM, PhistucK <phis...@gmail.com> wrote:
> >>
> >>> What is this manifest?
> >>> Is there a complete example with full source code, including this
> >>> manifest anywhere?
> >>>
> >>> The specification does not mention any manifest, Google Cloud
> >>> Messaging for Android (or for Chrome) also does not mention a manifest, as
> >>> far as I read.
> >>> Where does this manifest come into play?
> >>>
> >>>
> >>> ☆*PhistucK*
> >>>
> >>> On Thu, Feb 12, 2015 at 7:16 PM, <b.ke...@samsung.com> wrote:
> >>>
> >>>> This is not the only requirement that doesn't come from the spec. With
> >>>> the current implementation you need a manifest file, and you need 2
> >>>> properties: gcm_sender_id and gcm_user_visible_only. Afaik the
> >>>> gcm_sender_id is your google API key or something derives from that. So the
> >>>> thing is that gcm-ism is already shines through the implementation (not a
> >>>> critic, just noting). I guess people who want to use this api are likely
> >>>> already familiar with gcm. Now it happens to be that the user_visible_only
> >>>> attribute in gcm has similar semantics than what the web api provides at
> >>>> the moment. Along the lines of this way of thought I can understand that
> >>>> requiring gcm_user_visible_only might add some value since people will
> >>>> likely think about the api in it's current form as a direct bridge to gcm.
> >>>>
> >>>> Imho in an ideal word none of those properties as well as the manifest
> >>>> file should be mandatory, and the push platform would be just an
> >>>> implementation detail. In the real word it is quite understandable that an
> >>>> api key is required to use this api though, as it gives some defend against
> >>>> spamming.
> >>>>
> >>>> I guess my conclusion is that this user_visible attribute is kind of
> >>>> ok, however long term it might be desirable to make this api less platform
> >>>> specific although it's clearly a hard thing to do.
> >>>>
> >>>>
> >>>> On Thursday, February 12, 2015 at 2:07:37 AM UTC-5, PhistucK wrote:
> >>>>>
> >>>>> I also think it is useless. It would be a simple, "oh, in order to
> >>>>> work in Chrome, add this property. Nevermind it, though".
> >>>>>
> >>>>>
> >>>>> ☆*PhistucK*
Reply all
Reply to author
Forward
0 new messages