#include<iostream>
#include<string>
#include<vector>
#include<unordered_set>
using namespace std;
class TrieNode {
public:
	bool isWord;
	TrieNode * subTrie[26];
	TrieNode() {
		isWord = false;
		for (int i = 0; i < 26; i++)
			subTrie[i] = NULL;
	}
};
class Trie {
private:
	TrieNode * root;
public:
	Trie() {
		root = new TrieNode();
	}
	~Trie() {
		destruct(root);
		if (root != NULL)
			delete root;
	}
	void destruct(TrieNode * node) {
		if (node == NULL) return;
		for (int i = 0; i < 26; i++) {
			if (node->subTrie[i] != NULL) {
				destruct(node->subTrie[i]);
				delete node->subTrie[i];
			}
		}
	}
	void addWord(string word) {
		TrieNode * curr = root;
		for (int i = 0; i < word.length(); i++) {
			int idx = word[i] - 'A';
			if (idx < 0 || idx > 25) continue;
			if (curr->subTrie[idx] == NULL) {
				curr->subTrie[idx] = new TrieNode();
			}
			curr = curr->subTrie[idx];
		}
		curr->isWord = true;
	}
	string searchSet(vector<unordered_set<char>> &setSet, string &word, unsigned int maxDepth) {
		TrieNode *curr = root;
		int depth = 0;
		bool gotAbsent = false;
		unordered_set<char>::iterator itr = setSet[depth].begin();
		// breath first search
		for (; itr != setSet[depth].end(); itr++) {
			int idx = (*itr) - 'A';
			if (curr->subTrie[idx] == NULL) {
				// continue depth first search
				word[depth] = *itr;
				gotAbsent = true;
				break;
			}
		}
		if (gotAbsent) {
			return word;
		} else {
			if (searchNextLevel(curr, depth, word, setSet, maxDepth)) {
				return word;
			} else {
				return "-";
			}
		}
	}
	bool searchNextLevel(TrieNode *curr, int depth, string &word, vector<unordered_set<char>> &setSet, unsigned int maxDepth) {
		if (depth >= maxDepth - 1) {
			return false;
		}
		bool gotAbsent = false;
		unordered_set<char>::iterator itr = setSet[depth].begin();
		for (; itr != setSet[depth].end(); itr++) {
			int idx = (*itr) - 'A';
			gotAbsent = false;
			TrieNode* nextCurr = curr->subTrie[idx];
			word[depth] = *itr;
			unordered_set<char>::iterator itr2 = setSet[depth + 1].begin();
			for (; itr2 != setSet[depth + 1].end(); itr2++) {
				int idx2 = (*itr2) - 'A';
				if (nextCurr->subTrie[idx2] == NULL) {
					word[depth + 1] = *itr2;
					gotAbsent = true;
					break;
				}
			}
			if (gotAbsent) {
				return true;
			} else {
				if (searchNextLevel(nextCurr, depth + 1, word, setSet, maxDepth)) {
					return true;
				}
			}
		}
		return false;
	} // end of function
};
class MyMap {
public:
	vector<unordered_set<char>> setSet;
	Trie trie;
	string aWord;
	unsigned int N;
	unsigned int L;
	MyMap(unsigned int n, unsigned int l) {
		N = n;
		L = l;
		setSet = vector<unordered_set<char>>(L);
	}
	void insertSet(int y, char C) {
		if (setSet[y].find(C) == setSet[y].end()) {
			(setSet[y]).insert(C);
		}
	}
	void insertTrie(string word) {
		aWord = word;
		trie.addWord(word);
	}
	string calculateResult() {
		unsigned int n = 1;
		for (int i = 0; i < L; i++) {
			n = n * setSet[i].size();
		}
		if (n <= N) {
			return "-";
		} else {
			return trie.searchSet(setSet, aWord, L);
		}
	}
};
int main() {
	unsigned int T = 0, N = 0, L = 0;
	string word;
	cin >> T;
	for (int i = 0; i < T; i++) {
		cin >> N;
		cin >> L;
		MyMap myMap(N, L);
		for (int x = 0; x < N; x++) {
			cin >> word;
			myMap.insertTrie(word);
			for (int y = 0; y < L; y++) {
				myMap.insertSet(y, word[y]);
			}
		}
		string re = myMap.calculateResult();
		cout << "Case #" << i + 1 << ": " << re << endl;
	}
	return 0;
}