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 <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <map>
#include <set>

#define REP(i,k,n) for(int i=k;i<n;i++)
#define rep(i,n) for(int i=0;i<n;i++)
#define INF 1<<30
#define pb push_back
#define mp make_pair

using namespace std;
typedef long long ll;
typedef pair<int,int> P;

int w,h,x,y;
int sx,sy,gx,gy;
int dx[9] = { 1, 1, 1, 0, 0, 0,-1,-1,-1};
int dy[9] = {-1, 0, 1,-1, 0, 1,-1, 0, 1};

bool can(int y,int x) {
	if(0 <= y && y < h && 0 <= x && x < w) return true;
	return false;
}

int main() {
	while(cin >> h >> w) {
		if(h == 0 && w == 0) break;

		vector<string> s(h);
		rep(i, h) cin >> s[i];

		map<string, int> m;
		bool used[15][25];

		rep(i, h) {
			rep(j, w) {
				rep(k, 9) {
					int y = i, x = j;
					memset(used, 0, sizeof(used));
					string t = "";
					while(!used[y][x]) {
						used[y][x] = true;
						t += s[y][x];

						y = (y + h + dy[k]) % h;
						x = (x + w + dx[k]) % w;

						if(t.size() > 1) m[t]++;
					}
				}
			}
		}

		string ans = "";
		map<string, int>::iterator ite;
		for(ite = m.begin(); ite != m.end(); ite++) {
			if(ite->second < 2) continue;
			if(ite->first.size() > ans.size()) {
				ans = ite->first;
			} else if(ite->first.size() == ans.size()) {
				bool flag = true;
				rep(i, ans.size()) {
					if(ite->first[i] <= ans[i]) continue;
					flag = false;
				}

				if(flag) ans = ite->first;
			}
		}

		if(ans.size() == 0) cout << 0 << endl;
		else cout << ans << endl;
	}

	return 0;
}

C++: #include <bits/stdc++.h>
using namespace std;

// region template
#define rep(i, a, b) for (int i = (a); i < (b); ++i)
#define trav(a, x) for (auto &a : x)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;

ll gcd(ll a, ll b) { return __gcd(a, b); }

ll euclid(ll a, ll b, ll &x, ll &y) {
    if (b) { ll d = euclid(b, a % b, y, x);
        return y -= a/b * x, d; }
    return x = 1, y = 0, a;
}

typedef unsigned long long ull;
typedef long double ld;
ull mod_mul(ull a, ull b, ull M) {
    ll ret = a * b - M * ull(ld(a) * ld(b) / ld(M));
    return ret + M * (ret < 0) - M * (ret >= (ll)M);
}
ull mod_pow(ull b, ull e, ull mod) {
    ull ans = 1;
    for (; e; b = mod_mul(b, b, mod), e /= 2)
        if (e & 1) ans = mod_mul(ans, b, mod);
    return ans;
}

const ll mod = 1000000007;
struct Mod {
    ll x;
    Mod(ll xx) : x(xx) {}
    Mod operator+(Mod b) { return Mod((x + b.x) % mod); }
    Mod operator-(Mod b) { return Mod((x - b.x) % mod); }
    Mod operator*(Mod b) { return Mod((x * b.x) % mod); }
    Mod operator/(Mod b) { return *this * invert(b); }
    Mod invert(Mod a) {
        ll x, y, g = euclid(a.x, mod, x, y);
        assert(g == 1); return Mod((x + mod) % mod);
    }
    Mod operator^(ll e) {
        if (!e) return Mod(1);
        Mod r = *this ^ (e / 2); r = r * r;
        return e & 1 ? *this * r : r;
    }
};
// endregion

int n, m;
string grid[20];
map<string, int> mp;

void gen2(string s) {
    int l = s.length();
    rep(i, 0, l) {
        string k;
        rep(j, 0, l) {
            k += s[(i + j) % l];
            if (k.size() > 1) mp[k]++;
        }
    }
}

void gen(string s) {
    gen2(s);
    reverse(s.begin(), s.end());
    gen2(s);
}

int main() {
    for (;;) {
        cin >> n >> m; if (!n) break;
        mp.clear();

        for (int i = 0; i < n; i++) {
            cin >> grid[i];
        }

        for (int i = 0; i < n; i++) {
            string buf;
            for (int j = 0; j < m; j++) {
                buf += grid[i][j];
            }
            // cout << buf << endl;
            gen(buf);
        }

        for (int j = 0; j < m; j++) {
            string buf;
            for (int i = 0; i < n; i++) {
                buf += grid[i][j];
            }
            // cout << buf << endl;
            gen(buf);
        }

        int g = __gcd(n, m);
        for (int a = 0; a < g; a++) {
            string buf;
            for (int b = 0, i = a, j = 0; b < n * m / g; ++b, ++i %= n, ++j %= m) {
                buf += grid[i][j];
            }
            // cout << buf << endl;
            gen(buf);
        }
        for (int a = 0; a < g; a++) {
            string buf;
            for (int b = 0, i = a, j = 0; b < n * m / g; ++b, ++i %= n, j = (j + m - 1) % m) {
                buf += grid[i][j];
            }
            // cout << buf << endl;
            gen(buf);
        }

        string best = "";
        for (auto p : mp) {
            if (p.second >= 2 && (p.first.size() > best.size() || p.first.size() == best.size() && p.first < best)) {
                best = p.first;
            }
        }
        cout << (best.size() ? best.c_str() : "0") << endl;
    }
}

C++: #include <bits/stdc++.h>

using namespace std;

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

int main()
{
	long long int M , N;
	while(cin >> M >> N , M || N)
	{
		vector<vector<char>>D(M , vector<char>(N));
		set<string>SS;
		string ans;
		for(size_t i = 0; i < M; i++)
		{
			for(size_t j = 0; j < N; j++)
			{
				cin >> D[i][j];
			}
		}
		for(long long int i = 0; i < M; i++)
		{
			for(long long int j = 0; j < N; j++)
			{
				long long int startx = j , starty = i;
				for(long long int k = 0; k < 8; k++)
				{
					long long int p = 1;
					string s;
					s.push_back(D[starty][startx]);
					while(!( ( startx + p*dx[k] + N * 2000 ) % N == startx && ( starty + p*dy[k] + M * 2000 ) % M == starty ))
					{
						s.push_back(D[( starty + p*dy[k] + M * 205 ) % M][( startx + p*dx[k] + N * 205 ) % N]);
						if(s.length() > ans.length())
						{
							if(SS.find(s) != SS.end())
							{
								ans = s;
							} else
							{
								SS.insert(s);
							}
						}
						p++;
					}
				}
			}
		}
		if(ans == "")
		{
			cout << 0 << endl;
		} else
		{
			cout << ans << endl;
		}
	}
}