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
//------------------------------------------
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <climits>
#include <queue>

using namespace std;

//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef long long LL;

//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SZ(a) int((a).size())
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())

//repetition
//------------------------------------------
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

//constant
//--------------------------------------------
const double EPS = 1e-10;
const double PI  = acos(-1.0);

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

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

  int H, W;
  while(cin>>H>>W,H){
	vector<string> lns(H);
	REP(i,H) cin>>lns[i];

	map<string, int> mpsi;
	REP(y,H) REP(x,W){
	  REP(i,8){
		int tx = x, ty = y;
		string s = "";
		vector< vector<bool> > used(H, vector<bool>(W, false));
		while(true){
		  if(used[ty][tx]) break;
		  used[ty][tx] = true;
		  s.append(1, lns[ty][tx]);
		  tx = (tx + dx[i] + W) % W;
		  ty = (ty + dy[i] + H) % H;
		  mpsi[s]++;
		}
	  }
	}
	int len = 0;
	string s = "";
	for(auto it=mpsi.begin();it!=mpsi.end();++it){
	  if(it->second < 2) continue;
	  if(len < SZ(it->first) || (len == SZ(it->first) && it->first < s))
		len = SZ(it->first), s = it->first;
	}

	if(len < 2) cout << 0 << endl;
	else cout << s << endl;
  }
  
  return 0;
}

C++: #include <cstdlib>
#include <iostream>
#include <set>
#include <string>
#include <vector>
using namespace std;

int h, w;
const int dx[8] = {0, 1, 1, 1, 0, -1, -1, -1};
const int dy[8] = {1, 1, 0, -1, -1, -1, 0, 1};
vector<string> donut;
bool visited[10][20];

inline unsigned long long hash(const string& s) {
	const unsigned long long base = 1000000007;
	long long res = 0;
	for(int i = 0; i < s.size(); ++i) {
		res *= base;
		res += s[i];
	}

	return res;
}

inline string spell(int x, int y, int d) {
	if(visited[y][x])
		return "";

	visited[y][x] = true;
	string res = donut[y][x] + spell((x + dx[d] + w) % w, (y + dy[d] + h) % h, d);
	visited[y][x] = false;
	return res;
}

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

	const string init(2, 'z' + 1);

	while(cin >> h >> w, h) {
		donut.clear();
		donut.resize(h);
		for(int i = 0; i < h; ++i)
			cin >> donut[i];

		string ans = init;
		set<unsigned long long> s;
		for(int i = 0; i < h; ++i) {
			for(int j = 0; j < w; ++j) {
				for(int d = 0; d < 8; ++d) {
					const string str = spell(j, i, d);
					for(int i = ans.size(); i <= str.size(); ++i) {
						const string tmp = str.substr(0, i);
						const unsigned long long h = hash(tmp);
						if(s.find(h) == s.end())
							s.insert(h);

						else if(ans.size() < tmp.size() || (ans.size() == tmp.size() && tmp < ans))
							ans = tmp;
					}
				}
			}
		}

		cout << (ans != init ? ans : "0") << endl;
	}

	return EXIT_SUCCESS;
}

C++: #include <vector>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <utility>
#include <functional>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <climits>
#include <cassert>
using namespace std;
inline int toInt(string s) {int v; istringstream sin(s);sin>>v;return v;}
template<class T> inline string toString(T x) {ostringstream sout;sout<<x;return sout.str();}
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<string> vs;
typedef pair<int, int> pii;
typedef long long ll;
#define ALL(a) (a).begin(),(a).end()
#define RALL(a) (a).rbegin(),(a).rend()
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
const double EPS = 1e-7;
const double PI  = acos(-1.0);

int dx[]={-1,0,1,1,1,0,-1,-1};
int dy[]={-1,-1,-1,0,1,1,1,0};
int main(){
	int h,w;
	while(cin>>h>>w,h|w){
		vs f(h);
		REP(i,h){
			cin>>f[i];
		}

		map<string,int> m;
		string ans;
		REP(i,h){
			REP(j,w){
				REP(d,8){
					vvi used(h,vi(w));
					string s;
					int y=i,x=j;
					while(1){
						if(!used[y][x]){
							s+=f[y][x];
							used[y][x]=1;
							y+=dy[d];
							x+=dx[d];
							if(y<0)y=h-1;
							if(x<0)x=w-1;
							if(y>=h)y=0;
							if(x>=w)x=0;
						}else{
							break;
						}
						if(s.size()>1){
							if(!EXIST(m,s)){
								m[s]=0;
							}
							m[s]++;
							if(m[s]>1&&(s.size()>ans.size()||(s.size()==ans.size()&&s<ans))){
								ans=s;
							}
						}
					}
				}
			}
		}

		cout<<(ans==""?"0":ans)<<endl;
	}
}