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<string>
#include<vector>
#include<algorithm>
using namespace std;

int lcm(int a,int b){	//a,b < 20だしいいよね
		if (a < b){
			swap(a,b);
		}
		int times = a * b;
		vector<int> num;
		int gcd,lcm;
		while(1){
			int n;
			n = a % b;
			if(n == 0){	break;}
			a = b;
			b = n;
		}
		gcd = b;
		lcm = times / gcd;
	return lcm;
}

int main(){
	int h,w;
	while(1){
		cin >> h >> w ;
		if(h == 0 && w == 0){	break;}
		char donut[10][20];
		for(int i=0;i<10;i++){
			for(int j=0;j<20;j++){
				donut[i][j] = 0;
			}
		}
		string code[1600];
		bool much[1600];
		for(int i = 0; i < 1600; i++){
			code[i] = "";
			much[i] = true;
		}	//初期化…

		int l = lcm(w,h);	//ななめの最大数
		int a = 0;	//strの数を数えます

		for(int i = 0; i < h; i++){
			for(int j =0; j < w; j++){
				cin >> donut[i][j];
			}
		}	//input

		for(int y = 0; y < h; y++){
			for(int x = 0; x < w; x++){
				for(int i = 0; i < h; i++){	//縦列
					code[a].append(1,donut[(y + i)%h][x]);
					code[a+1].append(1,donut[h-(y + i)%h-1][x]);
				}
				a += 2;
				for(int j = 0; j < w; j++){	//横列
					code[a].append(1,donut[y][(x + j)%w]);
					code[a+1].append(1,donut[y][w-(x+j)%w-1]);//absつけなくても0になりません！
				}
				a += 2;
				for(int k = 0; k < l; k++){	//ななめ
					code[a].append(1,donut[(y + k)%h][(x + k)%w]);
					code[a+1].append(1,donut[(y + k)%h][(l + x - k)%w]);
					code[a+2].append(1,donut[(l + y - k)%h][(x + k)%w]);
					code[a+3].append(1,donut[(l + y - k)%h][(l + x - k)%w]);
				}
				a += 4;
			}
		}
		string mag = "";
		//a:strの数-1

		sort(code,code+a);//nとn+1を比べます

		for(int i = 0; i < a-1; i++){
			if(code[i][0] != code[i+1][0]){
				much[i+1] = false;
			}
		}
		for(int i = 1; i < l; i++){	//2文字目から
			for(int j = a-1; j > 0; j--){	//逆順
				if(much[j] == true && code[j].length() >= i+1 && code[j-1].length() >= i+1){//=を忘れていました
					//jのi+1文字目とj-1のi+1文字目を比べるよ
					if(code[j][i] != code[j-1][i]){
						much[j] = false;
					}else{
						mag = code[j];
						mag.resize(i+1);
					}
				}
			}
		}
		if(mag == ""){
			cout << "0" << endl;
		}else{
			cout << mag << endl;
		}
	}
	return 0;
}

C++: #include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
vector<string>vec;
char c[20][20]; int H, W; bool used[20][20];
int dx[8] = { 1,1,1,0,-1,-1,-1,0 };
int dy[8] = { -1,0,1,1,1,0,-1,0 };
int main() {
	while (true) {
		cin >> H >> W; vec.clear(); if (H == 0)break;
		for (int i = 0; i < H; i++) {
			for (int j = 0; j < W; j++)cin >> c[i][j];
		}
		for (int i = 0; i < H; i++) {
			for (int j = 0; j < W; j++) {
				for (int k = 0; k < 8; k++) {
					for (int l = 0; l < 400; l++)used[i / 20][i % 20] = 0;
					int cx = i, cy = j; string S; S += c[cx][cy]; used[cx][cy] = 1;
					while (true) {
						cx += dx[k]; cy += dy[k];
						if (used[cx][cy] == 1)break;
						used[cx][cy] = 1; S += c[cx][cy]; vec.push_back(S);
					}
				}
			}
		}
		sort(vec.begin(), vec.end()); string T = "0";
		for (int i = 1; i < vec.size(); i++) {
			if (vec[i - 1] == vec[i]) {
				if (vec[i].size()>T.size())T = vec[i];
				else if (vec[i].size() == T.size())T = min(T, vec[i]);
			}
		}
		cout << T << endl;
	}
	return 0;
}

C++: #include <iostream>
#include <string>
#include <set>
#include <cstring>
using namespace std;
 
#define REP(i,x,n) for(int i = x; i < (int)(n); i++)
#define rep(i,n) REP(i,0,n)
 
static const int dx[] = {-1,-1,-1,0,0,1,1,1};
static const int dy[] = {-1,0,1,-1,1,-1,0,1};
 
int h,w;
char D[10][20];
set<string> spell;
 
string solve(){
  spell.clear();
  string ret = "0";
   
  rep(i,h) rep(j,w){
    int sx = i;
    int sy = j;
    rep(k,8){
      int x = i;
      int y = j;
      string tmp;
      tmp += D[x][y];
       
      while(true){
        x = (x + h + dx[k]) % h;
        y = (y + w + dy[k]) % w;
        if(x == sx && y == sy) break;
         
        tmp += D[x][y];
        if(spell.find(tmp) != spell.end()){
          if(ret.size() == tmp.size()) ret = (ret < tmp) ? ret : tmp;
          else ret = (ret.size() < tmp.size()) ? tmp : ret;
        }
        else spell.insert(tmp);
      }
    } 
  }
   
  return ret;
}
 
int main(){
  while(cin >> h >> w && (h | w)){
    rep(i,h) rep(j,w){
      cin >> D[i][j];
    }
    cout << solve() << endl;
  }
  return 0;
}

C++: /*
 * GCA : "Computer is artificial subject absolutely,Math is God"
 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <climits>
#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 ox,oy;
string ans;
Int isid;
bool vis[M][M];
void dfs(int x,int y,int d,int dep){

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

}
void solve(){
	Set(vis,0);
	for(int i=0;i<ny;i++){
		for(int j=0;j<nx;j++){
			for(int k=0;k<8;k++){
				isid=0;
				vis[j][i]=1;
				dfs(j,i,k,0);
				vis[j][i]=0;
			}
		}
	}
	if(ans.size())
		puts(ans.c_str());
	else puts("0");
}
int main() {
	ios_base::sync_with_stdio(0);
	while(~scanf("%d%d",&ny,&nx)&&ny&&nx){
		sid.clear();
		ans="";
		for(int i=0;i<ny;i++)scanf("%s",mz[i]);
		solve();

	}

















}