dsa_visualizer 0.1.1 ā 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/dsa_visualizer/algorithms/graph_algorithms.rb +322 -6
- data/lib/dsa_visualizer/algorithms/sorting.rb +106 -2
- data/lib/dsa_visualizer/data_structures/bst.rb +303 -2
- data/lib/dsa_visualizer/data_structures/deque.rb +208 -2
- data/lib/dsa_visualizer/data_structures/doubly_linked_list.rb +255 -2
- data/lib/dsa_visualizer/data_structures/graph.rb +191 -2
- data/lib/dsa_visualizer/data_structures/heap.rb +327 -4
- data/lib/dsa_visualizer/data_structures/priority_queue.rb +214 -2
- data/lib/dsa_visualizer/data_structures/trie.rb +261 -2
- data/lib/dsa_visualizer/data_structures/union_find.rb +207 -2
- metadata +5 -5
|
@@ -1,10 +1,269 @@
|
|
|
1
1
|
module DSAVisualizer
|
|
2
2
|
module DataStructures
|
|
3
3
|
class Trie
|
|
4
|
+
class TrieNode
|
|
5
|
+
attr_accessor :children, :is_end_of_word
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@children = {}
|
|
9
|
+
@is_end_of_word = false
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
4
13
|
def self.learn
|
|
5
14
|
Visualizer.print_header("TRIE - Prefix Tree")
|
|
6
|
-
|
|
7
|
-
puts "
|
|
15
|
+
|
|
16
|
+
puts "\nš CONCEPT:"
|
|
17
|
+
puts "A Trie (Prefix Tree) is a tree-like data structure for storing strings:"
|
|
18
|
+
puts "⢠Each node represents a character"
|
|
19
|
+
puts "⢠Root represents empty string"
|
|
20
|
+
puts "⢠Path from root to node = prefix"
|
|
21
|
+
puts "⢠Efficient for prefix-based operations"
|
|
22
|
+
|
|
23
|
+
puts "\nā±ļø TIME COMPLEXITY:"
|
|
24
|
+
puts "⢠Insert: O(m) where m = word length"
|
|
25
|
+
puts "⢠Search: O(m)"
|
|
26
|
+
puts "⢠Prefix search: O(m)"
|
|
27
|
+
puts "⢠Delete: O(m)"
|
|
28
|
+
|
|
29
|
+
puts "\nš¾ SPACE COMPLEXITY: O(ALPHABET_SIZE * N * M)"
|
|
30
|
+
|
|
31
|
+
demonstrate_trie
|
|
32
|
+
demonstrate_operations
|
|
33
|
+
show_ruby_vs_cpp
|
|
34
|
+
show_practice_problems
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.demonstrate_trie
|
|
38
|
+
puts "\n" + "="*60
|
|
39
|
+
puts "DEMONSTRATION: Building a Trie"
|
|
40
|
+
puts "="*60
|
|
41
|
+
|
|
42
|
+
trie = TrieImplementation.new
|
|
43
|
+
words = ["cat", "car", "card", "care", "dog", "dodge"]
|
|
44
|
+
|
|
45
|
+
puts "\nInserting words: #{words.join(', ')}"
|
|
46
|
+
words.each { |word| trie.insert(word) }
|
|
47
|
+
|
|
48
|
+
puts "\nš Trie Structure:"
|
|
49
|
+
puts " root"
|
|
50
|
+
puts " / \\"
|
|
51
|
+
puts " c d"
|
|
52
|
+
puts " | |"
|
|
53
|
+
puts " a o"
|
|
54
|
+
puts " / \\ |"
|
|
55
|
+
puts " t r g"
|
|
56
|
+
puts " |\\ |"
|
|
57
|
+
puts " d e e"
|
|
58
|
+
puts " | |"
|
|
59
|
+
puts " e (dodge)"
|
|
60
|
+
|
|
61
|
+
puts "\nš Searching:"
|
|
62
|
+
["cat", "can", "card"].each do |word|
|
|
63
|
+
result = trie.search(word)
|
|
64
|
+
puts "Search '#{word}': #{result ? 'ā Found' : 'ā Not found'}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.demonstrate_operations
|
|
69
|
+
puts "\n" + "="*60
|
|
70
|
+
puts "TRIE OPERATIONS"
|
|
71
|
+
puts "="*60
|
|
72
|
+
|
|
73
|
+
trie = TrieImplementation.new
|
|
74
|
+
["apple", "app", "application", "apply"].each { |w| trie.insert(w) }
|
|
75
|
+
|
|
76
|
+
puts "\n1ļøā£ PREFIX SEARCH:"
|
|
77
|
+
prefix = "app"
|
|
78
|
+
words = trie.words_with_prefix(prefix)
|
|
79
|
+
puts "Words starting with '#{prefix}': #{words.join(', ')}"
|
|
80
|
+
|
|
81
|
+
puts "\n2ļøā£ AUTOCOMPLETE:"
|
|
82
|
+
puts "Type 'appl'..."
|
|
83
|
+
suggestions = trie.words_with_prefix("appl")
|
|
84
|
+
puts "Suggestions: #{suggestions.join(', ')}"
|
|
85
|
+
|
|
86
|
+
puts "\n3ļøā£ COUNT WORDS:"
|
|
87
|
+
puts "Total words: #{trie.count_words}"
|
|
88
|
+
|
|
89
|
+
puts "\n4ļøā£ LONGEST PREFIX:"
|
|
90
|
+
puts "Longest common prefix: '#{trie.longest_common_prefix}'"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def self.show_ruby_vs_cpp
|
|
94
|
+
puts "\n" + "="*60
|
|
95
|
+
puts "RUBY vs C++ IMPLEMENTATION"
|
|
96
|
+
puts "="*60
|
|
97
|
+
|
|
98
|
+
puts "\nš“ RUBY:"
|
|
99
|
+
puts <<~RUBY
|
|
100
|
+
class TrieNode
|
|
101
|
+
attr_accessor :children, :is_end_of_word
|
|
102
|
+
def initialize
|
|
103
|
+
@children = {}
|
|
104
|
+
@is_end_of_word = false
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class Trie
|
|
109
|
+
def initialize
|
|
110
|
+
@root = TrieNode.new
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def insert(word)
|
|
114
|
+
node = @root
|
|
115
|
+
word.each_char do |char|
|
|
116
|
+
node.children[char] ||= TrieNode.new
|
|
117
|
+
node = node.children[char]
|
|
118
|
+
end
|
|
119
|
+
node.is_end_of_word = true
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def search(word)
|
|
123
|
+
node = @root
|
|
124
|
+
word.each_char do |char|
|
|
125
|
+
return false unless node.children[char]
|
|
126
|
+
node = node.children[char]
|
|
127
|
+
end
|
|
128
|
+
node.is_end_of_word
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
RUBY
|
|
132
|
+
|
|
133
|
+
puts "\nšµ C++:"
|
|
134
|
+
puts <<~CPP
|
|
135
|
+
struct TrieNode {
|
|
136
|
+
unordered_map<char, TrieNode*> children;
|
|
137
|
+
bool isEndOfWord;
|
|
138
|
+
TrieNode() : isEndOfWord(false) {}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
class Trie {
|
|
142
|
+
TrieNode* root;
|
|
143
|
+
public:
|
|
144
|
+
Trie() { root = new TrieNode(); }
|
|
145
|
+
|
|
146
|
+
void insert(string word) {
|
|
147
|
+
TrieNode* node = root;
|
|
148
|
+
for (char c : word) {
|
|
149
|
+
if (!node->children[c])
|
|
150
|
+
node->children[c] = new TrieNode();
|
|
151
|
+
node = node->children[c];
|
|
152
|
+
}
|
|
153
|
+
node->isEndOfWord = true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
bool search(string word) {
|
|
157
|
+
TrieNode* node = root;
|
|
158
|
+
for (char c : word) {
|
|
159
|
+
if (!node->children[c]) return false;
|
|
160
|
+
node = node->children[c];
|
|
161
|
+
}
|
|
162
|
+
return node->isEndOfWord;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
CPP
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def self.show_practice_problems
|
|
169
|
+
puts "\n" + "="*60
|
|
170
|
+
puts "PRACTICE PROBLEMS"
|
|
171
|
+
puts "="*60
|
|
172
|
+
|
|
173
|
+
problems = [
|
|
174
|
+
"1. Implement autocomplete system",
|
|
175
|
+
"2. Word search in 2D grid",
|
|
176
|
+
"3. Design search autocomplete system",
|
|
177
|
+
"4. Replace words (dictionary)",
|
|
178
|
+
"5. Longest word in dictionary",
|
|
179
|
+
"6. Add and search word (with wildcards)",
|
|
180
|
+
"7. Word break problem",
|
|
181
|
+
"8. Maximum XOR of two numbers"
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
problems.each { |p| puts p }
|
|
185
|
+
|
|
186
|
+
puts "\nš” TIP: Trie is perfect for prefix-based searches!"
|
|
187
|
+
puts "š” TIP: Space-time tradeoff: uses more space for faster search"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
class TrieImplementation
|
|
191
|
+
def initialize
|
|
192
|
+
@root = TrieNode.new
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def insert(word)
|
|
196
|
+
node = @root
|
|
197
|
+
word.each_char do |char|
|
|
198
|
+
node.children[char] ||= TrieNode.new
|
|
199
|
+
node = node.children[char]
|
|
200
|
+
end
|
|
201
|
+
node.is_end_of_word = true
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def search(word)
|
|
205
|
+
node = find_node(word)
|
|
206
|
+
node && node.is_end_of_word
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def starts_with(prefix)
|
|
210
|
+
!find_node(prefix).nil?
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def words_with_prefix(prefix)
|
|
214
|
+
node = find_node(prefix)
|
|
215
|
+
return [] unless node
|
|
216
|
+
|
|
217
|
+
words = []
|
|
218
|
+
collect_words(node, prefix, words)
|
|
219
|
+
words
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def count_words
|
|
223
|
+
count_words_recursive(@root)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def longest_common_prefix
|
|
227
|
+
return "" if @root.children.empty?
|
|
228
|
+
|
|
229
|
+
prefix = ""
|
|
230
|
+
node = @root
|
|
231
|
+
|
|
232
|
+
while node.children.size == 1 && !node.is_end_of_word
|
|
233
|
+
char = node.children.keys.first
|
|
234
|
+
prefix += char
|
|
235
|
+
node = node.children[char]
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
prefix
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
private
|
|
242
|
+
|
|
243
|
+
def find_node(word)
|
|
244
|
+
node = @root
|
|
245
|
+
word.each_char do |char|
|
|
246
|
+
return nil unless node.children[char]
|
|
247
|
+
node = node.children[char]
|
|
248
|
+
end
|
|
249
|
+
node
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def collect_words(node, prefix, words)
|
|
253
|
+
words << prefix if node.is_end_of_word
|
|
254
|
+
|
|
255
|
+
node.children.each do |char, child_node|
|
|
256
|
+
collect_words(child_node, prefix + char, words)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def count_words_recursive(node)
|
|
261
|
+
count = node.is_end_of_word ? 1 : 0
|
|
262
|
+
node.children.each_value do |child|
|
|
263
|
+
count += count_words_recursive(child)
|
|
264
|
+
end
|
|
265
|
+
count
|
|
266
|
+
end
|
|
8
267
|
end
|
|
9
268
|
end
|
|
10
269
|
end
|
|
@@ -3,8 +3,213 @@ module DSAVisualizer
|
|
|
3
3
|
class UnionFind
|
|
4
4
|
def self.learn
|
|
5
5
|
Visualizer.print_header("UNION-FIND (Disjoint Set)")
|
|
6
|
-
|
|
7
|
-
puts "
|
|
6
|
+
|
|
7
|
+
puts "\nš CONCEPT:"
|
|
8
|
+
puts "Union-Find (Disjoint Set Union) tracks connected components:"
|
|
9
|
+
puts "⢠Find: Determine which set an element belongs to"
|
|
10
|
+
puts "⢠Union: Merge two sets together"
|
|
11
|
+
puts "⢠Path compression: Flatten tree during find"
|
|
12
|
+
puts "⢠Union by rank: Attach smaller tree to larger"
|
|
13
|
+
|
|
14
|
+
puts "\nā±ļø TIME COMPLEXITY:"
|
|
15
|
+
puts "⢠Find: O(α(n)) ā O(1) amortized"
|
|
16
|
+
puts "⢠Union: O(α(n)) ā O(1) amortized"
|
|
17
|
+
puts "⢠α(n) is inverse Ackermann function (very slow growing)"
|
|
18
|
+
|
|
19
|
+
puts "\nš¾ SPACE COMPLEXITY: O(n)"
|
|
20
|
+
|
|
21
|
+
demonstrate_union_find
|
|
22
|
+
demonstrate_operations
|
|
23
|
+
show_ruby_vs_cpp
|
|
24
|
+
show_practice_problems
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.demonstrate_union_find
|
|
28
|
+
puts "\n" + "="*60
|
|
29
|
+
puts "DEMONSTRATION: Union-Find Operations"
|
|
30
|
+
puts "="*60
|
|
31
|
+
|
|
32
|
+
uf = UnionFindImplementation.new(10)
|
|
33
|
+
|
|
34
|
+
puts "\nInitial state: Each element is its own set"
|
|
35
|
+
puts "Sets: {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}"
|
|
36
|
+
|
|
37
|
+
puts "\nPerforming unions:"
|
|
38
|
+
unions = [[0, 1], [2, 3], [4, 5], [6, 7], [0, 2], [4, 6]]
|
|
39
|
+
unions.each do |a, b|
|
|
40
|
+
uf.union(a, b)
|
|
41
|
+
puts "Union(#{a}, #{b})"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
puts "\nš Current sets:"
|
|
45
|
+
puts "Set 1: {0, 1, 2, 3}"
|
|
46
|
+
puts "Set 2: {4, 5, 6, 7}"
|
|
47
|
+
puts "Set 3: {8}"
|
|
48
|
+
puts "Set 4: {9}"
|
|
49
|
+
|
|
50
|
+
puts "\nNumber of components: #{uf.count}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.demonstrate_operations
|
|
54
|
+
puts "\n" + "="*60
|
|
55
|
+
puts "UNION-FIND OPERATIONS"
|
|
56
|
+
puts "="*60
|
|
57
|
+
|
|
58
|
+
uf = UnionFindImplementation.new(6)
|
|
59
|
+
|
|
60
|
+
puts "\n1ļøā£ FIND OPERATION:"
|
|
61
|
+
puts "Find(0): #{uf.find(0)}"
|
|
62
|
+
puts "Find(3): #{uf.find(3)}"
|
|
63
|
+
|
|
64
|
+
puts "\n2ļøā£ UNION OPERATION:"
|
|
65
|
+
uf.union(0, 1)
|
|
66
|
+
uf.union(2, 3)
|
|
67
|
+
puts "After Union(0,1) and Union(2,3)"
|
|
68
|
+
puts "Connected(0, 1): #{uf.connected?(0, 1)}"
|
|
69
|
+
puts "Connected(0, 2): #{uf.connected?(0, 2)}"
|
|
70
|
+
|
|
71
|
+
puts "\n3ļøā£ CHECK CONNECTIVITY:"
|
|
72
|
+
uf.union(1, 2)
|
|
73
|
+
puts "After Union(1,2)"
|
|
74
|
+
puts "Connected(0, 3): #{uf.connected?(0, 3)}"
|
|
75
|
+
|
|
76
|
+
puts "\n4ļøā£ COUNT COMPONENTS:"
|
|
77
|
+
puts "Number of disjoint sets: #{uf.count}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.show_ruby_vs_cpp
|
|
81
|
+
puts "\n" + "="*60
|
|
82
|
+
puts "RUBY vs C++ IMPLEMENTATION"
|
|
83
|
+
puts "="*60
|
|
84
|
+
|
|
85
|
+
puts "\nš“ RUBY:"
|
|
86
|
+
puts <<~RUBY
|
|
87
|
+
class UnionFind
|
|
88
|
+
def initialize(n)
|
|
89
|
+
@parent = (0...n).to_a
|
|
90
|
+
@rank = Array.new(n, 0)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def find(x)
|
|
94
|
+
if @parent[x] != x
|
|
95
|
+
@parent[x] = find(@parent[x]) # Path compression
|
|
96
|
+
end
|
|
97
|
+
@parent[x]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def union(x, y)
|
|
101
|
+
root_x = find(x)
|
|
102
|
+
root_y = find(y)
|
|
103
|
+
return if root_x == root_y
|
|
104
|
+
|
|
105
|
+
# Union by rank
|
|
106
|
+
if @rank[root_x] < @rank[root_y]
|
|
107
|
+
@parent[root_x] = root_y
|
|
108
|
+
elsif @rank[root_x] > @rank[root_y]
|
|
109
|
+
@parent[root_y] = root_x
|
|
110
|
+
else
|
|
111
|
+
@parent[root_y] = root_x
|
|
112
|
+
@rank[root_x] += 1
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
RUBY
|
|
117
|
+
|
|
118
|
+
puts "\nšµ C++:"
|
|
119
|
+
puts <<~CPP
|
|
120
|
+
class UnionFind {
|
|
121
|
+
vector<int> parent, rank;
|
|
122
|
+
public:
|
|
123
|
+
UnionFind(int n) : parent(n), rank(n, 0) {
|
|
124
|
+
iota(parent.begin(), parent.end(), 0);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
int find(int x) {
|
|
128
|
+
if (parent[x] != x)
|
|
129
|
+
parent[x] = find(parent[x]); // Path compression
|
|
130
|
+
return parent[x];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
void unite(int x, int y) {
|
|
134
|
+
int rootX = find(x);
|
|
135
|
+
int rootY = find(y);
|
|
136
|
+
if (rootX == rootY) return;
|
|
137
|
+
|
|
138
|
+
// Union by rank
|
|
139
|
+
if (rank[rootX] < rank[rootY]) {
|
|
140
|
+
parent[rootX] = rootY;
|
|
141
|
+
} else if (rank[rootX] > rank[rootY]) {
|
|
142
|
+
parent[rootY] = rootX;
|
|
143
|
+
} else {
|
|
144
|
+
parent[rootY] = rootX;
|
|
145
|
+
rank[rootX]++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
CPP
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def self.show_practice_problems
|
|
153
|
+
puts "\n" + "="*60
|
|
154
|
+
puts "PRACTICE PROBLEMS"
|
|
155
|
+
puts "="*60
|
|
156
|
+
|
|
157
|
+
problems = [
|
|
158
|
+
"1. Number of connected components in graph",
|
|
159
|
+
"2. Detect cycle in undirected graph",
|
|
160
|
+
"3. Friend circles / Number of provinces",
|
|
161
|
+
"4. Redundant connection",
|
|
162
|
+
"5. Accounts merge",
|
|
163
|
+
"6. Most stones removed",
|
|
164
|
+
"7. Satisfiability of equality equations",
|
|
165
|
+
"8. Smallest string with swaps"
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
problems.each { |p| puts p }
|
|
169
|
+
|
|
170
|
+
puts "\nš” TIP: Union-Find is perfect for dynamic connectivity problems!"
|
|
171
|
+
puts "š” TIP: Use for Kruskal's MST algorithm"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
class UnionFindImplementation
|
|
175
|
+
def initialize(n)
|
|
176
|
+
@parent = (0...n).to_a
|
|
177
|
+
@rank = Array.new(n, 0)
|
|
178
|
+
@count = n
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def find(x)
|
|
182
|
+
if @parent[x] != x
|
|
183
|
+
@parent[x] = find(@parent[x]) # Path compression
|
|
184
|
+
end
|
|
185
|
+
@parent[x]
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def union(x, y)
|
|
189
|
+
root_x = find(x)
|
|
190
|
+
root_y = find(y)
|
|
191
|
+
return if root_x == root_y
|
|
192
|
+
|
|
193
|
+
# Union by rank
|
|
194
|
+
if @rank[root_x] < @rank[root_y]
|
|
195
|
+
@parent[root_x] = root_y
|
|
196
|
+
elsif @rank[root_x] > @rank[root_y]
|
|
197
|
+
@parent[root_y] = root_x
|
|
198
|
+
else
|
|
199
|
+
@parent[root_y] = root_x
|
|
200
|
+
@rank[root_x] += 1
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
@count -= 1
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def connected?(x, y)
|
|
207
|
+
find(x) == find(y)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def count
|
|
211
|
+
@count
|
|
212
|
+
end
|
|
8
213
|
end
|
|
9
214
|
end
|
|
10
215
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dsa_visualizer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- DSA Learning Team
|
|
@@ -131,10 +131,10 @@ homepage: https://github.com/Avinashkrmehta/dsa_visualizer
|
|
|
131
131
|
licenses:
|
|
132
132
|
- MIT
|
|
133
133
|
metadata:
|
|
134
|
-
bug_tracker_uri: https://github.com/
|
|
135
|
-
changelog_uri: https://github.com/
|
|
136
|
-
documentation_uri: https://github.com/
|
|
137
|
-
source_code_uri: https://github.com/
|
|
134
|
+
bug_tracker_uri: https://github.com/Avinashkrmehta/dsa_visualizer/issues
|
|
135
|
+
changelog_uri: https://github.com/Avinashkrmehta/dsa_visualizer/blob/main/CHANGELOG.md
|
|
136
|
+
documentation_uri: https://github.com/Avinashkrmehta/dsa_visualizer/blob/main/README.md
|
|
137
|
+
source_code_uri: https://github.com/Avinashkrmehta/dsa_visualizer
|
|
138
138
|
post_install_message:
|
|
139
139
|
rdoc_options: []
|
|
140
140
|
require_paths:
|