> While the pattern-matching proposal does cover a much richer matching, it 
> still doesn't target the issue of being a statement vs an expression.  Part 
> of my initial motivation is that the evaluation of the switch returns a 
> value, which pattern-matching doesn't resolve.

That's still something a lot of people *want* to see end up in the
proposal - in fact,
https://github.com/tc39/proposal-pattern-matching/issues/116 was filed
by a TC39 committee member. I wouldn't dismiss the possibility of
pattern matching *expressions* before then.

-----

Isiah Meadows
[email protected]
www.isiahmeadows.com

On Thu, Feb 28, 2019 at 12:28 PM David Koblas <[email protected]> wrote:
>
> Isiah,
>
> While the pattern-matching proposal does cover a much richer matching,
> it still doesn't target the issue of being a statement vs an
> expression.  Part of my initial motivation is that the evaluation of the
> switch returns a value, which pattern-matching doesn't resolve.
>
> Very much enjoying the discussion,
> David
>
> On 2/28/19 12:07 PM, Isiah Meadows wrote:
> >> Using a "switch" here forces you to group classes of objects together and 
> >> then you don't get the 2nd, 3rd, 4th etc. levels of specialization that 
> >> you might later want.
> > Sometimes, this is actually *desired*, and most cases where I could've
> > used this, inheritance was not involved *anywhere*. Also, in
> > performance-sensitive contexts (like games, which *heavily* use
> > `switch`/`case`), method dispatch is *far* slower than a simple
> > `switch` statement, so that pattern doesn't apply everywhere.
> >
> > BTW, I prefer https://github.com/tc39/proposal-pattern-matching/ over
> > this anyways - it covers more use cases and is all around more
> > flexible, so I get more bang for the buck.
> >
> > -----
> >
> > Isiah Meadows
> > [email protected]
> > www.isiahmeadows.com
> >
> > On Thu, Feb 28, 2019 at 9:23 AM Naveen Chawla <[email protected]> wrote:
> >> Hi David!
> >>
> >> Your last example would, I think, be better served by classes and 
> >> inheritance, than switch.
> >>
> >> Dogs are house animals which are animals
> >> Cheetas are wild cats which are animals
> >>
> >> Each could have overridden methods, entirely optionally, where the method 
> >> gets called and resolves appropriately.
> >>
> >> The input argument could be the class name, from which it is trivial to 
> >> instantiate a new instance and get required results.
> >>
> >> Using a "switch" here forces you to group classes of objects together and 
> >> then you don't get the 2nd, 3rd, 4th etc. levels of specialization that 
> >> you might later want.
> >>
> >> All thoughts on this are welcome. Do let me know
> >>
> >> On Thu, 28 Feb 2019 at 14:06 David Koblas <[email protected]> wrote:
> >>> Naveen,
> >>>
> >>> Thanks for your observation.  The example that I gave might have been too 
> >>> simplistic, here's a more complete example:
> >>>
> >>> ```
> >>>
> >>>      switch (animal) {
> >>>      case Animal.DOG, Animal.CAT => {
> >>>          // larger block expression
> >>>          // which spans multiple lines
> >>>
> >>>          return "dry food";
> >>>        }
> >>>      case Animal.TIGER, Animal.LION, Animal.CHEETA => {
> >>>          // larger block expression
> >>>          // which spans multiple lines
> >>>
> >>>          return "fresh meat";
> >>>        }
> >>>      case Animal.ELEPHANT => "hay";
> >>>      default => { throw new Error("Unsupported Animal"); };
> >>>      }
> >>>
> >>> ```
> >>>
> >>> While you give examples that would totally work.  Things that bother me 
> >>> about the approach are, when taken to something more complex than a quick 
> >>> value for value switch you end up with something that looks like this.
> >>>
> >>> ```
> >>>
> >>>      function houseAnimal() {
> >>>
> >>>          // larger block expression
> >>>          // which spans multiple lines
> >>>
> >>>          return "dry food";
> >>>      }
> >>>
> >>>      function wildCatFood() {
> >>>
> >>>        // larger block expression
> >>>        // which spans multiple lines
> >>>
> >>>        return "fresh meat";
> >>>      }
> >>>
> >>>
> >>>      const cases = {
> >>>        [Animal.DOG]: houseAnimal,
> >>>        [Animal.CAT]: houseAnimal,
> >>>        [Animal.LION]: wildCatFood,
> >>>        [Animal.TIGER]: wildCatFood,
> >>>        [Animal.CHEETA]: wildCatFood,
> >>>      }
> >>>
> >>>      const food = cases[animal] ? cases[animal]() : (() => {throw new 
> >>> Error("Unsuppored Animal")})();
> >>>
> >>> ```
> >>>
> >>> As we all know once any language reaches a basic level of functionality 
> >>> anything is possible.  What I think is that JavaScript would benefit by 
> >>> having a cleaner approach.
> >>>
> >>> On 2/28/19 4:37 AM, Naveen Chawla wrote:
> >>>
> >>> Isn't the best existing pattern an object literal?
> >>>
> >>> const
> >>>      cases =
> >>>          {
> >>>               foo: ()=>1,
> >>>               bar: ()=>3,
> >>>               baz: ()=>6
> >>>          }
> >>>      ,
> >>>      x =
> >>>          cases[v] ?
> >>>              cases[v]() :
> >>>              99
> >>> ;
> >>>
> >>> What does any proposal have that is better than this? With optional 
> >>> chaining feature:
> >>>
> >>> const
> >>>      x =
> >>>          {
> >>>               foo: ()=>1,
> >>>               bar: ()=>3,
> >>>               baz: ()=>6
> >>>          }[v]?.()
> >>>          ||
> >>>          99
> >>> ;
> >>>
> >>> Do let me know your thoughts guys
> >>>
> >>>
> >>> On Thu, 28 Feb 2019 at 06:04 kai zhu <[email protected]> wrote:
> >>>> This is unmaintainable --
> >>>>
> >>>>      const x = v === 'foo' ? 1 : v === 'bar' ? 3 : v === 'baz' ? 6 : 99;
> >>>>
> >>>> i feel proposed switch-expressions are no more readable/maintainable 
> >>>> than ternary-operators, if you follow jslint's style-guide.  i'll like 
> >>>> to see more convincing evidence/use-case that they are better:
> >>>>
> >>>> ```javascript
> >>>> /*jslint*/
> >>>> "use strict";
> >>>> const v = "foo";
> >>>> const x = (
> >>>>      v === "foo"
> >>>>      ? 1
> >>>>      : v === "bar"
> >>>>      ? 3
> >>>>      : v === "baz"
> >>>>      ? 6
> >>>>      : 99
> >>>> );
> >>>> ```
> >>>>
> >>>> here's another example from real-world production-code, where 
> >>>> switch-expressions probably wouldn't help:
> >>>>
> >>>> ```javascript
> >>>> $ node -e '
> >>>> /*jslint devel*/
> >>>> "use strict";
> >>>> function renderRecent(date) {
> >>>> /*
> >>>>   * this function will render <date> to "xxx ago"
> >>>>   */
> >>>>      date = Math.ceil((Date.now() - new Date(date).getTime()) * 0.0001) 
> >>>> * 10;
> >>>>      return (
> >>>>          !Number.isFinite(date)
> >>>>          ? ""
> >>>>          : date < 60
> >>>>          ? date + " sec ago"
> >>>>          : date < 3600
> >>>>          ? Math.round(date / 60) + " min ago"
> >>>>          : date < 86400
> >>>>          ? Math.round(date / 3600) + " hr ago"
> >>>>          : date < 129600
> >>>>          ? "1 day ago"
> >>>>          : Math.round(date / 86400) + " days ago"
> >>>>      );
> >>>> }
> >>>>
> >>>> console.log(renderRecent(new Date().toISOString())); // "0 sec ago"
> >>>> console.log(renderRecent("2019-02-28T05:32:00Z")); // "10 sec ago"
> >>>> console.log(renderRecent("2019-02-28T05:27:30Z")); // "5 min ago"
> >>>> console.log(renderRecent("2019-02-28T05:14:00Z")); // "18 min ago"
> >>>> console.log(renderRecent("2019-02-28T03:27:00Z")); // "2 hr ago"
> >>>> console.log(renderRecent("2019-02-12T05:27:00Z")); // "16 days ago"
> >>>> console.log(renderRecent("2018-02-28T05:27:00Z")); // "365 days ago"
> >>>> '
> >>>>
> >>>> 0 sec ago
> >>>> 10 sec ago
> >>>> 5 min ago
> >>>> 18 min ago
> >>>> 2 hr ago
> >>>> 16 days ago
> >>>> 365 days ago
> >>>>
> >>>> $
> >>>> ```
> >>>>
> >>>> On 27 Feb 2019, at 13:12, David Koblas <[email protected]> wrote:
> >>>>
> >>>> Just for folks who might be interested, added a babel-plugin to see what 
> >>>> was involved in making this possible.
> >>>>
> >>>> Pull request available here -- https://github.com/babel/babel/pull/9604
> >>>>
> >>>> I'm sure I'm missing a bunch of details, but would be interested in some 
> >>>> help in making this a bit more real.
> >>>>
> >>>> Thanks
> >>>>
> >>>> On 2/26/19 2:40 PM, Isiah Meadows wrote:
> >>>>
> >>>> You're not alone in wanting pattern matching to be expression-based:
> >>>>
> >>>> https://github.com/tc39/proposal-pattern-matching/issues/116
> >>>>
> >>>> -----
> >>>>
> >>>> Isiah Meadows
> >>>> [email protected]
> >>>> www.isiahmeadows.com
> >>>>
> >>>> -----
> >>>>
> >>>> Isiah Meadows
> >>>> [email protected]
> >>>> www.isiahmeadows.com
> >>>>
> >>>>
> >>>> On Tue, Feb 26, 2019 at 1:34 PM David Koblas <[email protected]> wrote:
> >>>>
> >>>> Jordan,
> >>>>
> >>>> Thanks for taking time to read and provide thoughts.
> >>>>
> >>>> I just back and re-read the pattern matching proposal and it still fails 
> >>>> on the basic requirement of being an Expression not a Statement.  The 
> >>>> problem that I see and want to address is the need to have something 
> >>>> that removes the need to chain trinary expressions together to have an 
> >>>> Expression.
> >>>>
> >>>> This is unmaintainable --
> >>>>
> >>>>      const x = v === 'foo' ? 1 : v === 'bar' ? 3 : v === 'baz' ? 6 : 99;
> >>>>
> >>>> This is maintainable, but is less than ideal:
> >>>>
> >>>>     let x;
> >>>>
> >>>>     switch (v) {
> >>>>     case "foo":
> >>>>       x = 1;
> >>>>       break;
> >>>>     case "bar":
> >>>>       x = 3;
> >>>>       break;
> >>>>     case "baz":
> >>>>       x = 6;
> >>>>       break;
> >>>>     default:
> >>>>       x = 99;
> >>>>       break;
> >>>>     }
> >>>>
> >>>> Pattern matching does shorten the code, but you have a weird default 
> >>>> case and also still end up with a loose variable and since pattern 
> >>>> matching is a statement you still have a initially undefined variable.
> >>>>
> >>>>     let x;
> >>>>
> >>>>     case (v) {
> >>>>       when "foo" -> x = 1;
> >>>>       when "bar" -> x = 3;
> >>>>       when "baz" -> x = 6;
> >>>>       when v -> x = 99;
> >>>>     }
> >>>>
> >>>> Let's try do expressions, I'll leave people's thoughts to themselves.
> >>>>
> >>>>     const x = do {
> >>>>       if (v === "foo") { 1; }
> >>>>       else if (v === "bar") { 3; }
> >>>>       else if (v === "baz") { 6; }
> >>>>       else { 99; }
> >>>>     }
> >>>>
> >>>> Or as another do expression variant:
> >>>>
> >>>>     const x = do {
> >>>>       switch (v) {
> >>>>         case "foo": 1; break;
> >>>>         case "bar": 3; break;
> >>>>         case "baz": 6; break;
> >>>>         default: 99; break;
> >>>>       }
> >>>>     }
> >>>>
> >>>> And as I'm thinking about switch expressions:
> >>>>
> >>>>     const x = switch (v) {
> >>>>       case "foo" => 1;
> >>>>       case "bar" => 3;
> >>>>       case "baz" => 6;
> >>>>       default => 99;
> >>>>     }
> >>>>
> >>>> What I really like is that it preserves all of the normal JavaScript 
> >>>> syntax with the small change that a switch is allowed in an expression 
> >>>> provided that all of the cases evaluate to expressions hence the use of 
> >>>> the '=>' as an indicator.  Fundamentally this is a very basic concept 
> >>>> where you have a state machine and need it switch based on the current 
> >>>> state and evaluate to the new state.
> >>>>
> >>>>     const nextState = switch (currentState) {
> >>>>        case ... =>
> >>>>     }
> >>>>
> >>>>
> >>>>
> >>>> On 2/25/19 4:00 PM, Jordan Harband wrote:
> >>>>
> >>>> Pattern Matching is still at stage 1; so there's not really any 
> >>>> permanent decisions that have been made - the repo theoretically should 
> >>>> contain rationales for decisions up to this point.
> >>>>
> >>>> I can speak for myself (as "not a champion" of that proposal, just a 
> >>>> fan) that any similarity to the reviled and terrible `switch` is 
> >>>> something I'll be pushing back against - I want a replacement that lacks 
> >>>> the footguns and pitfalls of `switch`, and that is easily teachable and 
> >>>> googleable as a different, distinct thing.
> >>>>
> >>>> On Mon, Feb 25, 2019 at 12:42 PM David Koblas <[email protected]> wrote:
> >>>>
> >>>> Jordan,
> >>>>
> >>>> One question that I have lingering from pattern matching is why is the 
> >>>> syntax so different?  IMHO it is still a switch statement with a 
> >>>> variation of the match on the case rather than a whole new construct.
> >>>>
> >>>> Is there somewhere I can find a bit of discussion about the history of 
> >>>> the syntax decisions?
> >>>>
> >>>> --David
> >>>>
> >>>>
> >>>> On Feb 25, 2019, at 12:33 PM, Jordan Harband <[email protected]> wrote:
> >>>>
> >>>> Additionally, https://github.com/tc39/proposal-pattern-matching - switch 
> >>>> statements are something I hope we'll soon be able to relegate to the 
> >>>> dustbin of history.
> >>>>
> >>>> On Mon, Feb 25, 2019 at 6:01 AM David Koblas <[email protected]> wrote:
> >>>>
> >>>> I quite aware that it’s covered in do expressions. Personally I find do 
> >>>> expressions non-JavaScript in style and it’s also not necessarily going 
> >>>> to make it into the language.
> >>>>
> >>>> Hence why I wanted to put out there the idea of switch expressions.
> >>>>
> >>>> --David
> >>>>
> >>>>
> >>>> On Feb 25, 2019, at 5:28 AM, N. Oxer <[email protected]> wrote:
> >>>>
> >>>> Hi,
> >>>>
> >>>> This would be covered by do expressions. You could just do:
> >>>>
> >>>> ```js
> >>>> const category = do {
> >>>>    switch (...) {
> >>>>      ...
> >>>>    };
> >>>> };
> >>>> ```
> >>>>
> >>>> On Sun, Feb 24, 2019 at 10:42 AM David Koblas <[email protected]> wrote:
> >>>>
> >>>> After looking at a bunch of code in our system noted that there are many
> >>>> cases where our code base has a pattern similar to this:
> >>>>
> >>>>       let category = data.category;
> >>>>
> >>>>       if (category === undefined) {
> >>>>         // Even if Tax is not enabled, we have defaults for incomeCode
> >>>>         switch (session.merchant.settings.tax.incomeCode) {
> >>>>           case TaxIncomeCode.RENTS_14:
> >>>>             category = PaymentCategory.RENT;
> >>>>             break;
> >>>>           case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17:
> >>>>             category = PaymentCategory.SERVICES;
> >>>>             break;
> >>>>           case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17:
> >>>>             category = PaymentCategory.SERVICES;
> >>>>             break;
> >>>>         }
> >>>>       }
> >>>>
> >>>> I also bumped into a block of go code that also implemented similar
> >>>> patterns, which really demonstrated to me that there while you could go
> >>>> crazy with triary nesting there should be a better way.  Looked at the
> >>>> pattern matching proposal and while could possibly help looked like it
> >>>> was overkill for the typical use case that I'm seeing. The most relevant
> >>>> example I noted was switch expressions from Java.  When applied to this
> >>>> problem really create a simple result:
> >>>>
> >>>>       const category = data.category || switch (setting.incomeCode) {
> >>>>         case TaxIncomeCode.RENTS_14 => PaymentCategory.RENT;
> >>>>         case TaxIncomeCode.ROYALTIES_COPYRIGHTS_12 =>
> >>>> PaymentCategory.ROYALTIES;
> >>>>         case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17 =>
> >>>> PaymentCategory.SERVICES;
> >>>>         default => PaymentCategory.OTHER;
> >>>>       }
> >>>>
> >>>> Note; the instead of using the '->' as Java, continue to use => and with
> >>>> the understanding that the right hand side is fundamentally function.
> >>>> So similar things to this are natural, note this proposal should remove
> >>>> "fall through" breaks and allow for multiple cases as such.
> >>>>
> >>>>       const quarter = switch (foo) {
> >>>>         case "Jan", "Feb", "Mar" => "Q1";
> >>>>         case "Apr", "May", "Jun" => "Q2";
> >>>>         case "Jul", "Aug", "Sep" => "Q3";
> >>>>         case "Oct", "Nov", "Dec" => { return "Q4" };
> >>>>         default => { throw new Error("Invalid Month") };
> >>>>       }
> >>>>
> >>>> Also compared this to the do expression proposal, it also provides a
> >>>> substantial simplification, but in a way that is more consistent with
> >>>> the existing language.  In one of their examples they provide an example
> >>>> of the Redux reducer
> >>>> https://redux.js.org/basics/reducers#splitting-reducers -- this would be
> >>>> a switch expression implementation.
> >>>>
> >>>>       function todoApp(state = initialState, action) => switch
> >>>> (action.type) {
> >>>>         case SET_VISIBILITY_FILTER => { ...state, visibilityFilter:
> >>>> action.filter };
> >>>>         case ADD_TODO => {
> >>>>             ...state, todos: [
> >>>>               ...state.todos,
> >>>>               {
> >>>>                 text: action.text,
> >>>>                 completed: false
> >>>>               }
> >>>>             ]
> >>>>           };
> >>>>         case TOGGLE_TODO => {
> >>>>             ...state,
> >>>>             todos: state.todos.map((todo, index) => (index ===
> >>>> action.index) ? { ...todo, completed: !todo.completed } : todo)
> >>>>           };
> >>>>         default => state;
> >>>>       }
> >>>>
> >>>>
> >>>>
> >>>> _______________________________________________
> >>>> 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
> >>>>
> >>>> On 2/25/19 3:42 PM, David Koblas wrote:
> >>>>
> >>>> Jordan,
> >>>>
> >>>> One question that I have lingering from pattern matching is why is the 
> >>>> syntax so different?  IMHO it is still a switch statement with a 
> >>>> variation of the match on the case rather than a whole new construct.
> >>>>
> >>>> Is there somewhere I can find a bit of discussion about the history of 
> >>>> the syntax decisions?
> >>>>
> >>>> --David
> >>>>
> >>>>
> >>>> On Feb 25, 2019, at 12:33 PM, Jordan Harband <[email protected]> wrote:
> >>>>
> >>>> Additionally, https://github.com/tc39/proposal-pattern-matching - switch 
> >>>> statements are something I hope we'll soon be able to relegate to the 
> >>>> dustbin of history.
> >>>>
> >>>> On Mon, Feb 25, 2019 at 6:01 AM David Koblas <[email protected]> wrote:
> >>>>
> >>>> I quite aware that it’s covered in do expressions. Personally I find do 
> >>>> expressions non-JavaScript in style and it’s also not necessarily going 
> >>>> to make it into the language.
> >>>>
> >>>> Hence why I wanted to put out there the idea of switch expressions.
> >>>>
> >>>> --David
> >>>>
> >>>>
> >>>> On Feb 25, 2019, at 5:28 AM, N. Oxer <[email protected]> wrote:
> >>>>
> >>>> Hi,
> >>>>
> >>>> This would be covered by do expressions. You could just do:
> >>>>
> >>>> ```js
> >>>> const category = do {
> >>>>    switch (...) {
> >>>>      ...
> >>>>    };
> >>>> };
> >>>> ```
> >>>>
> >>>> On Sun, Feb 24, 2019 at 10:42 AM David Koblas <[email protected]> wrote:
> >>>>
> >>>> After looking at a bunch of code in our system noted that there are many
> >>>> cases where our code base has a pattern similar to this:
> >>>>
> >>>>       let category = data.category;
> >>>>
> >>>>       if (category === undefined) {
> >>>>         // Even if Tax is not enabled, we have defaults for incomeCode
> >>>>         switch (session.merchant.settings.tax.incomeCode) {
> >>>>           case TaxIncomeCode.RENTS_14:
> >>>>             category = PaymentCategory.RENT;
> >>>>             break;
> >>>>           case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17:
> >>>>             category = PaymentCategory.SERVICES;
> >>>>             break;
> >>>>           case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17:
> >>>>             category = PaymentCategory.SERVICES;
> >>>>             break;
> >>>>         }
> >>>>       }
> >>>>
> >>>> I also bumped into a block of go code that also implemented similar
> >>>> patterns, which really demonstrated to me that there while you could go
> >>>> crazy with triary nesting there should be a better way.  Looked at the
> >>>> pattern matching proposal and while could possibly help looked like it
> >>>> was overkill for the typical use case that I'm seeing. The most relevant
> >>>> example I noted was switch expressions from Java.  When applied to this
> >>>> problem really create a simple result:
> >>>>
> >>>>       const category = data.category || switch (setting.incomeCode) {
> >>>>         case TaxIncomeCode.RENTS_14 => PaymentCategory.RENT;
> >>>>         case TaxIncomeCode.ROYALTIES_COPYRIGHTS_12 =>
> >>>> PaymentCategory.ROYALTIES;
> >>>>         case TaxIncomeCode.INDEPENDENT_PERSONAL_SERVICE_17 =>
> >>>> PaymentCategory.SERVICES;
> >>>>         default => PaymentCategory.OTHER;
> >>>>       }
> >>>>
> >>>> Note; the instead of using the '->' as Java, continue to use => and with
> >>>> the understanding that the right hand side is fundamentally function.
> >>>> So similar things to this are natural, note this proposal should remove
> >>>> "fall through" breaks and allow for multiple cases as such.
> >>>>
> >>>>       const quarter = switch (foo) {
> >>>>         case "Jan", "Feb", "Mar" => "Q1";
> >>>>         case "Apr", "May", "Jun" => "Q2";
> >>>>         case "Jul", "Aug", "Sep" => "Q3";
> >>>>         case "Oct", "Nov", "Dec" => { return "Q4" };
> >>>>         default => { throw new Error("Invalid Month") };
> >>>>       }
> >>>>
> >>>> Also compared this to the do expression proposal, it also provides a
> >>>> substantial simplification, but in a way that is more consistent with
> >>>> the existing language.  In one of their examples they provide an example
> >>>> of the Redux reducer
> >>>> https://redux.js.org/basics/reducers#splitting-reducers -- this would be
> >>>> a switch expression implementation.
> >>>>
> >>>>       function todoApp(state = initialState, action) => switch
> >>>> (action.type) {
> >>>>         case SET_VISIBILITY_FILTER => { ...state, visibilityFilter:
> >>>> action.filter };
> >>>>         case ADD_TODO => {
> >>>>             ...state, todos: [
> >>>>               ...state.todos,
> >>>>               {
> >>>>                 text: action.text,
> >>>>                 completed: false
> >>>>               }
> >>>>             ]
> >>>>           };
> >>>>         case TOGGLE_TODO => {
> >>>>             ...state,
> >>>>             todos: state.todos.map((todo, index) => (index ===
> >>>> action.index) ? { ...todo, completed: !todo.completed } : todo)
> >>>>           };
> >>>>         default => state;
> >>>>       }
> >>>>
> >>>>
> >>>>
> >>>> _______________________________________________
> >>>> 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
> >>>>
> >>>> _______________________________________________
> >>>> 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
> >> _______________________________________________
> >> 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