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 <cstring>
#include <string>
#include <algorithm>
#include <iomanip>
#include <cmath>
#include <cassert>
#include <map>
using namespace std;

string b[10];
int dx[8] = { 1, 0, -1, 0, 1, 1, -1, -1 };
int dy[8] = { 0, 1, 0, -1, 1, -1, 1, -1 };
bool visit[10][20];

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

	int h, w;
	while(cin >> h >> w, h | w) {
		for(int i = 0; i < h; i++) {
			cin >> b[i];
		}

		map<string, int> m;

		for(int y = 0; y < h; y++) {
			for(int x = 0; x < w; x++) {
				for(int k = 0; k < 8; k++) {
					int ny = y, nx = x;
					memset(visit, 0, sizeof visit);
					string s;
					while(!visit[ny][nx]) {
						visit[ny][nx] = true;
						s += b[ny][nx];
						m[s]++;
						ny = (ny + dy[k] + h) % h;
						nx = (nx + dx[k] + w) % w;
					}
				}
			}
		}

		string ans;
		for(auto p : m) {
			if(p.second <= 1 || p.first.size() <= 1) continue;
			string s = p.first;
			if(ans.size() < s.size() || ans.size() == s.size() && ans > s) {
				ans = s;
			}
		}
		if(ans == "") ans = "0";
		cout << ans << endl;
	}
}

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 <bits/stdc++.h>
#define For(i, a, b) for(int (i)=(int)(a); (i)<(int)(b); ++(i))
#define rFor(i, a, b) for(int (i)=(int)(a)-1; (i)>=(int)(b); --(i))
#define rep(i, n) For((i), 0, (n))
#define rrep(i, n) rFor((i), (n), 0)
#define fi first
#define se second
using namespace std;
typedef long long lint;
typedef unsigned long long ulint;
typedef pair<int, int> pii;
template<class T> bool chmax(T &a, const T &b){if(a<b){a=b; return true;} return false;}
template<class T> bool chmin(T &a, const T &b){if(a>b){a=b; return true;} return false;}
template<class T> T div_floor(T a, T b){
    if(b < 0) a *= -1, b *= -1;
    return a>=0 ? a/b : (a+1)/b-1;
}
template<class T> T div_ceil(T a, T b){
    if(b < 0) a *= -1, b *= -1;
    return a>0 ? (a-1)/b+1 : a/b;
}

constexpr lint mod = 1e9+7;
constexpr lint INF = mod * mod;
constexpr int MAX = 300010;

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

int main(){
    int h, w;
    while(scanf("%d%d", &h, &w) && h){
        string s[h];
        rep(i, h) cin >> s[i];
        map<string, int> mp;
        rep(sx, h)rep(sy, w)rep(i, 8){
            string tmp;
            int x = sx, y = sy;
            do{
                tmp += s[x][y];
                ++mp[tmp];
                x = (x + dx[i] + h) % h;
                y = (y + dy[i] + w) % w;
            }while(x != sx || y != sy);
        }

        string ans = "0";
        for(auto &p: mp)if(p.se >= 2){
            if(ans.size() < p.fi.size() || (ans.size() == p.fi.size() && ans > p.fi)){
                ans = p.fi;
            }
        }
        cout << ans << "\n";
    }
}

C++: #include <iostream>
#include <algorithm>
#include <set>
using namespace std;
typedef unsigned long long ulli;

const int MAXH = 10;
const int MAXW = 20;
const ulli mod = 100000007ULL;

int H, W;
char G[MAXH][MAXW];
int cnt;
int vis[MAXH][MAXW];

int main() {
  while(cin >> H >> W && (H|W)) {
    for(int i = 0; i < H; ++i) {
      for(int j = 0; j < W; ++j) {
        cin >> G[i][j];
      }
    }
    string res = "";
    set<ulli> t;
    cnt = 0;
    fill(vis[0], vis[MAXH], 0);
    for(int i = 0; i < H; ++i) {
      for(int j = 0; j < W; ++j) {
        for(int di = -1; di <= 1; ++di) {
          for(int dj = -1; dj <= 1; ++dj) {
            if(di|dj); else continue;
            ++cnt;
            string s(1, G[i][j]);
            ulli h = G[i][j];
            int ni, nj;
            ni = i; nj = j;
            vis[ni][nj] = cnt;

            while(1) {
              ni = (ni+di+H)%H;
              nj = (nj+dj+W)%W;
              if(vis[ni][nj] == cnt) break;
              s += G[ni][nj];
              h = h * mod + G[ni][nj];

              vis[ni][nj] = cnt;
              if(t.count(h)) {
                if(s.size() > res.size() ||
                   s.size() == res.size() && s < res) {
                  res = s;
                }
              } else {
                t.insert(h);
              }
            }
          }
        }
      }
    }
    if(res == "") res = "0";
    cout << res << endl;
  }
  return 0;
}