On Nov 29, 2011, at 1:19 PM, Nicholas C. Zakas wrote:

> The reason I started down this path is because the API, as currently 
> designed, doesn't fit in with the rest of the JavaScript core language. Just 
> to summarize some of my earlier points:
> 
> 1) No part of core JavaScript uses namespaces today. Having a top-level 
> Globalization object that [does] nothing other than provide a hook onto which 
> new constructors are placed is a first and doesn't seem very useful. At the 
> very least I'd consider killing the Globalization object altogether and just 
> let the constructors exist in the global scope.

Injecting new names into the global scope is risky, since all the good names 
are already taking by user-defined globals.

The plan we discussed a few weeks ago was to use a built-in module, which could 
be imported from or declared freely in new opt-in code. Unversioned JS would 
have to use something like the

  Object.system.loadIntrinsic("@globalization")

API-sketch.

Whatever we do, it should be as future-friendly to modules as possible, and it 
shouldn't inject new global names into the shared scope of ES.next and 
unversioned scripts.


> 2) The current proposal requires that developers maintain a LocaleList object 
> and pass that into methods of NumberFormat, DateTimeFormat, and Collator 
> (assuming they don't want to use the default). Needing to keep track of an 
> object is a pain, but is lessened when that object does everything you need 
> it to. That's why I suggested having a Locale object. Yes, you'd need to keep 
> track of this object, but at least it would be one object instead of multiple 
> objects.

This still seems plausible to me. It caters to Norbert's "Customer categories" 
1 and 2, if I'm not mistaken.


> 3) The semantic difference between DateTimeFormat.isSupported(), 
> Locale.isSupported(), etc. is minimal. The point I was trying to make is that 
> the current requirements for the Globalization API don't preclude having a 
> single object. That's simply a design decision, not a huge barrier that can 
> be overcome.

Mark's point about isSupported not being binary and simplex is good, 
independent of whether objects are grouped into a Locale or not. Again if I'm 
following correctly (please tell me if not).


> Again, saying that "libraries will handle this" is too simple and 
> presumptive. You're assuming that some library a) likes what you've done 
> enough to invest in it, b) finds some advantage to this API over what it has 
> already, and c) can integrate with what they already have. You could create 
> an API that sits unused because libraries don't see any advantage to using it 
> vs. what they have already.

Again I agree with you. The flip side is that, per Mark's fine message dated 
November 28, 2011 1:13:24 PM PST, internationalization is multi-state/best-fit 
and complex, with evolving big data, user preferences in the loop.

Doing a low-level built-in library and letting others built higher-level 
abstractions is plausible based on experience with things like canvas, WebGL, 
and typed arrays. We don't get to do the perfect high-level API on short 
notice, certainly not in committee. I'm skeptical we can even do a low-level 
toolkit by next spring, with two truly independent implementations 
interoperating convincingly.

So "libraries will handle this" is the wrong guiding principle, but "let's find 
the high-level sweet spot" is high-risk without more time for experimentation 
and user testing.

I don't have any satisfying answers, but I hope this helps.

/be


