trackler 2.2.1.61 → 2.2.1.62

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/forth/canonical-data.json +1 -7
  4. data/problem-specifications/exercises/meetup/description.md +16 -12
  5. data/problem-specifications/exercises/sum-of-multiples/description.md +3 -3
  6. data/tracks/c/config.json +14 -1
  7. data/tracks/c/exercises/anagram/src/anagram.h +19 -4
  8. data/tracks/c/exercises/anagram/src/example.c +27 -40
  9. data/tracks/c/exercises/anagram/test/test_anagram.c +100 -152
  10. data/tracks/c/exercises/sublist/README.md +53 -0
  11. data/tracks/c/exercises/sublist/makefile +15 -0
  12. data/tracks/c/exercises/sublist/src/example.c +63 -0
  13. data/tracks/c/exercises/sublist/src/sublist.h +17 -0
  14. data/tracks/c/exercises/sublist/test/test_sublist.c +243 -0
  15. data/tracks/c/exercises/sublist/test/vendor/unity.c +1300 -0
  16. data/tracks/c/exercises/sublist/test/vendor/unity.h +274 -0
  17. data/tracks/c/exercises/sublist/test/vendor/unity_internals.h +701 -0
  18. data/tracks/ecmascript/config.json +56 -0
  19. data/tracks/ecmascript/exercises/rectangles/README.md +95 -0
  20. data/tracks/ecmascript/exercises/rectangles/example.js +38 -0
  21. data/tracks/ecmascript/exercises/rectangles/package.json +72 -0
  22. data/tracks/ecmascript/exercises/rectangles/rectangles.spec.js +147 -0
  23. data/tracks/ecmascript/exercises/rotational-cipher/README.md +66 -0
  24. data/tracks/ecmascript/exercises/rotational-cipher/example.js +16 -0
  25. data/tracks/ecmascript/exercises/rotational-cipher/package.json +72 -0
  26. data/tracks/ecmascript/exercises/rotational-cipher/rotational-cipher.spec.js +73 -0
  27. data/tracks/ecmascript/exercises/spiral-matrix/README.md +59 -0
  28. data/tracks/ecmascript/exercises/spiral-matrix/example.js +26 -0
  29. data/tracks/ecmascript/exercises/spiral-matrix/package.json +72 -0
  30. data/tracks/ecmascript/exercises/spiral-matrix/spiral-matrix.spec.js +55 -0
  31. data/tracks/ecmascript/exercises/transpose/README.md +94 -0
  32. data/tracks/ecmascript/exercises/transpose/example.js +12 -0
  33. data/tracks/ecmascript/exercises/transpose/package.json +71 -0
  34. data/tracks/ecmascript/exercises/transpose/transpose.spec.js +121 -0
  35. data/tracks/go/exercises/allergies/.meta/gen.go +88 -0
  36. data/tracks/go/exercises/allergies/allergies_test.go +19 -46
  37. data/tracks/go/exercises/allergies/cases_test.go +60 -0
  38. data/tracks/go/exercises/bob/bob.go +0 -2
  39. data/tracks/go/exercises/forth/cases_test.go +2 -7
  40. data/tracks/go/exercises/nucleotide-count/nucleotide_count.go +0 -2
  41. data/tracks/go/exercises/pangram/.meta/gen.go +54 -0
  42. data/tracks/go/exercises/pangram/cases_test.go +62 -0
  43. data/tracks/go/exercises/pangram/example.go +3 -5
  44. data/tracks/go/exercises/pangram/pangram_test.go +3 -24
  45. data/tracks/go/exercises/rna-transcription/rna_transcription.go +0 -2
  46. data/tracks/go/exercises/robot-name/bonus_example.go +0 -2
  47. data/tracks/java/exercises/acronym/.meta/src/reference/java/Acronym.java +3 -3
  48. data/tracks/lfe/config.json +4 -3
  49. data/tracks/perl6/docs/SNIPPET.txt +8 -3
  50. data/tracks/perl6/exercises/allergies/Allergies.pm6 +1 -1
  51. data/tracks/perl6/exercises/allergies/Example.pm6 +1 -1
  52. data/tracks/perl6/exercises/allergies/allergies.t +10 -2
  53. data/tracks/perl6/exercises/allergies/example.yaml +10 -2
  54. data/tracks/perl6/exercises/leap/Example.pm6 +1 -1
  55. data/tracks/perl6/exercises/leap/Leap.pm6 +1 -1
  56. data/tracks/perl6/exercises/leap/example.yaml +10 -2
  57. data/tracks/perl6/exercises/leap/leap.t +10 -2
  58. data/tracks/perl6/exercises/luhn/Example.pm6 +1 -1
  59. data/tracks/perl6/exercises/luhn/Luhn.pm6 +1 -1
  60. data/tracks/perl6/exercises/luhn/example.yaml +10 -2
  61. data/tracks/perl6/exercises/luhn/luhn.t +10 -2
  62. data/tracks/perl6/exercises/pangram/Example.pm6 +1 -1
  63. data/tracks/perl6/exercises/pangram/Pangram.pm6 +1 -1
  64. data/tracks/perl6/exercises/pangram/example.yaml +12 -6
  65. data/tracks/perl6/exercises/pangram/pangram.t +9 -3
  66. data/tracks/python/config.json +38 -0
  67. data/tracks/python/exercises/complex-numbers/complex_numbers_test.py +81 -66
  68. data/tracks/python/exercises/connect/README.md +44 -0
  69. data/tracks/python/exercises/connect/connect.py +7 -0
  70. data/tracks/python/exercises/connect/connect_test.py +118 -0
  71. data/tracks/python/exercises/connect/example.py +61 -0
  72. data/tracks/python/exercises/go-counting/README.md +44 -0
  73. data/tracks/python/exercises/go-counting/example.py +62 -0
  74. data/tracks/python/exercises/go-counting/go_counting.py +38 -0
  75. data/tracks/python/exercises/go-counting/go_counting_test.py +92 -0
  76. data/tracks/python/exercises/parallel-letter-frequency/README.md +24 -0
  77. data/tracks/python/exercises/parallel-letter-frequency/example.py +56 -0
  78. data/tracks/python/exercises/parallel-letter-frequency/parallel_letter_frequency.py +2 -0
  79. data/tracks/python/exercises/parallel-letter-frequency/parallel_letter_frequency_test.py +61 -0
  80. data/tracks/python/exercises/strain/README.md +3 -1
  81. data/tracks/python/exercises/strain/strain.py +2 -2
  82. data/tracks/rust/.travis.yml +1 -0
  83. data/tracks/rust/README.md +2 -0
  84. data/tracks/rust/_test/check-exercises.sh +41 -54
  85. data/tracks/rust/_test/ensure-readmes-are-updated.sh +40 -0
  86. data/tracks/rust/bin/test-exercise +84 -0
  87. data/tracks/rust/exercises/alphametics/.meta/test-in-release-mode +2 -0
  88. data/tracks/rust/exercises/alphametics/src/lib.rs +1 -1
  89. data/tracks/rust/exercises/dominoes/README.md +3 -3
  90. data/tracks/rust/exercises/isbn-verifier/README.md +3 -2
  91. data/tracks/rust/exercises/nucleotide-count/README.md +2 -2
  92. data/tracks/rust/exercises/perfect-numbers/src/lib.rs +10 -0
  93. data/tracks/rust/exercises/phone-number/README.md +1 -1
  94. data/tracks/rust/exercises/pythagorean-triplet/src/lib.rs +3 -0
  95. data/tracks/rust/exercises/rectangles/README.md +9 -9
  96. data/tracks/rust/exercises/two-bucket/README.md +7 -7
  97. data/tracks/typescript/config.json +16 -0
  98. data/tracks/typescript/exercises/diamond/README.md +84 -0
  99. data/tracks/typescript/exercises/diamond/diamond.example.ts +51 -0
  100. data/tracks/typescript/exercises/diamond/diamond.test.ts +35 -0
  101. data/tracks/typescript/exercises/diamond/diamond.ts +0 -0
  102. data/tracks/typescript/exercises/diamond/package.json +36 -0
  103. data/tracks/typescript/exercises/diamond/tsconfig.json +22 -0
  104. data/tracks/typescript/exercises/diamond/tslint.json +127 -0
  105. data/tracks/typescript/exercises/diamond/yarn.lock +2624 -0
  106. metadata +53 -2
