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 <algorithm>
#include <map>
#include <string>
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)

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

int w, h;
char grid[10][20];
map<string, int> spell;

void dfs(int sy, int sx, int y, int x, int d, string str)
{
	spell[str]++;

	int ny = (y + dy[d] + h) % h;
	int nx = (x + dx[d] + w) % w;
	
	if (ny == sy&&nx == sx) {
		return;
	}
	
	dfs(sy, sx, ny, nx, d, str + grid[ny][nx]);
}

int main()
{
	while (true) {
		cin >> h >> w;

		if (h == 0 && w == 0) {
			break;
		}

		spell.clear();
		vector<vector<bool>> visited(h, vector<bool>(w, false));

		rep(y, h) {
			rep(x, w) {
				cin >> grid[y][x];
			}
		}

		rep(y, h) {
			rep(x, w) {
				rep(d, 8) {
					string str;
					dfs(y, x, y, x, d, str + grid[y][x]);
				}
			}
		}

		string ans;

		for (auto it = spell.begin(); it != spell.end(); it++) {
			if (it->second >= 2) {
				if (ans.size() < it->first.size()) {
					ans = it->first;
				}
				else if (ans.size() == it->first.size()) {
					if (it->first < ans) {
						ans = it->first;
					}
				}
			}
		}

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

	return 0;
}

C++: #include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <sstream>
#include <algorithm>
#include <tr1/unordered_map>
using namespace std;
#define map tr1::unordered_map
#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
int H,W;
char MAP[20][20];
int dx[8]={1,0,-1,0,1,1,-1,-1};
int dy[8]={0,1,0,-1,-1,1,-1,1};
 
bool input(){
    cin>>H>>W;
    if(H==0&&W==0)return false;
    REP(y,H){
        string t;
        cin>>t;
        REP(x,W){
            MAP[x][y]=t[x];
        }
    }
    return true;
}
map<string,int> res;
void solve(int x,int y,int d){
    string s;
    int nx=x,ny=y;
    do{
        s.push_back(MAP[nx][ny]);
        if(x==nx&&y==ny&&d==0)res[s]++;
        else if(x!=nx||y!=ny)res[s]++;
        nx=nx+dx[d]+W;
        ny=ny+dy[d]+H;
        nx%=W;
        ny%=H;
    }while((nx!=x||ny!=y));
}
int main() {
    while(input()){
        res.clear();
        REP(x,W){
            REP(y,H){
                REP(k,8){
                    solve(x,y,k);
                }
            }
        }
        string ans="";
 
        FOR(it,res){
            if(it->first.size()==1)continue;
            if(it->second>1){
                string r=it->first;
                if(r.size()>ans.size()){
                    ans=r;
                }else if(r.size()==ans.size()){
                    ans=min(ans,r);
                }
            }
        }
        if(ans=="")ans="0";
        cout<<ans<<endl;
    }
 
    return 0;
}

C++: #include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <cstring>
#include <sstream>
#include <cassert>
#include <ctime>
#include <list>
#include <numeric>
#include <fstream>

using namespace std;
static const double EPS = 1e-8;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> PI;
#ifndef M_PI
const double M_PI=acos(-1.0);
#endif
#define rep(i,n) for(int i=0;i<(int)(n);++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define FORR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();++i)
#define ALL(c) (c).begin(), (c).end()
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define SZ(a) (int((a).size()))
#define F first
#define S second
void pkuassert(bool b){if(!b){int a=0;cout << 1/a << endl;}};
int dx[]={0,-1,0,1,1,1,-1,-1},dy[]={1,0,-1,0,1,-1,1,-1};

int n,m;

string in[100];

void solve(){
  vector<string> app;  
  rep(i,n) cin >> in[i];
  rep(i,n)rep(j,m){
    rep(k,8){
      int cx=i,cy=j;
      string str;
      do{
        str += in[cx][cy];
        cx += dx[k];
        cy += dy[k];
        if(cx<0) cx += n;
        if(cy<0) cy += m;
        if(cx>=n) cx -= n;
        if(cy>=m) cy -= m;
      }while(cx!=i || cy!=j);
      app.pb(str);
    }
  }
  sort(ALL(app));

  string ans;
  rep(i,SZ(app)-1){
    int le=0;
    while(le<SZ(app[i]) && le<SZ(app[i+1]) &&
          app[i][le]==app[i+1][le])
      ++le;
    if(SZ(ans)<le) ans = app[i].substr(0,le);
  }
  
  if(SZ(ans)>1) cout << ans << endl;
  else cout << 0 << endl;
}

int main(){
  while(cin >> n >> m && n&&m) solve();
}

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 = 0;
		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;
}