Re: Jan 29 TC39 Meeting Notes
Le 09/02/2013 00:39, Claude Pache a écrit : Since BC is not an issue, let's pick the semantic that is most conform to the existing Ecmascript object model, and let's not invent a weird: true property descriptor just because we think that __proto__ deserves one. The goal is to standardise the least weird thing possible. Indeed, backward-compat doesn't care. *The* goal if any is to standardize the minimum set of properties that the web relies on (and Microsoft can implement to support existing mobile websites (ab)using __proto__). In my opinion, a couple of properties should go along: * it should be compulsory that __proto__ was deletable * It would be preferable that there was no usable extractable setter (because it increases attack opportunities). * it would be preferable that __proto__ doesn't work on non-extensible objects. Beyond that, any detail, as long as it's localized to Object.prototype, is unimportant. Although __proto__ reaches the spec, it doesn't make it a feature people should be encouraged to use. In my opinion, the only thing devs should know about is that it's a de-facto standard, in the spec because of economical constraints and that the only thing they should do with it is delete Object.prototype.__proto__ (which is why anything beyond __proto__ must be deletable is at most a preference, in my opinion again). Given that the good practice is to delete __proto__, both conforming to what exists in the object model and aiming at the least weird thing possible are probably over-engineering; magic: true is as bad as any other idea. Coin tossing is as good as any other mean to decide the details. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
Rick Waldron wrote: # January 29 2013 Meeting Notes * @@create is a well known symbol that when used as a property of a constructor provides the alloca1on method for that constructor. * New definition of the ordinary [[Construct]] : 1. Let creator be [[Get]] of this constructors @@create property 2. If creator is not undefined, then a. Let obj be the result of calling creator with this constructor as its this value. 3. Else, fallback implementation a. Let obj be a new ordinary object with its [[Prototype]] initialized from this constructor's “prototype” property. 4. Call this constructor with obj as the this value and the original argument list. 5. Return obj. BE, EA, YK, WH, others: Get rid of the fallback implementation and just throw if there is no @@create. It's unnecessary complexity. * Most constructors just inherit Function.prototype[@@create] which allocates a new ordinary object with its [[Prototype]] initialized from this.prototype (the constructor’s “prototype” property). * `new Foo() = Foo.call(Foo[@@create]())` There are ...args, so this is in fact `new Foo(...args) = Foo.call(Foo[@@create](), ...args)` I would argue this is wrong semantic, it should be `new Foo(...args) = Foo[@@create]().constructor(...args)` At least for builtins are classes, this is attainable. For userland contructor functions, this would break, so they probably need the old semantics; but there is yet another possibility, I'll show it below[1]. **Conclusion/Resolution** Consensus on @@create, allocation and initialization decoupling. Let us assume we want to simulate classic class-based OOP semantics. There are three roles here, they should be explicitly declared to the members of the show: * Class identity: this is one that * holds statics * is used in `new Foo` * is used in `extends Foo` This is currently played by the function Foo, with [[Construct]]. Note: deliberately missing [[Call]]ability. It is not really needed. More[2] below. * Allocator of new instance Makes the new uninitalized instance, with necessary magic. This is now played by Foo[@@create]. * Initializer of an instance: this is one that * initializes new instance of Foo in `new Foo` * initializes new instance of SubFoo in `super(...args)` in `new SubFoo`. (do someone really think these are separate? I think they are the same) This is schizophrenic now. Sometimes, this is played by function Foo, sometimes this is played by (potetially different or nonexisting) `Foo.prototype.constructor`. Plus, there is fourth thing/role: knowledge own class. An instance wants to know its class (as it Class identity described above), to have access to its own statics (dynamically) and ability to use `new`. This is much like smalltalk's `#class`. It is now played by `constructor`, but very poorly, since it is often missing because of rewriting `.prototype`. All of these four thing are needed; and third is schizophrenic and fourth is missing. I think the object model regarding `new` etc. should be reformed a bit more (@@create was great first step). By my suggestion of `new Foo(...args) = Foo[@@create]().constructor(...args)` I tried to solve the schizophreny of the third one. If this could be attained, the third role could _always_ be played by `Foo.prototype.constructor`. To solve the fourth, I would propose (at least a though experiment) in which it is an invariant that (new Foo).constructor === Foo`, that is, `constructor` always points to the creator class in case of instances created via `new`. For `class`es (and builtins) this can be achieved easily: write-protect `Foo.prototype` (it is in case of `class` and I would presume it is for builtins, as well) and write-protect `Foo.prototype.constructor` as well. For free userland constructor functions, this is more of a problem. They can have their .prototype rewritten, and / or .constructor with their .prototype. Now I propose the little breaking change (I would like to hear how much breaking it is, if you have the opinion, or even data): legacy constructor functions will have not only .prototype create, but also [@@behaviour] object behind the scenes where: * `Foo[@@behaviour].__proto__ === Foo.prototype` (whenever the Foo.prototype is changed, new [@@behaviour] should be recreated) * default Foo[@@create] would set __proto__ of new instance to [@@behaviour], not to .prototype. * [@@behaviour] will have write-protected .constructor pointing to `Foo` An obvious optimization which saves a lot of unnecessary allocation is: only create [@@behaviour] lazily when first `new Foo` actually happens (majority of constructor function never really [[Construct]]). (For classes and builtins, let's say [@@behaviuor] will always return .prototype) What this means, (new Foo).constructor is always Foo. The question is: is this too breaking? Is there a code that changes .constructor
Re: Jan 29 TC39 Meeting Notes
Le 07/02/2013 18:42, Andreas Rossberg a écrit : On 7 February 2013 18:36, David Bruant bruan...@gmail.com wrote: I hardly understand the benefit of an inconditionally-throwing setter over a __proto__ as data property, but I'm fine with either. Well, it _is_ a setter, and even one that modifies its receiver, not its holder. What would be the benefit of pretending it's not? It _is_ an abomination (arguably, it even __is__ an abomination). Any resemblance to real ECMAScript construct, living or dead (?), is purely coincidental. From the notes, a quote from Allen is involves magic. I don't think I will surprise anyone if I say that whatever is decided for __proto__, there will be magic involved. An idea that I don't think has been suggested is to stop pretending __proto__ is something else than magic: $ Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'); { magic: true, enumerable: false, configurable: true } Quite exotic but very clear. At will, replace magic with abomination, de facto standard, wildcard, don't use __proto__ or Why did you call Object.getOwnPropertyDescriptor on __proto__ anyway?. Other better suggestions are welcome, obviously. Admittedly, the last idea may be a bit long, but that's a string, so that can be an property name. I wouldn't rule it out too quickly ;-) David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
Le 8 févr. 2013 à 16:00, David Bruant bruan...@gmail.com a écrit : Le 07/02/2013 18:42, Andreas Rossberg a écrit : On 7 February 2013 18:36, David Bruant bruan...@gmail.com wrote: I hardly understand the benefit of an inconditionally-throwing setter over a __proto__ as data property, but I'm fine with either. Well, it _is_ a setter, and even one that modifies its receiver, not its holder. What would be the benefit of pretending it's not? It _is_ an abomination (arguably, it even __is__ an abomination). Any resemblance to real ECMAScript construct, living or dead (?), is purely coincidental. From the notes, a quote from Allen is involves magic. I don't think I will surprise anyone if I say that whatever is decided for __proto__, there will be magic involved. An idea that I don't think has been suggested is to stop pretending __proto__ is something else than magic: $ Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'); { magic: true, enumerable: false, configurable: true } Quite exotic but very clear. At will, replace magic with abomination, de facto standard, wildcard, don't use __proto__ or Why did you call Object.getOwnPropertyDescriptor on __proto__ anyway?. Other better suggestions are welcome, obviously. Admittedly, the last idea may be a bit long, but that's a string, so that can be an property name. I wouldn't rule it out too quickly ;-) David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss The magic is not in the form of the '__proto__' property of the Object.prototype object, but in the action that its setter performs. Precisely, as implemented in the latest versions of Safari and Firefox (I haven't tested other browsers), Object.prototype.__proto__ acts as if it has been defined as follows: ;(function() { var getPrototypeOf = Object.getPrototypeOf Object.defineProperty(Object.prototype, '__proto__', { get: function() { return getPrototypeOf(this) } , set: function(p) { __setPrototypeOf__(this, p) } , configurable: true , enumerable: false }) })() where __setPrototypeOf__(obj, p) is some function that does the following (note the second bullet): * throws an error if obj is not an object; otherwise, * throws an error if obj is not extensible; otherwise, * fails if p is not an object; otherwise, * throws an error if obj is equal to p or is in the prototype chain of p (to avoid cycles); otherwise, * replaces the prototype of obj with p. The only part not user-implementable (and the only magic, if any,) is in the replaces the prototype of obj with p part above. However, I would find reasonable to treat __proto__ similarly to eval: so that the aforementioned __setPrototypeOf__ function is allowed to fail when it has not been called with the exact syntax obj.__proto__ = something. Anything else, including obj['__proto__'] = something, could fail. Admittedly, THAT would be black magic, but again, it is not in form the property descriptor, but in the definition of __setPrototypeOf__. —Claude ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
On Feb 8, 2013, at 10:15 AM, Claude Pache wrote: Le 8 févr. 2013 à 16:00, David Bruant bruan...@gmail.com a écrit : Le 07/02/2013 18:42, Andreas Rossberg a écrit : On 7 February 2013 18:36, David Bruant bruan...@gmail.com wrote: I hardly understand the benefit of an inconditionally-throwing setter over a __proto__ as data property, but I'm fine with either. Well, it _is_ a setter, and even one that modifies its receiver, not its holder. What would be the benefit of pretending it's not? It _is_ an abomination (arguably, it even __is__ an abomination). Any resemblance to real ECMAScript construct, living or dead (?), is purely coincidental. From the notes, a quote from Allen is involves magic. I don't think I will surprise anyone if I say that whatever is decided for __proto__, there will be magic involved. An idea that I don't think has been suggested is to stop pretending __proto__ is something else than magic: $ Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'); { magic: true, enumerable: false, configurable: true } Quite exotic but very clear. At will, replace magic with abomination, de facto standard, wildcard, don't use __proto__ or Why did you call Object.getOwnPropertyDescriptor on __proto__ anyway?. Other better suggestions are welcome, obviously. Admittedly, the last idea may be a bit long, but that's a string, so that can be an property name. I wouldn't rule it out too quickly ;-) David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss The magic is not in the form of the '__proto__' property of the Object.prototype object, but in the action that its setter performs. Precisely, as implemented in the latest versions of Safari and Firefox (I haven't tested other browsers), Object.prototype.__proto__ acts as if it has been defined as follows: ;(function() { var getPrototypeOf = Object.getPrototypeOf Object.defineProperty(Object.prototype, '__proto__', { get: function() { return getPrototypeOf(this) } , set: function(p) { __setPrototypeOf__(this, p) } , configurable: true , enumerable: false }) })() where __setPrototypeOf__(obj, p) is some function that does the following (note the second bullet): * throws an error if obj is not an object; otherwise, * throws an error if obj is not extensible; otherwise, * fails if p is not an object; otherwise, * throws an error if obj is equal to p or is in the prototype chain of p (to avoid cycles); otherwise, * replaces the prototype of obj with p. The only part not user-implementable (and the only magic, if any,) is in the replaces the prototype of obj with p part above. However, I would find reasonable to treat __proto__ similarly to eval: so that the aforementioned __setPrototypeOf__ function is allowed to fail when it has not been called with the exact syntax obj.__proto__ = something. Anything else, including obj['__proto__'] = something, could fail. Admittedly, THAT would be black magic, but again, it is not in form the property descriptor, but in the definition of __setPrototypeOf__. —Claude The magic that was being proposed at the meeting was that Object.getOwnPropertyDescriptor(Object.prototype,__proto__} would return an accessor property descriptor whose set property (and get??) was a function like: function () {throw new TypeErrorException} This violates the mundane inherited accessor property equivalence for situations like: obj.__proto__ = foo; and Object.getOwnPropertyDescriptor(Object.prototype,__proto__).set.call(obj,foo); But such a relationship between [[Get]] or [[Set]] and [[GetOwnProperty]] has never been identified as an essential invariant and it is easy to create a proxy that does not have that behavior. So what was proposed is only magic from the perspective of ordinary objects. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
Le 08/02/2013 19:35, Allen Wirfs-Brock a écrit : On Feb 8, 2013, at 10:15 AM, Claude Pache wrote: The magic is not in the form of the '__proto__' property of the Object.prototype object, but in the action that its setter performs. You're assuming it's a setter already, but that's not a given. Even Firefox's recent accessor has some weirdnesses [1], making it not-such-an-accessor. Precisely, as implemented in the latest versions of Safari and Firefox (I haven't tested other browsers) In Chrome and Node, Object.getOwnPropertyDescriptor(Object.prototype, '__proto__') is undefined. From that (and the fact that Firefox move to a setter is recent), we can conclude that the backward-compat story is no one cares about this detail. The magic that was being proposed at the meeting was that Object.getOwnPropertyDescriptor(Object.prototype,__proto__} would return an accessor property descriptor whose set property (and get??) was a function like: function () {throw new TypeErrorException} This violates the mundane inherited accessor property equivalence for situations like: obj.__proto__ = foo; and Object.getOwnPropertyDescriptor(Object.prototype,__proto__).set.call(obj,foo); But such a relationship between [[Get]] or [[Set]] and [[GetOwnProperty]] has never been identified as an essential invariant and it is easy to create a proxy that does not have that behavior. So what was proposed is only magic from the perspective of ordinary objects. I'm somewhat surprised any form of consistency with existing properties/invariant is discussed at all. __proto__ is in ES6 as a de-facto standard. What is needed is obj.__proto__ = obj2 to work. To avoid problems, it should be possible to delete __proto__, and it'd be preferable to avoid having an extractable usable setter (the goal is to de-facto standardize, lipstick isn't necessary). *Any* solution in these constraints in acceptable. Accessor? data? magic:true property? That's all the same. Backward-compat doesn't care. I understand from the notes that the topic had some... emotion to it. Toss a 3-sided coin at next TC39 meeting? David [1] https://twitter.com/olov/status/298395329945030657 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
Le 08/02/2013 23:07, David Bruant a écrit : *Any* solution in these constraints in acceptable. Accessor? data? magic:true property? That's all the same. Backward-compat doesn't care. I forgot to say that in my opinion, any JS dev in his/her right mind would start any new script with: use strict; delete Object.prototype.__proto__ Object.freeze(Object.prototype); Making the details of __proto__ not-so-important. Legitimate __proto__ use cases are covered by extends in the class syntax. No need to keep that around. Very much like any web dev in their right mind start their CSS with *{ box-sizing: border-box; } I understand from the notes that the topic had some... emotion to it. Toss a 3-sided coin at next TC39 meeting? Please record the video if you ever do that :-) David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
Le 8 févr. 2013 à 23:07, David Bruant bruan...@gmail.com a écrit : Le 08/02/2013 19:35, Allen Wirfs-Brock a écrit : On Feb 8, 2013, at 10:15 AM, Claude Pache wrote: The magic is not in the form of the '__proto__' property of the Object.prototype object, but in the action that its setter performs. You're assuming it's a setter already, but that's not a given. Even Firefox's recent accessor has some weirdnesses [1], making it not-such-an-accessor. The behaviour described in [1] is regular: {}.__proto__ is equal to Object.prototype.__proto__ by prototypal inheritance, which is a setter that fails silently when fed with a non-object; and Object.create(null) has no prototype, so that setting something to *.__proto__ creates a regular data property. Please blame the ES5 object model, not __proto__. Precisely, as implemented in the latest versions of Safari and Firefox (I haven't tested other browsers) In Chrome and Node, Object.getOwnPropertyDescriptor(Object.prototype, '__proto__') is undefined. From that (and the fact that Firefox move to a setter is recent), we can conclude that the backward-compat story is no one cares about this detail. Since BC is not an issue, let's pick the semantic that is most conform to the existing Ecmascript object model, and let's not invent a weird: true property descriptor just because we think that __proto__ deserves one. The magic that was being proposed at the meeting was that Object.getOwnPropertyDescriptor(Object.prototype,__proto__} would return an accessor property descriptor whose set property (and get??) was a function like: function () {throw new TypeErrorException} This violates the mundane inherited accessor property equivalence for situations like: obj.__proto__ = foo; and Object.getOwnPropertyDescriptor(Object.prototype,__proto__).set.call(obj,foo); But such a relationship between [[Get]] or [[Set]] and [[GetOwnProperty]] has never been identified as an essential invariant and it is easy to create a proxy that does not have that behavior. So what was proposed is only magic from the perspective of ordinary objects. I'm somewhat surprised any form of consistency with existing properties/invariant is discussed at all. __proto__ is in ES6 as a de-facto standard. What is needed is obj.__proto__ = obj2 to work. To avoid problems, it should be possible to delete __proto__, and it'd be preferable to avoid having an extractable usable setter (the goal is to de-facto standardize, lipstick isn't necessary). *Any* solution in these constraints in acceptable. Accessor? data? magic:true property? That's all the same. Backward-compat doesn't care. The goal is to standardise the least weird thing possible. Indeed, backward-compat doesn't care. —Claude I understand from the notes that the topic had some... emotion to it. Toss a 3-sided coin at next TC39 meeting? David [1] https://twitter.com/olov/status/298395329945030657 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
Le 07/02/2013 17:25, Rick Waldron a écrit : ## __proto__. YK: We just need compatibility LH: We need to just suck it up and standardize :-) YK/BE: Discussion re: interop with current implementations. BE: (Review of latest changes to __proto__ in Firefox) EA: Matches Safari BE: __proto__ is configurable (can be deleted), accessor (getter and setter throw), reflection does not leak. AWB: Involves magic BE: Yes, but minimal. (Confirms that latest __proto__ is out in wild, Firefox) WH: Clarify poisoning? BE: When you call it, it throws. WH: So how does it know when not to throw? (If it always throws then it won't work.) EA: Throws if called with object and setter coming from different realms …Discussion re: MOP semantics with __proto__ BE: Proxy has to stratify the MOP. Speaking of proxies, what should happen in the following case (setter and proxy from same realm): var protoSetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set var p = new Proxy({}, handler); protoSetter.call(p, {}); ? Ideas: 1) add a setPrototypeOf trap 2) throw because it's a proxy (which wouldn't be entirely absurd since extracting the setter shouldn't be encouraged). This problem is inexistent with a data property. Is an extractable setter *required* for web-compatibility? I've seen lots of use of __proto__ as a pseudo property, but no one extracting the setter yet. AWB: Another issue… Objects that are non-extensible, can you change __proto__? Specifically, now that we're talking about being able to change __proto__, what type of objects can be changed? BE: Wait for Mark? YK?: Changing __proto__ is a write, not adding a property, so it should not be affected by extensibility. AWB: Agree How can one defend itself against abusive __proto__ modification? __proto__ becoming standard, delete Object.prototype.__proto__ is hardly a reliable option, because more code will rely on its existence. If that's not the [[Extensible]] boolean, another boolean has to be added. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
On 7 February 2013 18:09, David Bruant bruan...@gmail.com wrote: Speaking of proxies, what should happen in the following case (setter and proxy from same realm): var protoSetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set var p = new Proxy({}, handler); protoSetter.call(p, {}); ? The property descriptor for Object.prototype.__proto__ will contain a poisoned setter that always throws. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
Le 07/02/2013 18:22, Andreas Rossberg a écrit : On 7 February 2013 18:09, David Bruant bruan...@gmail.com wrote: Speaking of proxies, what should happen in the following case (setter and proxy from same realm): var protoSetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set var p = new Proxy({}, handler); protoSetter.call(p, {}); ? The property descriptor for Object.prototype.__proto__ will contain a poisoned setter that always throws. So what does the following mean: EA: Throws if called with object and setter coming from different realms ? I hardly understand the benefit of an inconditionally-throwing setter over a __proto__ as data property, but I'm fine with either. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
On 7 February 2013 18:36, David Bruant bruan...@gmail.com wrote: Le 07/02/2013 18:22, Andreas Rossberg a écrit : On 7 February 2013 18:09, David Bruant bruan...@gmail.com wrote: Speaking of proxies, what should happen in the following case (setter and proxy from same realm): var protoSetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set var p = new Proxy({}, handler); protoSetter.call(p, {}); ? The property descriptor for Object.prototype.__proto__ will contain a poisoned setter that always throws. So what does the following mean: EA: Throws if called with object and setter coming from different realms ? I hardly understand the benefit of an inconditionally-throwing setter over a __proto__ as data property, but I'm fine with either. Well, it _is_ a setter, and even one that modifies its receiver, not its holder. What would be the benefit of pretending it's not? /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 29 TC39 Meeting Notes
On Feb 7, 2013, at 9:09 AM, David Bruant bruan...@gmail.com wrote: Le 07/02/2013 17:25, Rick Waldron a écrit : ## __proto__. Discussion re: MOP semantics with __proto__ BE: Proxy has to stratify the MOP. Speaking of proxies, what should happen in the following case (setter and proxy from same realm): var protoSetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set var p = new Proxy({}, handler); protoSetter.call(p, {}); ? Ideas: 1) add a setPrototypeOf trap 2) throw because it's a proxy (which wouldn't be entirely absurd since extracting the setter shouldn't be encouraged). I think most favored (2) for all arguments, but we need to confirm. This problem is inexistent with a data property. Is an extractable setter *required* for web-compatibility? I've seen lots of use of __proto__ as a pseudo property, but no one extracting the setter yet. Of course, because until very recently __proto__ has only ever reflected as a data property. We were going to spec it that way, but implementors felt it more regular to reflect as an accessor. But they also preferred to build in a realm check, rather than poisoning reflected setter and getter. Here we are! AWB: Another issue… Objects that are non-extensible, can you change __proto__? Specifically, now that we're talking about being able to change __proto__, what type of objects can be changed? BE: Wait for Mark? YK?: Changing __proto__ is a write, not adding a property, so it should not be affected by extensibility. AWB: Agree How can one defend itself against abusive __proto__ modification? __proto__ becoming standard, delete Object.prototype.__proto__ is hardly a reliable option, because more code will rely on its existence. If that's not the [[Extensible]] boolean, another boolean has to be added. Mark reminded us that ES5 (not 6) stipulates that [[Extensible]] false prevents [[Prototype]] writes. /be David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss