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 <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <functional>
using namespace std;

#define rep(i,a,n) for(int (i)=(a); (i)<(n); (i)++)
#define repq(i,a,n) for(int (i)=(a); (i)<=(n); (i)++)
#define repr(i,a,n) for(int (i)=(a); (i)>=(n); (i)--)
#define int long long int

template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}

typedef pair<int, int> pii;
typedef long long ll;

int dx[] = {0, 0, 1, -1, 1, 1, -1, -1};
int dy[] = {1, -1, 0, 0, 1, -1, 1, -1};
constexpr ll INF = 1001001001001001LL;
constexpr ll MOD = 1000000007LL;

int H, W;
char board[15][25];
bool used[15][25];
map<string, int> memo;

void solve(int x, int y, int dir) {
    string ret = "";
    int s = x, t = y;
    while(1) {
        if(used[s][t]) break;
        used[s][t] = true;
        ret += board[s][t];
        memo[ret]++;

        s = (s + dx[dir] + H) % H;
        t = (t + dy[dir] + W) % W;
    }
}

bool isbetter(string a, string b) {
    if(a.length() != b.length()) return a.length() > b.length();
    else return a < b;
}

signed main() {
    while(cin >> H >> W, H || W) {
        memo.clear();
        rep(i,0,H) rep(j,0,W) cin >> board[i][j];
        rep(i,0,H) rep(j,0,W) rep(k,0,8) {
            memset(used, false, sizeof(used));
            solve(i, j, k);
        }
        string ans = "";
        for(auto elem : memo) {
            if(elem.second < 2) continue;
            if(elem.first.length() < 2) continue;
            if(isbetter(elem.first, ans)) ans = elem.first;
        }
        if(ans == "") cout << 0 << endl;
        else cout << ans << endl;
    }
    return 0;
}

C++: #include <cstdio>
#include <string>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
#define REP(i,x)for(int i=0;i<x;i++)

string res;
int H,W,dx,dy,min_len;
char s[200];
char MAP[11][22];
bool visit[20][20];
vector<string> ss;
void dfs(int x,int y,int k){
  if(visit[y][x]){
    ss.push_back(string(s));
    return;
  }
  s[k]=MAP[y][x];  visit[y][x]=1;
  dfs((x + dx + W) % W, (y + dy + H) % H, k + 1);
  s[k]=0;  visit[y][x]=0;
}
int main() {
  while(scanf("%d%d",&H,&W),H){
    REP(i,H)scanf("%s",MAP[i]);
    ss.clear();
    min_len=1; res="0";
    REP(y,H)REP(x,W){
      for(dx=-1;dx<=1;dx++){
        for(dy=-1;dy<=1;dy++){
          if(dx|dy)dfs(x,y,0);
        }
      }
    }
    string res = "0";
    sort(ss.begin(),ss.end());
    REP(i,ss.size()-1){
      int len = 0;
      if(min(ss[i].size(),ss[i+1].size()) < len)continue;
      REP(k,min(ss[i].size(),ss[i+1].size())){
        if(ss[i][k]==ss[i+1][k])len++;
        else break;
      }
      if(len < res.size())continue;
      if(res.size() == len){
        res = min(res, ss[i].substr(0,len));
      }else{
        res = ss[i].substr(0, len);
      }
    }
    puts(res.c_str());
  }
}

