Go: package main

import "fmt"

var H, W int

type point struct {
	x, y int
}

func (p *point) add(q point) {
	p.x += q.x
	p.y += q.y
	if p.x < 0 {
		p.x += H
	}
	if p.y < 0 {
		p.y += W
	}
	p.x %= H
	p.y %= W
}

func isPalindrome(str string) bool {
	for i, j := 0, len(str)-1; i < j; i, j = i+1, j-1 {
		if str[i] != str[j] {
			return false
		}
	}
	return true
}

func magicSpel(arr []string) string {
	var ans string
	m := map[string]int{}
	for i := range arr {
		for j := range arr[i] {
			for _, d := range []point{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}} {
				cur := point{x: i, y: j}
				str := string(arr[cur.x][cur.y])
				cur.add(d)
				for i != cur.x || j != cur.y {
					str += string(arr[cur.x][cur.y])
					cur.add(d)
					if isPalindrome(str) {
						m[str] += 2
					} else {
						m[str]++
					}
				}
			}
		}
	}
	for s, v := range m {
		if 1 < v {
			if len(ans) < len(s) {
				ans = s
			} else if len(ans) == len(s) && s < ans {
				ans = s
			}
		}
	}

	if len(ans) == 0 {
		return "0"
	}

	return ans
}

func main() {
	for {
		fmt.Scan(&H, &W)
		if H == 0 && W == 0 {
			break
		}

		var arr []string

		for i := 0; i < H; i++ {
			var s string
			fmt.Scan(&s)
			arr = append(arr, s)
		}

		fmt.Println(magicSpel(arr))
	}
}

// 2 3
// ABC
// DEF

C++: #include <vector>
#include <iostream>
#include <utility>
#include <algorithm>
#include <string>
#include <deque>
#include <tuple>
#include <queue>
#include <functional>
#include <cmath>
#include <iomanip>
#include <map>
//cin.sync_with_stdio(false);
//streambuf
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;

int main() {
	int h, w;
	while (cin >> h >> w, h) {
		vector<string> map(h);
		for (auto &a : map)cin >> a;
		int dx[] = { 0,0,1,1,1,-1,-1,-1 };
		int dy[] = { 1,-1,0,-1,1,0,1,-1 };
		vector<tuple<string, int, int, int>> buf;
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				for (int d = 0; d < 8; d++) {
					buf.push_back(make_tuple((string)"" + map[i][j], j, i, d));
				}
			}
		}
		int l = 1;
		for (;; l++) {
			sort(buf.begin(), buf.end());
			vector<tuple<string, int, int, int>> buf2;
			for (int i = 1; i < buf.size(); i++) {
				if (get<0>(buf[i - 1]).size() < l)continue;
				if (get<0>(buf[i - 1]) == get<0>(buf[i]))buf2.push_back(buf[i - 1]);
				for (; i<buf.size()&&get<0>(buf[i - 1]) == get<0>(buf[i]); i++)buf2.push_back(buf[i]);
			}
			if (buf2.empty())break;
			buf = move(buf2);
			for (auto &a : buf) {
				string str;
				int x, y, d;
				tie(str, x, y, d) = a;
				int x1 = ((x + dx[d]*l) % w + w) % w;
				int y1 = ((y + dy[d]*l) % h + h) % h;
				if (x1 == x && y1 == y)continue;
				str += map[y1][x1];
				a = make_tuple(str, x, y, d);
			}
		}
		if (l < 3)cout << 0 << endl;
		else {
			string str = get<0>(buf[0]);
			cout << str.substr(0, l-1) << endl;
		}
	}
	return 0;
}

C++: #include <iostream>
#include <vector>
#include <string>
#include <set>

using namespace std;

const int dx[] = { -1, 0, 1, 1, 1, 0, -1, -1 };
const int dy[] = { -1, -1, -1, 0, 1, 1, 1, 0 };

int main(){
	while(true){
		int w, h;
		cin >> h >> w;
		if(h == 0 && w == 0){ break; }
		vector<string> v(h);
		for(int i = 0; i < h; ++i){ cin >> v[i]; }
		set<string> found;
		string answer;
		for(int i = 0; i < h; ++i){
			for(int j = 0; j < w; ++j){
				for(int d = 0; d < 8; ++d){
					int y = i, x = j;
					string s;
					do {
						s += v[y][x];
						if(found.find(s) == found.end()){
							found.insert(s);
						}else{
							if(answer.size() < s.size()){
								answer = s;
							}else if(answer.size() == s.size() && s < answer){
								answer = s;
							}
						}
						y = (y + dy[d] + h) % h;
						x = (x + dx[d] + w) % w;
					} while(y != i || x != j);
				}
			}
		}
		cout << answer << endl;
	}
	return 0;
}

C++: #include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
using namespace std;

#define lengthof(array) (sizeof(array) / sizeof(*array))
#define dump(a) (cerr << (#a) << " = " << (a) << endl)
#define FOR(it,c) for(__typeof((c).begin())it=(c).begin(); it!=(c).end();++it)
#define RFOR(it,c) for(__typeof((c).rbegin())it=(c).rbegin(); it!=(c).rend();++it)

template<class T> inline void chmax(T& a, const T& b) { if(b > a) a = b; }
template<class T> inline void chmin(T& a, const T& b) { if(b < a) a = b; }

template<typename T, typename U> ostream& operator<<(ostream& os, const pair<T, U>& p) {
	os << '(' << p.first << ", " << p.second << ')';
	return os;
}

template<typename T> ostream& operator<<(ostream& os, const vector<T>& v) {
	copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
	return os;
}

int h, w;
const int dx[8] = {0, 1, 1, 1, 0, -1, -1, -1};
const int dy[8] = {1, 1, 0, -1, -1, -1, 0, 1};
vector<string> donut;
bool visited[10][20];

inline unsigned long long hash(const string& s) {
	const unsigned long long base = 1000000007;
	long long res = 0;
	for(int i = 0; i < s.size(); ++i) {
		res *= base;
		res += s[i];
	}

	return res;
}

string spell(int x, int y, int d) {
	if(visited[y][x])
		return "";

	visited[y][x] = true;
	string res = donut[y][x] + spell((x + dx[d] + w) % w, (y + dy[d] + h) % h, d);
	visited[y][x] = false;
	return res;
}

int main() {
	cin.tie(0);
	ios::sync_with_stdio(false);

	const string init(2, 'z' + 1);

	while(cin >> h >> w, h) {
		donut.clear();
		donut.resize(h);
		for(int i = 0; i < h; ++i)
			cin >> donut[i];

		string ans = init;
//		set<string> s;
		set<unsigned long long> s;
		map<string, int> cnt;
		for(int i = 0; i < h; ++i) {
			for(int j = 0; j < w; ++j) {
				for(int d = 0; d < 8; ++d) {
					const string str = spell(j, i, d);
					for(int i = ans.size(); i <= str.size(); ++i) {

						const string tmp = str.substr(0, i);
/*
						if(s.find(tmp) == s.end())
							s.insert(tmp);
*/

						const unsigned long long h = hash(tmp);
						if(s.find(h) == s.end())
							s.insert(h);

						else if(ans.size() < tmp.size() || (ans.size() == tmp.size() && tmp < ans))
							ans = tmp;
					}
				}
			}
		}

		cout << (ans != init ? ans : "0") << endl;
	}

	return EXIT_SUCCESS;
}