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++: /*
諤サ逧?庄莉・蠖堤コウ謌?荳牙?扈?x,y,z):
x:逕ィ謗貞コ剰ァ」蜀ウ
y:逕ィ謗貞コ丞刈cdq蛻?イサ隗」蜀ウ
z:逕ィ譬醍憾謨ー扈?ァ」蜀ウ
*/
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <iomanip>
#include <string>
#include <vector>
#include <cstring>
#include <sstream>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <bitset>
#include <climits>
#include <ostream>
#include <ios>
#include <cstdlib>
using namespace std;

#define wh while
#define inf (int)(~0u/2)
#define FOR(i, n) for(int i = 0; i < n; i++)
#define FOR1(i, n) for(int i = 1; i < n; i++)
#define FOR2(i, n) for(int i = 0; i <= n; i++)
#define REP(i,n) for(int i = 1; i <= n; i++)
#define FORI(it,n) for(typeof(n.begin()) it = n.begin(); it != n.end(); it++)
#define sf scanf
#define pf printf
#define frs first
#define sec second
#define psh push_back
#define mkp make_pair
#define PB(x) push_back(x)
#define MP(x, y) make_pair(x, y)
#define clr(abc,z) memset(abc,z,sizeof(abc))
#define lt(v) v << 1
#define rt(v) v << 1 | 1
#define mid ((l + r) >> 1)
#define lson l, mid, v << 1
#define rson mid + 1, r, v << 1 | 1

#define fre freopen("1.txt", "r", stdin);

typedef long long LL;
typedef long double LD;

const int maxnode = 1e6 + 10;
const int sigma_size = 26;

int h, w;
struct Trie {
    map<int, string> mp;
  int ch[maxnode][sigma_size];
  int val[maxnode];
  int len[maxnode];
  bool isOK[maxnode];
  int sz;
  void _clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0]));
  clr(isOK, false); mp.clear();
  }
  int idx(char c) { return c - 'A'; }
  void _insert(const char *s, int v) {
    int u = 0, n = strlen(s);
    for(int i = 0; i < n; i++) {
        len[u] = i;
      int c = idx(s[i]);
      if(!ch[u][c]) {
        memset(ch[sz], 0, sizeof(ch[sz]));
        val[sz] = 0;
        ch[u][c] = sz++;
      }
      u = ch[u][c];
    }
    len[u] = n;
    if(val[u]) isOK[u] = true;
    else{
        val[u] = v; mp[v] = s;
    }
  }
};

Trie tree;
char tmp[12][42];
char tmpB[220];
int dx[] = {-1, 1, 0, 0, 1, 1, -1, -1};
int dy[] = {0, 0, -1, 1, 1, -1, 1, -1};

int ansl, ansv;

void dfs(int cur){
    if(tree.val[cur]){
        if(tree.len[cur] > ansl && tree.isOK[cur]){
            ansl = tree.len[cur];
            ansv = tree.val[cur];
        }
    }
    FOR(i, 26){
        if(tree.ch[cur][i]){
            dfs(tree.ch[cur][i]);
        }
    }
}

int main(){
    int cur;
    fre
    wh(sf("%d%d", &h, &w) != EOF){
        if(!h && !w) break;
        cur = 0; ansl = 0;
        tree._clear();
        FOR(i, h) sf("%s", tmp[i]);
        FOR(i, h) FOR(j, w){
            FOR(k, 8){
                int cnt = 0;
                tmpB[cnt++] = tmp[i][j]; tmpB[cnt] = '\0';
                tree._insert(tmpB, ++cur);
                int ni = i + dx[k], nj = j + dy[k];
                wh(ni < 0) ni += h; wh(nj < 0) nj += w;
                ni = ni % h; nj = nj % w;
                wh(!(ni == i && nj == j)){
                    tmpB[cnt++] = tmp[ni][nj]; tmpB[cnt] = '\0';
                    tree._insert(tmpB, ++cur);
                    ni = ni + dx[k]; nj = nj + dy[k];
                    ni = ni % h; nj = nj % w;
                    wh(ni < 0) ni += h; wh(nj < 0) nj += w;
                }
            }
        }
        dfs(0);
        if(ansl < 2)
            pf("0\n");
        else
            cout << tree.mp[ansv] << endl;
    }
}

C++: #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

const int dx[8] = { 1, 1, 1, 0, -1, -1, -1, 0 };
const int dy[8] = { -1, 0, 1, 1, 1, 0, -1, -1 };
char field[100][100];
bool visit[30][30];
int h, w;

int main() {
  while (scanf("%d %d", &h, &w), h|w) {
    REP(y, h) {
      scanf("%s", field[y]);
    }
    string ans = "0";
    map<string, int> open;
    REP(sy, h) {
      REP(sx, w) {
        REP(dir, 8) {
          MEMSET(visit, false);
          string s;
          int x = sx;
          int y = sy;
          while (!visit[y][x]) {
            visit[y][x] = true;
            s += field[y][x];
            if (s.size() > 1) {
              open[s]++;
              if (open[s] >= 2) {
                if (ans.size() < s.size() ||
                    (ans.size() == s.size() && s < ans)) {
                  ans = s;
                }
              }
            }
            x = (x + dx[dir] + w) % w;
            y = (y + dy[dir] + h) % h;
          }
        }
      }
    }
    cout << ans << endl;
  }
}

C++: #include<bits/stdc++.h>
#define r(i,n) for(int i=0;i<n;i++)
using namespace std;
string s[21];
int dx[]={1,1,1,0,0,-1,-1,-1};
int dy[]={1,0,-1,1,-1,1,0,-1};
int h,w;
vector<string>v;
set<string> se;
void dfs(int d,int y,int x,int p,string t,int p1,int p2){
  if(d&&y==p1&&x==p2)return;
  t+=s[y][x];
  if(d){
    if(!se.count(t))se.insert(t);
    else v.push_back(t);
  }
  x+=dx[p],y+=dy[p];
  if(x<0)x=w-1;
  if(y<0)y=h-1;
  if(x>=w)x=0;
  if(y>=h)y=0;
  dfs(d+1,y,x,p,t,p1,p2);
}
int main(){
  while(cin>>h>>w,h){
    se.clear();
    v.clear();
    r(i,h)cin>>s[i];
    r(i,h)r(j,w)r(k,8)dfs(0,i,j,k,"",i,j);
    sort(v.begin(),v.end());
    int p=0;
    r(i,v.size())p=max(p,(int)v[i].size());
    if(v.size())r(i,v.size()){
      if(v[i].size()==p){
        cout<<v[i]<<endl;
        break;
      }
    }
    else cout<<0<<endl;
  }
}

C++: #include<bits/stdc++.h>
#define rep(i,n)for(int i=0;i<(n);i++)
using namespace std;

char s[10][21];
bool used[10][20];
int main() {
	int h, w;
	while (scanf("%d%d", &h, &w), h) {
		rep(i, h)scanf("%s", s[i]);
		map<string, int>mp;
		rep(i, h)rep(j, w) {
			for (int dx = -1; dx <= 1; dx++) {
				for (int dy = -1; dy <= 1; dy++) {
					if (dx == 0 && dy == 0)continue;
					string t;
					memset(used, 0, sizeof(used));
					int x = i, y = j;
					while (!used[x][y]) {
						t += s[x][y]; used[x][y] = 1; x += dx; y += dy;
						x = (x + h) % h; y = (y + w) % w;
						mp[t]++;
					}
				}
			}
		}
		string ans = "0";
		for (auto p : mp) {
			if (p.second > 1 && ans.size() < p.first.size())ans = p.first;
		}
		cout << ans << endl;
	}
}