diff --git a/config.json b/config.json index eb88c4a..1110977 100644 --- a/config.json +++ b/config.json @@ -914,6 +914,14 @@ "prerequisites": [], "difficulty": 7 }, + { + "slug": "poker", + "name": "Poker", + "uuid": "662bce2e-94bb-4b1e-94a0-d69be06ab7e8", + "practices": [], + "prerequisites": [], + "difficulty": 7 + }, { "slug": "rectangles", "name": "Rectangles", diff --git a/exercises/practice/poker/.busted b/exercises/practice/poker/.busted new file mode 100644 index 0000000..86b84e7 --- /dev/null +++ b/exercises/practice/poker/.busted @@ -0,0 +1,5 @@ +return { + default = { + ROOT = { '.' } + } +} diff --git a/exercises/practice/poker/.docs/instructions.md b/exercises/practice/poker/.docs/instructions.md new file mode 100644 index 0000000..107cd49 --- /dev/null +++ b/exercises/practice/poker/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +Pick the best hand(s) from a list of poker hands. + +See [Wikipedia][poker-hands] for an overview of poker hands. + +[poker-hands]: https://en.wikipedia.org/wiki/List_of_poker_hands diff --git a/exercises/practice/poker/.meta/config.json b/exercises/practice/poker/.meta/config.json new file mode 100644 index 0000000..6a4e57d --- /dev/null +++ b/exercises/practice/poker/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glennj" + ], + "files": { + "solution": [ + "poker.moon" + ], + "test": [ + "poker_spec.moon" + ], + "example": [ + ".meta/example.moon" + ] + }, + "blurb": "Pick the best hand(s) from a list of poker hands.", + "source": "Inspired by the training course from Udacity.", + "source_url": "https://www.udacity.com/course/design-of-computer-programs--cs212" +} diff --git a/exercises/practice/poker/.meta/example.moon b/exercises/practice/poker/.meta/example.moon new file mode 100644 index 0000000..adb7558 --- /dev/null +++ b/exercises/practice/poker/.meta/example.moon @@ -0,0 +1,110 @@ +List = require 'pl.List' +import fold from require 'moon' + +class Card + new: (cardString) => + @cardString = cardString + @suit = cardString\sub -1 + @rank = switch cardString\sub 0, -2 + when 'A' then 14 + when 'K' then 13 + when 'Q' then 12 + when 'J' then 11 + else tonumber(cardString\sub 0, -2) + + __lt: (other) => @rank < other.rank + __eq: (other) => @rank == other.rank + __gt: (other) => @rank > other.rank + +-- ------------------------------------------------------------------ +class PokerHand + new: (handString) => + @handString = handString + @cards = List [Card cardString for cardString in handString\gmatch '%S+'] + @category, @value = @initialize! + + initialize: => + @cards\sort (a, b) -> a.rank > b.rank -- sort descending by rank + + ranks = [card.rank for card in *@cards] + -- handle the ranks as the digits of a base-14 number, so we can easily compare hands of the same category + ranking = (...) -> fold({0, ...}, (acc, rank) -> acc * 14 + rank) + + -- ignore five of a kind + + is_straight, straight_val = @isStraight! + is_flush = @isFlush! + + if is_straight and is_flush + return 2, ranking straight_val + + -- four of a kind + if ranks[1] == ranks[4] + return 3, ranking(ranks[1], ranks[5]) + elseif ranks[2] == ranks[5] + return 3, ranking(ranks[2], ranks[1]) + + -- full house + if ranks[1] == ranks[3] and ranks[4] == ranks[5] + return 4, ranking(ranks[1], ranks[4]) + elseif ranks[1] == ranks[2] and ranks[3] == ranks[5] + return 4, ranking(ranks[3], ranks[1]) + + if is_flush + return 5, ranking(table.unpack ranks) + if is_straight + return 6, ranking straight_val + + -- three of a kind + if ranks[1] == ranks[3] + return 7, ranking(ranks[1], ranks[4], ranks[5]) + elseif ranks[2] == ranks[4] + return 7, ranking(ranks[2], ranks[1], ranks[5]) + elseif ranks[3] == ranks[5] + return 7, ranking(ranks[3], ranks[1], ranks[2]) + + -- two pair + if ranks[1] == ranks[2] and ranks[3] == ranks[4] + return 8, ranking(ranks[1], ranks[3], ranks[5]) + elseif ranks[1] == ranks[2] and ranks[4] == ranks[5] + return 8, ranking(ranks[1], ranks[4], ranks[3]) + elseif ranks[2] == ranks[3] and ranks[4] == ranks[5] + return 8, ranking(ranks[2], ranks[4], ranks[1]) + + -- one pair + for i = 1, 4 + if ranks[i] == ranks[i+1] + return 9, ranking(ranks[i], table.unpack [ranks[j] for j = 1, 5 when j < i or j > i+1]) + + -- high card + return 10, ranking(table.unpack ranks) + + + isFlush: => + suits = [card.suit for card in *@cards when card.suit == @cards[1].suit] + #suits == #@cards + + isStraight: => + ranks = List [card.rank for card in *@cards] + return true, 5 if ranks == {14, 5, 4, 3, 2} + for i = 2, 5 + return false, 0 if ranks[i] != ranks[i-1] - 1 + true, ranks[1] + + isRoyalFlush: => + @isStraight() and @isFlush() and @cards[1].rank == 14 + + __lt: (other) => + -- lower category wins; if same category, higher value wins + @category < other.category or (@category == other.category and @value > other.value) + + __eq: (other) => + @category == other.category and @value == other.value + +-- ------------------------------------------------------------------ +{ + bestHands: (handsStrings) -> + hands = List [PokerHand hand for hand in *handsStrings] + hands\sort! + [hand.handString for hand in *hands when hand == hands[1]] +} diff --git a/exercises/practice/poker/.meta/spec_generator.moon b/exercises/practice/poker/.meta/spec_generator.moon new file mode 100644 index 0000000..8bd70df --- /dev/null +++ b/exercises/practice/poker/.meta/spec_generator.moon @@ -0,0 +1,17 @@ +import indent, string_list from require 'spec_helpers' +assertions = require 'spec_helpers/assertions' + +{ + module_name: 'Poker', + + test_helpers: assertions.same_elements + + generate_test: (case, level) -> + lines = { + "hands = #{string_list case.input.hands, level, inline: 1}", + "expected = #{string_list case.expected, level, inline: 1}", + } + assertion = if #case.expected == 1 then 'assert.are.same' else 'assert.has.same_elements' + table.insert lines, "#{assertion} expected, Poker.#{case.property} hands" + table.concat [indent line, level for line in *lines], '\n' +} diff --git a/exercises/practice/poker/.meta/tests.toml b/exercises/practice/poker/.meta/tests.toml new file mode 100644 index 0000000..2e654ef --- /dev/null +++ b/exercises/practice/poker/.meta/tests.toml @@ -0,0 +1,131 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[161f485e-39c2-4012-84cf-bec0c755b66c] +description = "single hand always wins" + +[370ac23a-a00f-48a9-9965-6f3fb595cf45] +description = "highest card out of all hands wins" + +[d94ad5a7-17df-484b-9932-c64fc26cff52] +description = "a tie has multiple winners" + +[61ed83a9-cfaa-40a5-942a-51f52f0a8725] +description = "multiple hands with the same high cards, tie compares next highest ranked, down to last card" + +[da01becd-f5b0-4342-b7f3-1318191d0580] +description = "winning high card hand also has the lowest card" + +[f7175a89-34ff-44de-b3d7-f6fd97d1fca4] +description = "one pair beats high card" + +[e114fd41-a301-4111-a9e7-5a7f72a76561] +description = "highest pair wins" + +[b3acd3a7-f9fa-4647-85ab-e0a9e07d1365] +description = "both hands have the same pair, high card wins" + +[935bb4dc-a622-4400-97fa-86e7d06b1f76] +description = "two pairs beats one pair" + +[c8aeafe1-6e3d-4711-a6de-5161deca91fd] +description = "both hands have two pairs, highest ranked pair wins" + +[88abe1ba-7ad7-40f3-847e-0a26f8e46a60] +description = "both hands have two pairs, with the same highest ranked pair, tie goes to low pair" + +[15a7a315-0577-47a3-9981-d6cf8e6f387b] +description = "both hands have two identically ranked pairs, tie goes to remaining card (kicker)" + +[f761e21b-2560-4774-a02a-b3e9366a51ce] +description = "both hands have two pairs that add to the same value, win goes to highest pair" + +[fc6277ac-94ac-4078-8d39-9d441bc7a79e] +description = "two pairs first ranked by largest pair" + +[21e9f1e6-2d72-49a1-a930-228e5e0195dc] +description = "three of a kind beats two pair" + +[c2fffd1f-c287-480f-bf2d-9628e63bbcc3] +description = "both hands have three of a kind, tie goes to highest ranked triplet" + +[eb856cc2-481c-4b0d-9835-4d75d07a5d9d] +description = "with multiple decks, two players can have same three of a kind, ties go to highest remaining cards" +include = false + +[26a4a7d4-34a2-4f18-90b4-4a8dd35d2bb1] +description = "with multiple decks, two players can have same three of a kind, ties go to highest remaining cards" +reimplements = "eb856cc2-481c-4b0d-9835-4d75d07a5d9d" + +[a858c5d9-2f28-48e7-9980-b7fa04060a60] +description = "a straight beats three of a kind" + +[73c9c756-e63e-4b01-a88d-0d4491a7a0e3] +description = "aces can end a straight (10 J Q K A)" + +[76856b0d-35cd-49ce-a492-fe5db53abc02] +description = "aces can start a straight (A 2 3 4 5)" + +[e214b7df-dcba-45d3-a2e5-342d8c46c286] +description = "aces cannot be in the middle of a straight (Q K A 2 3)" + +[6980c612-bbff-4914-b17a-b044e4e69ea1] +description = "both hands with a straight, tie goes to highest ranked card" + +[5135675c-c2fc-4e21-9ba3-af77a32e9ba4] +description = "even though an ace is usually high, a 5-high straight is the lowest-scoring straight" + +[c601b5e6-e1df-4ade-b444-b60ce13b2571] +description = "flush beats a straight" + +[4d90261d-251c-49bd-a468-896bf10133de] +description = "both hands have a flush, tie goes to high card, down to the last one if necessary" +include = false + +[e04137c5-c19a-4dfc-97a1-9dfe9baaa2ff] +description = "both hands have a flush, tie goes to high card, down to the last one if necessary" +reimplements = "4d90261d-251c-49bd-a468-896bf10133de" + +[3a19361d-8974-455c-82e5-f7152f5dba7c] +description = "full house beats a flush" + +[eb73d0e6-b66c-4f0f-b8ba-bf96bc0a67f0] +description = "both hands have a full house, tie goes to highest-ranked triplet" + +[34b51168-1e43-4c0d-9b32-e356159b4d5d] +description = "with multiple decks, both hands have a full house with the same triplet, tie goes to the pair" + +[d61e9e99-883b-4f99-b021-18f0ae50c5f4] +description = "four of a kind beats a full house" + +[2e1c8c63-e0cb-4214-a01b-91954490d2fe] +description = "both hands have four of a kind, tie goes to high quad" + +[892ca75d-5474-495d-9f64-a6ce2dcdb7e1] +description = "with multiple decks, both hands with identical four of a kind, tie determined by kicker" + +[923bd910-dc7b-4f7d-a330-8b42ec10a3ac] +description = "straight flush beats four of a kind" + +[d9629e22-c943-460b-a951-2134d1b43346] +description = "aces can end a straight flush (10 J Q K A)" + +[05d5ede9-64a5-4678-b8ae-cf4c595dc824] +description = "aces can start a straight flush (A 2 3 4 5)" + +[ad655466-6d04-49e8-a50c-0043c3ac18ff] +description = "aces cannot be in the middle of a straight flush (Q K A 2 3)" + +[d0927f70-5aec-43db-aed8-1cbd1b6ee9ad] +description = "both hands have a straight flush, tie goes to highest-ranked card" + +[be620e09-0397-497b-ac37-d1d7a4464cfc] +description = "even though an ace is usually high, a 5-high straight flush is the lowest-scoring straight flush" diff --git a/exercises/practice/poker/poker.moon b/exercises/practice/poker/poker.moon new file mode 100644 index 0000000..255376a --- /dev/null +++ b/exercises/practice/poker/poker.moon @@ -0,0 +1,4 @@ +{ + bestHands: (handsStrings) -> + error 'Implement me!' +} diff --git a/exercises/practice/poker/poker_spec.moon b/exercises/practice/poker/poker_spec.moon new file mode 100644 index 0000000..5b4ac78 --- /dev/null +++ b/exercises/practice/poker/poker_spec.moon @@ -0,0 +1,321 @@ +Poker = require 'poker' + +describe 'poker:', -> + -- ---------------------------------------------------------- + -- assert that two lists have the same elements, regardless of order + same_elements = (state, arguments) -> + { list1, list2 } = arguments + return false if #list1 != #list2 + for elem in *list1 + found = false + for elem2 in *list2 + if elem == elem2 + found = true + break + return false if not found + true + + say = require 'say' + say\set 'assertion.same_elements.positive', 'Expected %s to be in the range [%s, %s]' + say\set 'assertion.same_elements.negative', 'Expected %s not to be in the range [%s, %s]' + assert\register 'assertion', 'same_elements', same_elements, 'assertion.same_elements.positive', 'assertion.same_elements.negative' + -- ---------------------------------------------------------- + + it 'single hand always wins', -> + hands = {'4S 5S 7H 8D JC'} + expected = {'4S 5S 7H 8D JC'} + assert.are.same expected, Poker.bestHands hands + + pending 'highest card out of all hands wins', -> + hands = { + '4D 5S 6S 8D 3C', + '2S 4C 7S 9H 10H', + '3S 4S 5D 6H JH', + } + expected = {'3S 4S 5D 6H JH'} + assert.are.same expected, Poker.bestHands hands + + pending 'a tie has multiple winners', -> + hands = { + '4D 5S 6S 8D 3C', + '2S 4C 7S 9H 10H', + '3S 4S 5D 6H JH', + '3H 4H 5C 6C JD', + } + expected = { + '3S 4S 5D 6H JH', + '3H 4H 5C 6C JD', + } + assert.has.same_elements expected, Poker.bestHands hands + + pending 'multiple hands with the same high cards, tie compares next highest ranked, down to last card', -> + hands = { + '3S 5H 6S 8D 7H', + '2S 5D 6D 8C 7S', + } + expected = {'3S 5H 6S 8D 7H'} + assert.are.same expected, Poker.bestHands hands + + pending 'winning high card hand also has the lowest card', -> + hands = { + '2S 5H 6S 8D 7H', + '3S 4D 6D 8C 7S', + } + expected = {'2S 5H 6S 8D 7H'} + assert.are.same expected, Poker.bestHands hands + + pending 'one pair beats high card', -> + hands = { + '4S 5H 6C 8D KH', + '2S 4H 6S 4D JH', + } + expected = {'2S 4H 6S 4D JH'} + assert.are.same expected, Poker.bestHands hands + + pending 'highest pair wins', -> + hands = { + '4S 2H 6S 2D JH', + '2S 4H 6C 4D JD', + } + expected = {'2S 4H 6C 4D JD'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have the same pair, high card wins', -> + hands = { + '4H 4S AH JC 3D', + '4C 4D AS 5D 6C', + } + expected = {'4H 4S AH JC 3D'} + assert.are.same expected, Poker.bestHands hands + + pending 'two pairs beats one pair', -> + hands = { + '2S 8H 6S 8D JH', + '4S 5H 4C 8C 5C', + } + expected = {'4S 5H 4C 8C 5C'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have two pairs, highest ranked pair wins', -> + hands = { + '2S 8H 2D 8D 3H', + '4S 5H 4C 8S 5D', + } + expected = {'2S 8H 2D 8D 3H'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have two pairs, with the same highest ranked pair, tie goes to low pair', -> + hands = { + '2S QS 2C QD JH', + 'JD QH JS 8D QC', + } + expected = {'JD QH JS 8D QC'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have two identically ranked pairs, tie goes to remaining card (kicker)', -> + hands = { + 'JD QH JS 8D QC', + 'JS QS JC 2D QD', + } + expected = {'JD QH JS 8D QC'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have two pairs that add to the same value, win goes to highest pair', -> + hands = { + '6S 6H 3S 3H AS', + '7H 7S 2H 2S AC', + } + expected = {'7H 7S 2H 2S AC'} + assert.are.same expected, Poker.bestHands hands + + pending 'two pairs first ranked by largest pair', -> + hands = { + '5C 2S 5S 4H 4C', + '6S 2S 6H 7C 2C', + } + expected = {'6S 2S 6H 7C 2C'} + assert.are.same expected, Poker.bestHands hands + + pending 'three of a kind beats two pair', -> + hands = { + '2S 8H 2H 8D JH', + '4S 5H 4C 8S 4H', + } + expected = {'4S 5H 4C 8S 4H'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have three of a kind, tie goes to highest ranked triplet', -> + hands = { + '2S 2H 2C 8D JH', + '4S AH AS 8C AD', + } + expected = {'4S AH AS 8C AD'} + assert.are.same expected, Poker.bestHands hands + + pending 'with multiple decks, two players can have same three of a kind, ties go to highest remaining cards', -> + hands = { + '5S AH AS 7C AD', + '4S AH AS 8C AD', + } + expected = {'4S AH AS 8C AD'} + assert.are.same expected, Poker.bestHands hands + + pending 'a straight beats three of a kind', -> + hands = { + '4S 5H 4C 8D 4H', + '3S 4D 2S 6D 5C', + } + expected = {'3S 4D 2S 6D 5C'} + assert.are.same expected, Poker.bestHands hands + + pending 'aces can end a straight (10 J Q K A)', -> + hands = { + '4S 5H 4C 8D 4H', + '10D JH QS KD AC', + } + expected = {'10D JH QS KD AC'} + assert.are.same expected, Poker.bestHands hands + + pending 'aces can start a straight (A 2 3 4 5)', -> + hands = { + '4S 5H 4C 8D 4H', + '4D AH 3S 2D 5C', + } + expected = {'4D AH 3S 2D 5C'} + assert.are.same expected, Poker.bestHands hands + + pending 'aces cannot be in the middle of a straight (Q K A 2 3)', -> + hands = { + '2C 3D 7H 5H 2S', + 'QS KH AC 2D 3S', + } + expected = {'2C 3D 7H 5H 2S'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands with a straight, tie goes to highest ranked card', -> + hands = { + '4S 6C 7S 8D 5H', + '5S 7H 8S 9D 6H', + } + expected = {'5S 7H 8S 9D 6H'} + assert.are.same expected, Poker.bestHands hands + + pending 'even though an ace is usually high, a 5-high straight is the lowest-scoring straight', -> + hands = { + '2H 3C 4D 5D 6H', + '4S AH 3S 2D 5H', + } + expected = {'2H 3C 4D 5D 6H'} + assert.are.same expected, Poker.bestHands hands + + pending 'flush beats a straight', -> + hands = { + '4C 6H 7D 8D 5H', + '2S 4S 5S 6S 7S', + } + expected = {'2S 4S 5S 6S 7S'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have a flush, tie goes to high card, down to the last one if necessary', -> + hands = { + '2H 7H 8H 9H 6H', + '3S 5S 6S 7S 8S', + } + expected = {'2H 7H 8H 9H 6H'} + assert.are.same expected, Poker.bestHands hands + + pending 'full house beats a flush', -> + hands = { + '3H 6H 7H 8H 5H', + '4S 5H 4C 5D 4H', + } + expected = {'4S 5H 4C 5D 4H'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have a full house, tie goes to highest-ranked triplet', -> + hands = { + '4H 4S 4D 9S 9D', + '5H 5S 5D 8S 8D', + } + expected = {'5H 5S 5D 8S 8D'} + assert.are.same expected, Poker.bestHands hands + + pending 'with multiple decks, both hands have a full house with the same triplet, tie goes to the pair', -> + hands = { + '5H 5S 5D 9S 9D', + '5H 5S 5D 8S 8D', + } + expected = {'5H 5S 5D 9S 9D'} + assert.are.same expected, Poker.bestHands hands + + pending 'four of a kind beats a full house', -> + hands = { + '4S 5H 4D 5D 4H', + '3S 3H 2S 3D 3C', + } + expected = {'3S 3H 2S 3D 3C'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have four of a kind, tie goes to high quad', -> + hands = { + '2S 2H 2C 8D 2D', + '4S 5H 5S 5D 5C', + } + expected = {'4S 5H 5S 5D 5C'} + assert.are.same expected, Poker.bestHands hands + + pending 'with multiple decks, both hands with identical four of a kind, tie determined by kicker', -> + hands = { + '3S 3H 2S 3D 3C', + '3S 3H 4S 3D 3C', + } + expected = {'3S 3H 4S 3D 3C'} + assert.are.same expected, Poker.bestHands hands + + pending 'straight flush beats four of a kind', -> + hands = { + '4S 5H 5S 5D 5C', + '7S 8S 9S 6S 10S', + } + expected = {'7S 8S 9S 6S 10S'} + assert.are.same expected, Poker.bestHands hands + + pending 'aces can end a straight flush (10 J Q K A)', -> + hands = { + 'KC AH AS AD AC', + '10C JC QC KC AC', + } + expected = {'10C JC QC KC AC'} + assert.are.same expected, Poker.bestHands hands + + pending 'aces can start a straight flush (A 2 3 4 5)', -> + hands = { + 'KS AH AS AD AC', + '4H AH 3H 2H 5H', + } + expected = {'4H AH 3H 2H 5H'} + assert.are.same expected, Poker.bestHands hands + + pending 'aces cannot be in the middle of a straight flush (Q K A 2 3)', -> + hands = { + '2C AC QC 10C KC', + 'QH KH AH 2H 3H', + } + expected = {'2C AC QC 10C KC'} + assert.are.same expected, Poker.bestHands hands + + pending 'both hands have a straight flush, tie goes to highest-ranked card', -> + hands = { + '4H 6H 7H 8H 5H', + '5S 7S 8S 9S 6S', + } + expected = {'5S 7S 8S 9S 6S'} + assert.are.same expected, Poker.bestHands hands + + pending 'even though an ace is usually high, a 5-high straight flush is the lowest-scoring straight flush', -> + hands = { + '2H 3H 4H 5H 6H', + '4D AD 3D 2D 5D', + } + expected = {'2H 3H 4H 5H 6H'} + assert.are.same expected, Poker.bestHands hands diff --git a/lib/spec_helpers/assertions.moon b/lib/spec_helpers/assertions.moon index c9222bf..3fa1902 100644 --- a/lib/spec_helpers/assertions.moon +++ b/lib/spec_helpers/assertions.moon @@ -23,6 +23,28 @@ assertions = { say\set 'assertion.between.negative', 'Expected %s not to be in the range [%s, %s]' assert\register 'assertion', 'between', between, 'assertion.between.positive', 'assertion.between.negative' -- ---------------------------------------------------------- +]], + + same_elements: [[ + -- ---------------------------------------------------------- + -- assert that two lists have the same elements, regardless of order + same_elements = (state, arguments) -> + { list1, list2 } = arguments + return false if #list1 != #list2 + for elem in *list1 + found = false + for elem2 in *list2 + if elem == elem2 + found = true + break + return false if not found + true + + say = require 'say' + say\set 'assertion.same_elements.positive', 'Expected %s to be in the range [%s, %s]' + say\set 'assertion.same_elements.negative', 'Expected %s not to be in the range [%s, %s]' + assert\register 'assertion', 'same_elements', same_elements, 'assertion.same_elements.positive', 'assertion.same_elements.negative' + -- ---------------------------------------------------------- ]] }