C++: /*
 * GCA : "Computer is artificial subject absolutely,Math is God"
 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <climits>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <cctype>
#include <utility>
#include <ctime>
using namespace std;
#ifdef DEBUG
#define VAR(a,b) __typeof(b) a=(b)
#define debug(...) printf("DEBUG: "),printf(__VA_ARGS__)
#else
#define VAR(a,b) __typeof(b) a=(b)
#define debug(...)
#endif
typedef unsigned int uint;
typedef long long int Int;
typedef unsigned long long int UInt;
#define Set(a,s) memset(a,s,sizeof(a))
#define Pln() printf("\n")
#define For(i,x)for(int i=0;i<x;i++)
#define CON(x,y) x##y
#define M 25
#define PB push_back
#define oo INT_MAX
#define FOR(a,b) for(VAR(a,(b).begin());a!=(b).end();++a)
#define eps 1e-9
#define X first
#define Y second
inline bool xdy(double x,double y){return x>y+eps;}
inline bool xddy(double x,double y){return x>y-eps;}
inline bool xcy(double x,double y){return x<y-eps;}
inline bool xcdy(double x,double y){return x<y+eps;}
const Int mod=1000000007;
int nx,ny;
char mz[M][M];
set<Int> sid;
int dx[8]={0,1,1,1,0,-1,-1,-1};
int dy[8]={1,1,0,-1,-1,-1,0,1};
char store[M*M];
Int ist=0;
int ox,oy;
string ans;
//string has[M][M][9];
//bool vis[M][M][9];
bool vis[M][M];
void dfs(int x,int y,int d,int dep){

	store[dep]=mz[y][x];
	ist=ist*134+mz[y][x];
	int nex=(x+dx[d]+nx)%nx;
	int ney=(y+dy[d]+ny)%ny;
	store[dep+1]=0;
	string ss(store);
//		puts(store);
	if(sid.count(ist)){
		if(ss.length()>ans.length()){
			ans=ss;
		}else if(ss.length()==ans.length()&&ss<ans){
			ans=ss;
		}
	}
	sid.insert(ist);
	if(vis[nex][ney]){
		return;
	}
	vis[nex][ney]=1;
	dfs(nex,ney,d,dep+1);
	vis[nex][ney]=0;

}
void solve(){
	for(int i=0;i<ny;i++){
		for(int j=0;j<nx;j++){
			for(int k=0;k<8;k++){
				ist=0;
				vis[j][i]=1;
				Set(store,0);
				dfs(j,i,k,0);
				vis[j][i]=0;
			}
		}
	}
//	for(int i=0;i<8;i++){
//		ox=1;oy=1;
//		dfs(1,1,i,0);
//	}
	if(ans.length()>=2)
		printf("%s\n",ans.c_str());
	else puts("0");
}
int main() {
	ios_base::sync_with_stdio(0);
	while(~scanf("%d%d",&ny,&nx)&&nx&&ny){
		sid.clear();
		ans="";
		Set(vis,0);
		for(int i=0;i<ny;i++)scanf("%s",mz[i]);
		solve();

	}

















}

C++: #include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

int h,w;
string fie[11];
int dx[8]={1,0,-1,0,1,1,-1,-1};
int dy[8]={0,1,0,-1,1,-1,1,-1};
map<string,int> cnt;
bool used[11][21];
vector<string> index2;

void dfs(int y,int x,int k,string str){
	if(used[y][x])return;
	used[y][x]=true;
	str+=fie[y][x];
	cnt[str]++;
	index2.push_back(str);
	dfs((y+dy[k]+h)%h,(x+dx[k]+w)%w,k,str);
}

int main(void){
	while(1){
		scanf("%d %d",&h,&w);
		if(h+w==0)break;
		cnt.clear();
		index2.clear();
		for(int i=0;i<h;i++){
			cin >> fie[i];
		}
		for(int i=0;i<h;i++){
			for(int j=0;j<w;j++){
				for(int k=0;k<8;k++){
					memset(used,false,sizeof(used));
					dfs(i,j,k,"");
				}
			}
		}
		sort(index2.begin(),index2.end());
		index2.erase(unique(index2.begin(),index2.end()),index2.end());
		string res="0";
		for(int i=0;i<index2.size();i++){
			if(cnt[index2[i]]>=2 && index2[i].size()>=2){
				if(res.size()<index2[i].size() || (res.size()==index2[i].size() && index2[i]<res)){
					res=index2[i];
				}
			}
		}
		cout << res << endl;
	}
	return 0;
}