@@ -0,0 +1,61 @@
1
+
2
+ class ConnectGame:
3
+
4
+ directions = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, -1), (-1, 1)]
5
+ white = "O"
6
+ black = "X"
7
+ none = ""
8
+
9
+ def __init__(self, lines):
10
+ self.board = self.make_board(lines)
11
+ assert len(self.board) > 0
12
+
13
+ self.width = len(self.board[0])
14
+ self.height = len(self.board)
15
+ assert self.width > 0 and self.height > 0
16
+
17
+ for l in self.board:
18
+ assert len(l) == self.width
19
+
20
+ def valid(self, x, y):
21
+ return x >= 0 and x < self.width and y >= 0 and y < self.height
22
+
23
+ def make_board(self, lines):
24
+ return ["".join(l.split()) for l in lines.splitlines()]
25
+
26
+ def player_reach_dest(self, player, x, y):
27
+ if player == self.black:
28
+ return x == self.width - 1
29
+ if player == self.white:
30
+ return y == self.height - 1
31
+
32
+ def walk_board(self, player, x, y, visited=[]):
33
+ if (x, y) in visited:
34
+ return False
35
+
36
+ if (not self.valid(x, y)) or self.board[y][x] != player:
37
+ return False
38
+
39
+ if self.player_reach_dest(player, x, y):
40
+ return True
41
+
42
+ for d in self.directions:
43
+ if self.walk_board(player, x + d[0], y + d[1], visited + [(x, y)]):
44
+ return True
45
+
46
+ def check_player_is_winner(self, player):
47
+ if player == self.black:
48
+ for y in range(self.height):
49
+ if self.walk_board(player, 0, y):
50
+ return True
51
+ if player == self.white:
52
+ for x in range(self.width):
53
+ if self.walk_board(player, x, 0):
54
+ return True
55
+
56
+ def get_winner(self):
57
+ if self.check_player_is_winner(self.black):
58
+ return self.black
59
+ if self.check_player_is_winner(self.white):
60
+ return self.white
61
+ return self.none
@@ -0,0 +1,44 @@
1
+ # Go Counting
2
+
3
+ Count the scored points on a Go board.
4
+
5
+ In the game of go (also known as baduk, igo, cờ vây and wéiqí) points
6
+ are gained by completely encircling empty intersections with your
7
+ stones. The encircled intersections of a player are known as its
8
+ territory.
9
+
10
+ Write a function that determines the territory of each player. You may
11
+ assume that any stones that have been stranded in enemy territory have
12
+ already been taken off the board.
13
+
14
+ Multiple empty intersections may be encircled at once and for encircling
15
+ only horizontal and vertical neighbours count. In the following diagram
16
+ the stones which matter are marked "O" and the stones that don't are
17
+ marked "I" (ignored). Empty spaces represent empty intersections.
18
+
19
+ ```
20
+ +----+
21
+ |IOOI|
22
+ |O O|
23
+ |O OI|
24
+ |IOI |
25
+ +----+
26
+ ```
27
+
28
+ To be more precise an empty intersection is part of a player's territory
29
+ if all of its neighbours are either stones of that player or empty
30
+ intersections that are part of that player's territory.
31
+
32
+ For more information see
33
+ [wikipedia](https://en.wikipedia.org/wiki/Go_%28game%29) or [Sensei's
34
+ Library](http://senseis.xmp.net/).
35
+
36
+ ## Submitting Exercises
37
+
38
+ Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
39
+
40
+ For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
41
+
42
+ ## Submitting Incomplete Solutions
43
+ It's possible to submit an incomplete solution so you can see how others have completed the
44
+ exercise.
@@ -0,0 +1,62 @@
1
+
2
+ BLACK = "B"
3
+ WHITE = "W"
4
+ NONE = ""
5
+ STONES = [BLACK, WHITE]
6
+ DIRECTIONS = [(0, 1), (0, -1), (1, 0), (-1, 0)]
7
+
8
+
9
+ class Board:
10
+ def __init__(self, board):
11
+ self.board = board.splitlines()
12
+ self.width = len(self.board[0])
13
+ self.height = len(self.board)
14
+
15
+ def valid(self, x, y):
16
+ return x >= 0 and x < self.width and y >= 0 and y < self.height
17
+
18
+ def walk(self, x, y,
19
+ visited_territory=[],
20
+ visited_coords=[],
21
+ visited_stones=[]):
22
+ if not (x, y) in visited_coords and self.valid(x, y):
23
+ s = self.board[y][x]
24
+ if s in STONES:
25
+ if s not in visited_stones:
26
+ return (visited_territory, visited_stones + [s])
27
+ else: # s is empty
28
+ for d in DIRECTIONS:
29
+ visited = self.walk(x + d[0], y + d[1],
30
+ visited_territory + [(x, y)],
31
+ visited_coords + [(x, y)],
32
+ visited_stones)
33
+ visited_territory = visited[0]
34
+ visited_stones = visited[1]
35
+
36
+ return (visited_territory, visited_stones)
37
+
38
+ def territoryFor(self, coord):
39
+ assert len(coord) == 2
40
+ x, y = coord[0], coord[1]
41
+ if not self.valid(x, y) or self.board[y][x] in STONES:
42
+ return (NONE, set())
43
+
44
+ visited_territory, visited_stones = self.walk(x, y)
45
+ result = set(visited_territory)
46
+
47
+ if len(visited_stones) == 1:
48
+ return (visited_stones[0], result)
49
+ return (NONE, result)
50
+
51
+ def territories(self):
52
+ owners = STONES + [NONE]
53
+ result = dict([(owner, set()) for owner in owners])
54
+ visited = set()
55
+ for y in range(self.height):
56
+ for x in range(self.width):
57
+ if not (x, y) in visited:
58
+ owner, owned_territories = self.territoryFor((x, y))
59
+ result[owner].update(owned_territories)
60
+ visited.update(owned_territories)
61
+
62
+ return result
@@ -0,0 +1,38 @@
1
+
2
+ class Board:
3
+ """Count territories of each player in a Go game
4
+
5
+ Args:
6
+ board (list[str]): A two-dimensional Go board
7
+ """
8
+
9
+ def __init__(self, board):
10
+ pass
11
+
12
+ def territoryFor(self, coord):
13
+ """Find the owner and the territories given a coordinate on
14
+ the board
15
+
16
+ Args:
17
+ coord ((int,int)): Coordinate on the board
18
+
19
+ Returns:
20
+ (str, set): A tuple, the first element being the owner
21
+ of that area. One of "W", "B", "". The
22
+ second being a set of coordinates, representing
23
+ the owner's territories.
24
+ """
25
+ pass
26
+
27
+ def territories(self):
28
+ """Find the owners and the territories of the whole board
29
+
30
+ Args:
31
+ none
32
+
33
+ Returns:
34
+ dict(str, set): A dictionary whose key being the owner
35
+ , i.e. "W", "B", "". The value being a set
36
+ of coordinates owned by the owner.
37
+ """
38
+ pass
@@ -0,0 +1,92 @@
1
+ import unittest
2
+ import gocounting
3
+
4
+
5
+ # Tests adapted from `problem-specifications//canonical-data.json` @ v1.1.0
6
+
7
+ board5x5 = "\n".join([
8
+ " B ",
9
+ " B B ",
10
+ "B W B",
11
+ " W W ",
12
+ " W "
13
+ ])
14
+
15
+ board9x9 = "\n".join([
16
+ " B B ",
17
+ "B B B",
18
+ "WBBBWBBBW",
19
+ "W W W W W",
20
+ " ",
21
+ " W W W W ",
22
+ "B B B B",
23
+ " W BBB W ",
24
+ " B B "
25
+ ])
26
+
27
+
28
+ class GoCountingTest(unittest.TestCase):
29
+ def test_5x5_for_black(self):
30
+ board = gocounting.Board(board5x5)
31
+ stone, territory = board.territoryFor((0, 1))
32
+ self.assertEqual(stone, gocounting.BLACK)
33
+ self.assertEqual(territory, set([(0, 0), (0, 1), (1, 0)]))
34
+
35
+ def test_5x5_for_white(self):
36
+ board = gocounting.Board(board5x5)
37
+ stone, territory = board.territoryFor((2, 3))
38
+ self.assertEqual(stone, gocounting.WHITE)
39
+ self.assertEqual(territory, set([(2, 3)]))
40
+
41
+ def test_5x5_for_open_territory(self):
42
+ board = gocounting.Board(board5x5)
43
+ stone, territory = board.territoryFor((1, 4))
44
+ self.assertEqual(stone, gocounting.NONE)
45
+ self.assertEqual(territory, set([(0, 3), (0, 4), (1, 4)]))
46
+
47
+ def test_5x5_for_non_territory(self):
48
+ board = gocounting.Board(board5x5)
49
+ stone, territory = board.territoryFor((1, 1))
50
+ self.assertEqual(stone, gocounting.NONE)
51
+ self.assertEqual(territory, set())
52
+
53
+ def test_5x5_for_valid_coordinate(self):
54
+ board = gocounting.Board(board5x5)
55
+ stone, territory = board.territoryFor((-1, 1))
56
+ self.assertEqual(stone, gocounting.NONE)
57
+ self.assertEqual(territory, set())
58
+
59
+ def test_5x5_for_valid_coordinate2(self):
60
+ board = gocounting.Board(board5x5)
61
+ stone, territory = board.territoryFor((1, 5))
62
+ self.assertEqual(stone, gocounting.NONE)
63
+ self.assertEqual(territory, set())
64
+
65
+ def test_one_territory_whole_board(self):
66
+ board = gocounting.Board(" ")
67
+ territories = board.territories()
68
+ self.assertEqual(territories[gocounting.BLACK], set())
69
+ self.assertEqual(territories[gocounting.WHITE], set())
70
+ self.assertEqual(territories[gocounting.NONE], set([(0, 0)]))
71
+
72
+ def test_two_territories_rectangular_board(self):
73
+ input_board = "\n".join([
74
+ " BW ",
75
+ " BW "
76
+ ])
77
+ board = gocounting.Board(input_board)
78
+ territories = board.territories()
79
+ self.assertEqual(territories[gocounting.BLACK], set([(0, 0), (0, 1)]))
80
+ self.assertEqual(territories[gocounting.WHITE], set([(3, 0), (3, 1)]))
81
+ self.assertEqual(territories[gocounting.NONE], set())
82
+
83
+ def test_9x9_for_open_territory(self):
84
+ board = gocounting.Board(board9x9)
85
+ stone, territory = board.territoryFor((0, 8))
86
+ self.assertEqual(stone, gocounting.NONE)
87
+ self.assertEqual(territory,
88
+ set([(2, 7), (2, 8), (1, 8), (0, 8), (0, 7)]))
89
+
90
+
91
+ if __name__ == '__main__':
92
+ unittest.main()
@@ -0,0 +1,24 @@
1
+ # Parallel Letter Frequency
2
+
3
+ Count the frequency of letters in texts using parallel computation.
4
+
5
+ Parallelism is about doing things in parallel that can also be done
6
+ sequentially. A common example is counting the frequency of letters.
7
+ Create a function that returns the total frequency of each letter in a
8
+ list of texts and that employs parallelism.
9
+
10
+ The letters used consists of ASCII letters `a` to `z`, inclusive, and is case
11
+ insensitive.
12
+
13
+ ## Submitting Exercises
14
+
15
+ Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
16
+
17
+ For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
18
+
19
+
20
+ For more detailed information about running tests, code style and linting,
21
+ please see the [help page](http://exercism.io/languages/python).
22
+
23
+ ## Submitting Incomplete Solutions
24
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,56 @@
1
+ # -*- coding: utf-8 -*-
2
+ from collections import Counter
3
+ from threading import Lock, Thread
4
+ from time import sleep
5
+ import sys
6
+ if sys.version[0] == '2':
7
+ from Queue import Queue
8
+ else:
9
+ from queue import Queue
10
+
11
+ total_workers = 3 # Maximum number of threads chosen arbitrarily
12
+
13
+
14
+ class LetterCounter(object):
15
+
16
+ def __init__(self):
17
+ self.lock = Lock()
18
+ self.value = Counter()
19
+
20
+ def add_counter(self, counter_to_add):
21
+ self.lock.acquire()
22
+ try:
23
+ self.value = self.value + counter_to_add
24
+ finally:
25
+ self.lock.release()
26
+
27
+
28
+ def count_letters(queue_of_texts, letter_to_frequency, worker_id):
29
+ while not queue_of_texts.empty():
30
+ sleep(worker_id + 1)
31
+ line_input = queue_of_texts.get()
32
+ if line_input is not None:
33
+ letters_in_line = Counter([x for x in line_input.lower() if
34
+ x.isalpha()])
35
+ letter_to_frequency.add_counter(letters_in_line)
36
+ queue_of_texts.task_done()
37
+ if line_input is None:
38
+ break
39
+
40
+
41
+ def calculate(list_of_texts):
42
+ queue_of_texts = Queue()
43
+ [queue_of_texts.put(line) for line in list_of_texts]
44
+ letter_to_frequency = LetterCounter()
45
+ threads = []
46
+ for i in range(total_workers):
47
+ worker = Thread(target=count_letters, args=(queue_of_texts,
48
+ letter_to_frequency, i))
49
+ worker.start()
50
+ threads.append(worker)
51
+ queue_of_texts.join()
52
+ for i in range(total_workers):
53
+ queue_of_texts.put(None)
54
+ for t in threads:
55
+ t.join()
56
+ return letter_to_frequency.value
@@ -0,0 +1,2 @@
1
+ def calculate(text_input):
2
+ pass
@@ -0,0 +1,61 @@
1
+ # -*- coding: utf-8 -*-
2
+ from collections import Counter
3
+ import unittest
4
+
5
+ from parallel_letter_frequency import calculate
6
+
7
+
8
+ class ParallelLetterFrequencyTest(unittest.TestCase):
9
+ def test_one_letter(self):
10
+ actual = calculate(['a'])
11
+ expected = {'a': 1}
12
+ self.assertDictEqual(actual, expected)
13
+
14
+ def test_case_insensitivity(self):
15
+ actual = calculate(['aA'])
16
+ expected = {'a': 2}
17
+ self.assertDictEqual(actual, expected)
18
+
19
+ def test_numbers(self):
20
+ actual = calculate(['012', '345', '6789'])
21
+ expected = {}
22
+ self.assertDictEqual(actual, expected)
23
+
24
+ def test_punctuations(self):
25
+ actual = calculate(['[]\;,', './{}|', ':"<>?'])
26
+ expected = {}
27
+ self.assertDictEqual(actual, expected)
28
+
29
+ def test_whitespaces(self):
30
+ actual = calculate([' ', '\t ', '\n\n'])
31
+ expected = {}
32
+ self.assertDictEqual(actual, expected)
33
+
34
+ def test_repeated_string_with_known_frequencies(self):
35
+ letter_frequency = 3
36
+ text_input = 'abc\n' * letter_frequency
37
+ actual = calculate(text_input.split('\n'))
38
+ expected = {'a': letter_frequency, 'b': letter_frequency,
39
+ 'c': letter_frequency}
40
+ self.assertDictEqual(actual, expected)
41
+
42
+ def test_multiline_text(self):
43
+ text_input = "3 Quotes from Excerism Homepage:\n" + \
44
+ "\tOne moment you feel like you're\n" + \
45
+ "getting it. The next moment you're\n" + \
46
+ "stuck.\n" + \
47
+ "\tYou know what it’s like to be fluent.\n" + \
48
+ "Suddenly you’re feeling incompetent\n" + \
49
+ "and clumsy.\n" + \
50
+ "\tHaphazard, convoluted code is\n" + \
51
+ "infuriating, not to mention costly. That\n" + \
52
+ "slapdash explosion of complexity is an\n" + \
53
+ "expensive yak shave waiting to\n" + \
54
+ "happen."
55
+ actual = calculate(text_input.split('\n'))
56
+ expected = Counter([x for x in text_input.lower() if x.isalpha()])
57
+ self.assertDictEqual(actual, expected)
58
+
59
+
60
+ if __name__ == '__main__':
61
+ unittest.main()