> 
> -N
> 
> 
> On 11/28/2011 4:17 PM, Norbert Lindenberg wrote:
>> I'm not sure why this discussion is drifting so far in the direction of a 
>> functional API. I thought objects, constructors, and methods are all part of 
>> ECMAScript, are widely used in the language specification, in libraries, and 
>> in applications, and developers have to understand them in order to be 
>> productive in JavaScript. So what is the advantage of 
>> isSupportDateTimeFormat(locale) or isSupported("DateTimeFormat", locale) 
>> over DateTimeFormat.isSupported(locale)?
>> 
>> I thought the real question is: How do we enable simpler code for the most 
>> common use cases? For example, don't require applications to create a 
>> DateTimeFormat object when it's only used once to format a date and then 
>> disposed of, or to specify a locale list to every API call when it never 
>> changes.
>> 
>> We should also consider what should be handled by the Globalization API, and 
>> what is better left to libraries. We tend to focus on the Globalization API 
>> in this discussion because that's what we can change directly, but I think 
>> default locale management is really better handled at a higher level. See
>> https://mail.mozilla.org/pipermail/es-discuss/2011-November/018665.html
>> 
>> Specific comments on Nicholas proposal:
>> 
>> - Extensibility is a big issue: What happens if two components within one 
>> application load two incompatible word break implementations - who wins, or 
>> is there a way to keep them separate?
>> 
>> - The existing locale and parameter negotiation won't work with other 
>> services: Our current negotiation mechanism knows a lot about collators and 
>> number and date formats, and nothing about other internationalization 
>> services, and it's not designed for adaptation to such other services. This 
>> means other services have to provide their own negotiation, but that 
>> conflicts with them being part of a single Locale object.
>> 
>> - Having the Locale object store the resolved locale doesn't work because 
>> the resolved locale can vary between services for the same requested locale 
>> list. It probably makes more sense for it to store the requested locale 
>> list, and use that to negotiate against each service's capabilities. That's 
>> the approach used in YUI internationalization:
>> http://yuilibrary.com/yui/docs/intl/
>> 
>> - The Locale object as proposed doesn't seem to help the application with 
>> managing its own resources. YUI, on the other hand, provides support for 
>> this, and it seems more logical to extend the locale management in YUI to 
>> also support the services provided by the Globalization API than to have two 
>> separate mechanisms. For example, it could complement its current number 
>> formatting with a new locale sensitive function:
>> 
>> Y.DataType.Number.localeFormat = function (data, options) {
>>     if (Y.Lang.isNumber(data)) {
>>         var localeList = Y.config.lang;
>>         if (!Y.Lang.isArray(localeList)) {
>>             localeList = localeList.split(/[, ]/);
>>         }
>>         return data.toLocaleString(localeList, options);
>>     } else {
>>         // do whatever Y.DataType.Number.format does in this case
>>     }
>> }
>> 
>> Overall I think a container like the proposed Locale object may make sense 
>> at the application level, but doesn't seem like the right approach for the 
>> Globalization API.
>> 
>> Regards,
>> Norbert
>> 
>> 
>> 
>> 28. новембар 2011. 11.27, Nicholas C. Zakas<[email protected]>  је 
>> написао/ла:
>>> On 11/28/2011 9:15 AM, Nebojša Ćirić wrote:
>>>> It's my fault - I read "discussed with Norbert" as if you and Norbert 
>>>> agreed on this approach.
>>> No worries - email is hard. :)
>>> 
>>> 
>>>> We are essentially choosing beween two approaches:
>>>> 
>>>> 1. Create an object, query its properties, use object methods (original 
>>>> approach)
>>>> 2. Create Locale object, call various methods like isSupportedXXX, if 
>>>> service is supported use formatYYY or compare
>>>> 
>>>> They are very similar in what the user has to do (query capabilites, call 
>>>> formatters) to get the final result, so I don't think we would lose any 
>>>> functionality picking any of those.
>>>> 
>>>> With 1. we might end up having lots of isSupportedDate, 
>>>> isSupportedNumber... after couple of iterations of adding new features 
>>>> (like segmentation, calendars, spell check...), but if we follow the same 
>>>> naming style I don't see a problem with that.
>>> Another approach would be to have a single isSupported() method with 
>>> constants that you pass in. That limits the overall API size while still 
>>> allowing developers to query capabilities. The DOM has something similar, 
>>> though I think the globalization use case is much more appropriate: 
>>> http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMFeatures
>>> 
>>> What would be harder for a third party developer to extend:
>>> 
>>> isSupported('x') or isSupportedX()
>>> 
>>> This in case they wanted to provide a service which native implementation 
>>> doesn't support (yet).
>>> 
>>> 
>>>> As for the namespace issue, I don't see much difference between Locale and 
>>>> Globalization. We discussed Modules on the other thread and came up with:
>>>> 
>>>> Object.system.load('@g11n', callback()) {}
>>>> 
>>>> or synchronous call
>>>> 
>>>> var global = Object.system.load('@g11n') {
>>>>   return __Globalization__;
>>>> }
>>>> 
>>>> This would become module global import '@g11n' in the future. This 
>>>> approach eliminates the need of finding proper name for the namespace (and 
>>>> possibly for Locale()?).
>>> There's a difference between creating a new native type vs. creating a 
>>> namespace. The Locale approach creates a single top-level type and no other 
>>> constructors. The current approach, Globalization.*, uses Globalization 
>>> only as a namespace and has constructors hanging off of it - this isn't 
>>> something that's currently done in ECMAScript.
>>> 
>>>> Thank you for helping out. Your proposal is exactly what we need at this 
>>>> point - to help us refine our work and make it palatable to TC39 members 
>>>> :).
>>> My pleasure!
>>> 
>>> 
>>>> 24. новембар 2011. 16.47, Nicholas C. Zakas<[email protected]>  
>>>> је написао/ла:
>>>> Again, my apologies - I didn't mean to imply that Norbert agreed with any 
>>>> of this, just that a few ideas have been more solidified in my mind after 
>>>> speaking with him.
>>>> 
>>>> As a web developer who has built large-scale web sites that have been 
>>>> internationalized to dozens of countries, my main purpose in contributing 
>>>> to this discussion is to provide feedback on what I would have liked to 
>>>> see in such an API to make it useful to me.
>>>> 
>>>> The current proposal doesn't feel very JavaScript-like, and so I've been 
>>>> trying to offer alternatives that make it more JavaScript-like and, 
>>>> therefore, more likely to be used by more developers. I'm a bit concerned 
>>>> that design decisions seem to have been guided by considering the most 
>>>> complex use cases instead of the most common.
>>>> 
>>>> It is my opinion (and I can only speak for myself) that a single object to 
>>>> encompass  would represent a better API for JavaScript than adding a 
>>>> namespace, which hasn't been done to this point, and several new types, 
>>>> all of which just do one thing. That's a very Java-like approach, and I 
>>>> think JavaScript deserves better.
>>>> 
>>>> As I told Norbert, I'm very happy to lend my experience and insights to 
>>>> this process. I realize I may end up bringing things up that you all have 
>>>> discussed before - but considering that you did have a single Locale 
>>>> object at one point, I'd like to claim "great minds" think alike and 
>>>> continue discussing it. :)
>>>> 
>>>> Happy Thanksgiving.
>>>> 
>>>> -Nicholas
>>>> 
>>>> 
>>>> 
>>>> On 11/24/2011 2:44 PM, Norbert Lindenberg wrote:
>>>> I didn't agree with this approach, and Nicholas didn't claim that I did :-)
>>>> 
>>>> I'm very glad though that Nicholas is taking the time to provide feedback, 
>>>> come up with his own ideas, and discuss them with us. In the end, the 
>>>> Globalization API can only be successful if people like him are 
>>>> comfortable using the API in their projects, and explain it to others so 
>>>> that they're comfortable doing so. Right now, the feedback from him, Rick, 
>>>> several TC39 members, and others indicates significant discomfort, so we 
>>>> have some work to do. Some of that work may be changes to the API, but 
>>>> some may also be better explanation of how to use the API, directly from 
>>>> applications or in higher-level libraries.
>>>> 
>>>> More after Thanksgiving.
>>>> 
>>>> Norbert
>>>> 
>>>> 
>>>> On Nov 23, 2011, at 15:15 , Nebojša Ćirić wrote:
>>>> 
>>>> 
>>>> 23. новембар 2011. 14.32, Nicholas C. Zakas<[email protected]>   
>>>> је написао/ла:
>>>> On 11/23/2011 12:57 PM, Nebojša Ćirić wrote:
>>>> Similar approach was proposed (with locale as a top object, others under 
>>>> it) and I have nothing against it, but there are some issues with your 
>>>> approach:
>>>> 
>>>> (code == localeID)
>>>> 
>>>> Sorry for being unclear - I didn't intend for this to be a complete 
>>>> alternate proposal, just a starting point. There are definitely still 
>>>> issues that would have to be resolved.
>>>> 
>>>> I just feel we are going in circles sometimes :). I am surprised Norbert 
>>>> agreed with this approach - I think he was against top level Locale object.
>>>> 
>>>> 1. An implementation may support NumberFormat for localeID x, but not 
>>>> support DateFormat for x (it would need to do a fallback to less specific 
>>>> one, or default). That's why we have supportedLocaleOf method on each 
>>>> object.
>>>> So what you're saying is that there needs to be some way to feature detect 
>>>> support for number and date formats separately. That could be handled in 
>>>> any number of ways. One that pops to mind would be 
>>>> isDateFormatSupported()/isNumberFormatSupported() as an instance method.
>>>> 
>>>> That would probably work. We could add more methods in the future - say 
>>>> one that tells you closest locale to the current one that does support 
>>>> service in question.
>>>> 
>>>> 2. How do you convey status of option/locale resolution to the developer? 
>>>> Which options were resolved and to what value (say I ask for 'islamic' 
>>>> calendar, but we only have 'gregory' for a given locale). In our current 
>>>> proposal we expose resolvedOptions accessor on i.e. DateTimeFormat object 
>>>> instance that has 'calendar' property, so a developer can decide what to   
>>>>       do.
>>>> Thanks, I was having trouble understanding what resolvedOptions was used 
>>>> for. Could the use case be handled by having a similar object on a Locale 
>>>> instance? It seems like you could include options for available calendars 
>>>> and anything else that developers could query against, such as:
>>>> 
>>>> 
>>>>     var locale = new Locale();
>>>>     if (locale.supportedOptions.islamicCalendar){
>>>>         //foo
>>>>     }
>>>> 
>>>> You could also go a more traditional direction (at least in terms of DOM 
>>>> objects), by doing something like:
>>>> 
>>>>     Locale.CALENDAR_ISLAMIC = 1;
>>>>     Locale.CALENDAR_GREGORIAN = 2;
>>>> 
>>>> 
>>>>     var locale = new Locale();
>>>>     locale.isSupported(Locale.CALENDAR_ISLAMIC);
>>>> 
>>>> I think feature detection is an easily solved problem if everything else 
>>>> is in place.
>>>> 
>>>> Sometimes options can influence each other. For example:
>>>> 
>>>> 1. Ask for th locale (Thai)
>>>> 2. There are two calendars available - buddhist and gregory
>>>> 3. There are two numbering systems available - thai and latin
>>>> 
>>>> but only buddhist + thai and gregory + latin combinations are supported.
>>>> 
>>>> If you ask locale.isSupported('calendar': 'buddhist') you'll get true. If 
>>>> you ask locale.isSupported('numberingSystem', 'latin') you'll get true 
>>>> again. If you try to format date using that combination (thai + latin) 
>>>> you'll get something you didn't expect.
>>>> 
>>>> I would propose sligthly different isSupported method:
>>>> 
>>>> locale.returnSupported(serviceName, options), where serviceName is one of 
>>>> 'dateFormat', 'numberFormat', 'collator', options object contains 
>>>> requested settings (calendar, numbering system, collation options...) and 
>>>> method returns the object with supported features for a given service.
>>>> 3. This approach would require internal caching of 
>>>> collator/dateformatter/numberformatter objects.
>>>> That's an implementation detail. I'm more interested in defining an usable 
>>>> and relatively intuitive API before worrying about optimization.
>>>> 
>>>> I agree, it's implementation detail, but you will need to pass format 
>>>> parameter to each call of .format() method. I don't think that's a big 
>>>> problem. Also I would move format and option parameters to the last 
>>>> position (can be optional), so that user can specify only value and rely 
>>>> on defaults.
>>>> 23. новембар 2011. 12.09, Nicholas C. Zakas<[email protected]>   
>>>> је написао/ла:
>>>> After meeting with Norbert to discuss the use cases and design decision 
>>>> rationale, I've come to a different understanding of the goals of the 
>>>> globalization API. Some things I learned:
>>>> 
>>>> 1. Augmenting native types with some default locale support may be 
>>>> dangerous. Consider the case where a single web page displays two modules 
>>>> with different locales. Which one wins? Therefore, "default" locale 
>>>> behavior for native types is impractical.
>>>> 2. Locale information is most frequently used for formatting numbers and 
>>>> dates as well as comparing strings. The locale information doesn't 
>>>> permeate the entire execution context.
>>>> 3. Developers are likely to want to define locale information once and 
>>>> then reuse that multiple times through a script.
>>>> 
>>>> Given this, I'd like to propose an alternate approach to the one currently 
>>>> taken in the API and also different from my initial email. It goes like 
>>>> this:
>>>> 
>>>> Have a single, top-level type called Locale defined as:
>>>> 
>>>>    function Locale(code){
>>>> 
>>>>        //whatever has to happen to process the code
>>>> 
>>>>        this.code = code;
>>>>    }
>>>> 
>>>>    /*
>>>>     * Determine if a locale is supported.
>>>>     * @param code The code to check.
>>>>     * @return True if supported, false if not.
>>>>     */
>>>>    Locale.isLocaleSupported = function(code){
>>>>        ...
>>>>    };
>>>> 
>>>>    /*
>>>>     * Replaces supportedLocalesOf
>>>>     * @param code The code to check.
>>>>     * @return Array of supported locales.
>>>>     */
>>>>    Locale.getSupportedLocales = function(code){
>>>>        ...
>>>>    };
>>>> 
>>>>    /*
>>>>     * Replaces Globalization.Collator
>>>>     * @param a The first item.
>>>>     * @param b The second item.
>>>>     * @param options (Optional) The options to use when comparing.
>>>>     * @return -1 if a comes before b, 0 if they're equal, 1 otherwise
>>>>     */
>>>>    Locale.prototype.compare = function(a, b, options){
>>>>        ...
>>>>    };
>>>> 
>>>>    /*
>>>>     * Replaces Globalization.NumberFormat
>>>>     * @param format A pattern format string for outputting the number.
>>>>     * @param value The value to format.
>>>>     * @return The number formatted as a string.
>>>>     */
>>>>     Locale.prototype.formatNumber = function(format, value){
>>>>        ...
>>>>    };
>>>> 
>>>>    /*
>>>>     * Replaces Globalization.DateFormat
>>>>     * @param format A pattern format string for outputting the date.
>>>>     * @param value The date to format.
>>>>     * @return The number formatted as a string.
>>>>     */
>>>>    Locale.prototype.formatDate = function(format, value){
>>>>        ...
>>>>    };
>>>> 
>>>> You would then be able to create a single Locale instance and have that be 
>>>> used in your script. If the constructor is used without an argument, then 
>>>> default locale information is used:
>>>> 
>>>>    var locale = new Locale();
>>>> 
>>>> If you provide a code, then that is used:
>>>> 
>>>>    var locale = new Locale("en-us");
>>>> 
>>>> If you provide multiple codes, then the first supported one is used:
>>>> 
>>>>    var locale = new Locale(["en-us", "en-gb"]);
>>>> 
>>>> Then, you can use that locale information for the other operations you 
>>>> want to do:
>>>> 
>>>>    locale.formatDate("DMYs-short", new Date());
>>>>    locale.formatNumber("##.##", 55);
>>>>    locale.compare("foo", "bar");
>>>> 
>>>> By the way, not saying this is the format pattern string that should be 
>>>> used, it's just for discussion.
>>>> 
>>>> I like having a single object to deal with instead of multiple for 
>>>> everything the API is trying to do. It seems a lot more intuitive than 
>>>> needing to manage a LocaleList that is passed into new instances of 
>>>> NumberFormat and DateFormat all the time (that's a bunch of housekeeping 
>>>> for developers).
>>>> 
>>>> Thoughts?
>>>> 
>>>> -Nicholas
>>>> 
>>>> 
>>>> 
>>>> 
>>>> On 11/21/2011 11:12 AM, Nicholas C. Zakas wrote:
>>>> As promised, more verbose feedback for the Globalization API. My general 
>>>> feeling is that the API is overly verbose for what it's doing. I'll state 
>>>> my bias up front: I'm not a fan of introducing a bunch of new types to 
>>>> handle formatting. I'd much rather have additional methods that perform 
>>>> formatting on existing objects. My feedback is mostly about eliminating 
>>>> the new constructors - which has an added bonus of eliminating the 
>>>> Globalization namespace because there would be only one constructor left: 
>>>> Collator.
>>>> 
>>>> 1. LocaleList
>>>> 
>>>> I'm not sure why this type is necessary. I don't believe that locale 
>>>> resolution is an expensive operation, and even if it is, I'd expect the 
>>>> implementation to cache the results of such resolution for later use. I'd 
>>>> just leave this as an internal construct and instruct developers to use 
>>>> arrays all the time.
>>>> 
>>>> 2. supportedLocalesOf
>>>> 
>>>> I find this method name strange - I've read it several times and am still 
>>>> not sure I fully understand what it does. Perhaps "getSupportedLocales()" 
>>>> is a better name for this method? (I always prefer methods begin with 
>>>> verbs.)
>>>> 
>>>> 3. NumberFormat
>>>> 
>>>> Number formatting seems simple enough that it could just be added as a 
>>>> series of methods on Number.prototype. The three types of formatting 
>>>> (currency, decimal, percent) could each have their own method. Currency 
>>>> formatting has relatively few options to specify, so it's method can be:
>>>> 
>>>>    /*
>>>>     * Formats the number as if it were currency
>>>>     * @param code Currency code, e.g., "EUR"
>>>>     * @param type (Optional) The way to format the currency code, "code", 
>>>> "symbol" (default),
>>>>     * @param locales - (Optional) Array of locales to use.
>>>>     */
>>>>    Number.prototype.toCurrencyString = function(code, type, locales) {
>>>>        ...
>>>>    };
>>>> 
>>>>    var num = 500;
>>>>    console.log(num.toCurrencyCode("EUR", "code"));    //"EUR 500.00"
>>>> 
>>>> 
>>>> Decimal and percent formatting options are slightly different in that they 
>>>> include significant digits options. For that, I prefer to use a formatting 
>>>> string rather than the multitude of optional properties as currently 
>>>> defined (see http://www.exampledepot.com/egs/java.text/FormatNum.html). 
>>>> The formatting string indicates must-have digits as 0 and optional digits 
>>>> as #, allowing you to very succinctly specify how you want your number to 
>>>> be output. For example:
>>>> 
>>>>    /*
>>>>     * Formats the number as a decimal string.
>>>>     * @param format Format string indicating max/min significant digits
>>>>     * @param locales (Optional) Array of locales to use.
>>>>     */
>>>>    Number.prototype.toDecimalString = function(format, locales){
>>>>        ...
>>>>    };
>>>> 
>>>>    /*
>>>>     * Formats the number as a percent string.
>>>>     * @param format Format string indicating max/min significant digits
>>>>     * @param locales (Optional) Array of locales to use.
>>>>     */
>>>>    Number.prototype.toPercentString = function(format, locales){
>>>>        ...
>>>>    };
>>>> 
>>>>    var num = 1234.567;
>>>>    console.log(numtoDecimalString("000##.##")); "01234.57"
>>>> 
>>>> 4. DateTimeFormat
>>>> 
>>>> As with NumberFormat, it seems like this could more succinctly be 
>>>> implemented as a method on Date.prototype. As its easiest:
>>>> 
>>>>    /*
>>>>     * Format a date
>>>>     * @param options The already-defined options for DateTimeFormat
>>>>     * @param locales (Optional) Array of locales to use.
>>>>     */
>>>>    Date.prototype.toFormatString = function(options, locales){
>>>>        ...
>>>>    };
>>>> 
>>>> In an ideal world, I'd like to see options overloaded so it can be an 
>>>> options object as specified now or a formatting string. I understand that 
>>>> there was a sentiment against formatting strings due to their limitations 
>>>> and edge case errors. However, I'd like to point out that any 
>>>> internationalized web application is highly likely to already be using 
>>>> formatting strings for dates, since this is pretty much how every other 
>>>> language handles date formatting. That means supporting format strings in 
>>>> JavaScript would allow application developers to reuse the settings they 
>>>> already have. As it stands now, you'd need to create two different ways of 
>>>> formatting dates for a web app: one for your server-side language and one 
>>>> for your client-side language (until the day everything is running on 
>>>> Node.js, of course). I'd prefer my client-side code to reuse settings and 
>>>> configuration that the server-side code uses, otherwise I end up with two 
>>>> very different pieces of code doing the exact same thing, and there be 
>>>> dragons.
>>>> 
>>>> -Nicholas
>>>> 
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> [email protected]
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>> 
>>>> 
>>>> 
>>>> -- 
>>>> Nebojša Ćirić
>>>> 
>>>> 
>>>> 
>>>> -- 
>>>> Nebojša Ćirić
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> [email protected]
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>> 
>>>> 
>>>> 
>>>> 
>>>> 
>>>> -- 
>>>> Nebojša Ćirić
>>> 
>>> 
>>> 
>>> -- 
>>> Nebojša Ćirić
>>> _______________________________________________
>>> es-discuss mailing list
>>> [email protected]
>>> https://mail.mozilla.org/listinfo/es-discuss
> 
> 
> _______________________________________________
> es-discuss mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to