Issue #7444 has been reported by marcandre (Marc-Andre Lafortune). ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-11-27 06:45
on 2012-11-27 14:06
Issue #7444 has been updated by trans (Thomas Sawyer). I'd prefer `Array.product`, all things being the same. But you have given me a neat idea. In Ruby Facets there is a method Enumerable#every. It works like so: [1,2,3].every + 2 #=> [3,4,5] [1,2,3].every * 2 #=> [2,4,6] #every is a HOM (a higher-order method). You made me realize another good form of this would be one that applies to each new result. I am not sure what a good name for it would be, but for the moment lets just call it #apply. Then in your case of #product. deck.apply.product #=> [[1, :spades], [2, :spades], ...] Only problem is I haven't had any success it getting the Ruby gods to come around on HOMs :( ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34038 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-12-02 22:30
Issue #7444 has been updated by boris_stitnicky (Boris Stitnicky). IF this feature will not be considered feature creep by others, with respect to eg. Array#repeated_combination etc. (I do not possess 100% knowledge of Array / Enumerable / Enumerator features), THEN +1 to your variant syntax Array.product( ... ) As for HOMs, they are beautiful, but their place is in the private libraries of connoisseurs. Beginners have hard enough time understanding Enumerator already. ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34329 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-12-02 23:33
Issue #7444 has been updated by trans (Thomas Sawyer). > As for HOMs, they are beautiful, but their place is in the private libraries > of connoisseurs. Man, I couldn't disagree with that more. It delegation man, delegation! ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34331 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-12-03 10:27
Issue #7444 has been updated by alexeymuranov (Alexey Muranov). @marcandre, here are just some things that first came to my mind: 1. I do not think that an "Array instance method" is a good place for this function: otherwise every time a new function of multiple arguments is wanted, a new instance method would be added to `Array` (like the product of an array of numbers that you mentioned). It seems that what is needed here is some advanced multiple dispatch. `Enumerable::product(*enums)` would also look reasonable to me. 2. The name `product_set` seems to suggest that the result is a `Set`, but it is an `Enumerator`. 3. `[(1..13).to_a, %w(spades hearts diamond clubs)].inject(:product)` does a very similar thing to what the proposed method would do. ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34354 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-12-03 16:43
Issue #7444 has been updated by marcandre (Marc-Andre Lafortune). alexeymuranov (Alexey Muranov) wrote: > @marcandre, here are just some things that first came to my mind: > > 1. I do not think that an "Array instance method" is a good place for this function: otherwise every time a new function of multiple arguments is wanted, a new instance method would be added to `Array` (like the product of an array of numbers that you mentioned). It seems that what is needed here is some advanced multiple dispatch. `Enumerator::product(*enums)` would also look reasonable to me. I'm not suggesting that functions of multiple (generic) arguments be instance methods of Array. I'm proposing that this function of multiple *array* arguments (or array-like) be an instance of Array, like Array#transpose is. > 2. The name `product_set` seems to suggest that the result is a `Set`, but it is an `Enumerator`. A google search on "product set" confirms its meaning. > 3. `[(1..13).to_a, %w(spades hearts diamond clubs)].inject(:product)` does a very similar thing to what the proposed method would do. Not really. `arrays.product_set.to_a` and `arrays.inject(:product)` give only the same result if `arrays.size == 2`. If < or > 2, results are different. Finally, the inject isn't lazy. ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34364 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-12-03 17:26
Issue #7444 has been updated by stomar (Marcus Stollsteimer). >> 3. `[(1..13).to_a, %w(spades hearts diamond clubs)].inject(:product)` does a very similar thing to what the proposed method would do. > Not really. `arrays.product_set.to_a` and `arrays.inject(:product)` give only the same result if `arrays.size == 2`. If < or > 2, results are different. Please elaborate. ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34372 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-12-03 18:25
Issue #7444 has been updated by marcandre (Marc-Andre Lafortune). stomar (Marcus Stollsteimer) wrote: > > Not really. `arrays.product_set.to_a` and `arrays.inject(:product)` give only the same result if `arrays.size == 2`. If < or > 2, results are different. > > Please elaborate. I'm not sure how I was not clear, but in concrete examples: [].inject(:product) # => nil [].product_set.to_a # => [[]] [[1,2]].inject(:product) # => [1,2] [[1,2]].product_set.to_a # => [[1], [2]] [[1,2], [3,4], [5,6]].inject(:product) # => [[[1, 3], 5], [[1, 3], 6], [[1, 4], 5], [[1, 4], 6], [[2, 3], 5], [[2, 3], 6], [[2, 4], 5], [[2, 4], 6]] [[1,2], [3,4], [5,6]].product_set.to_a # => [[1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]] # etc... As noted, I also have to call `to_a` on `product_set` to compare. ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34376 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-12-03 18:51
Issue #7444 has been updated by stomar (Marcus Stollsteimer). Thanks and sorry for being unclear. It seemed to me that you did not specify the expected behavior for the proposed method in the case of e.g. 3 arrays. ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34377 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-12-03 19:14
Issue #7444 has been updated by alexeymuranov (Alexey Muranov). marcandre (Marc-Andre Lafortune) wrote: > alexeymuranov (Alexey Muranov) wrote: > > 1. I do not think that an "Array instance method" is a good place for this function: otherwise every time a new function of multiple arguments is wanted, a new instance method would be added to `Array` (like the product of an array of numbers that you mentioned). It seems that what is needed here is some advanced multiple dispatch. `Enumerator::product(*enums)` would also look reasonable to me. > > I'm not suggesting that functions of multiple (generic) arguments be instance methods of Array. I'm proposing that this function of multiple *array* arguments (or array-like) be an instance of Array, like Array#transpose is. In your example the first element was not an Array, but a Range. The method is called on the *outer* array, and constructs a certain product of its elements. I would see no reason to forbid such "collecting" operations for other element types (Set, Integer, etc.). `transpose` is special because it treats the array as a matrix. > > 2. The name `product_set` seems to suggest that the result is a `Set`, but it is an `Enumerator`. > > A google search on "product set" confirms its meaning. Exactly, and this is not what the method returns (enumerator) :). > > 3. `[(1..13).to_a, %w(spades hearts diamond clubs)].inject(:product)` does a very similar thing to what the proposed method would do. > > Not really. `arrays.product_set.to_a` and `arrays.inject(:product)` give only the same result if `arrays.size == 2`. If < or > 2, results are different. Finally, the inject isn't lazy. Yes, but i wanted to point out that this operation would look more natural to me if defined in terms of a binary operation on arrays or enumerators: `[(1..13), %w(spades hearts diamond clubs)].inject(:smart_product)` where `smart_product` is to be defined lazy, and with other nice properties. ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34379 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
on 2012-12-04 20:12
Issue #7444 has been updated by alexeymuranov (Alexey Muranov). Ok, is think i understand why it can be defined as an instance methods of `Array`: it it is called on an array, and produces an enumerator which returns a sequence of arrays of the same length. Then maybe `Array#each_combination`? ---------------------------------------- Feature #7444: Array#product_set https://bugs.ruby-lang.org/issues/7444#change-34399 Author: marcandre (Marc-Andre Lafortune) Status: Open Priority: Normal Assignee: matz (Yukihiro Matsumoto) Category: core Target version: next minor I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product) deck = [1..13, %i(spades hearts diamond clubs)].product_set # => <#Enumerator ...> deck.first(2) # => [[1, :spades], [2, :spades]] `product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do. Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method. The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`. Addressing objections raised in #6499: 1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of. It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on. Writing `arrays.product_set` is much nicer. 2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-) 3) [].product_set.to_a # => [[]] This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.