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 <map>
using namespace std;

int main(){
    int h,w;
    while(cin>>h>>w,h){
        char D[h][w];
        for(int i=0;i<h;i++){
            for(int j=0;j<w;j++){
                cin>>D[i][j];
            }
        }
        map<string,int> M;
        for(int i=0;i<h;i++){
            for(int j=0;j<w;j++){
                for(int di=-1;di<=1;di++){
                    for(int dj=-1;dj<=1;dj++){
                        if(!di&&!dj) continue;
                        string S;
                        int I=i,J=j;
                        while(true){
                            S.push_back(D[I][J]);
                            M[S]++;
                            I+=di;
                            if(I<0)I=h-1;
                            if(I>=h)I=0;
                            J+=dj;
                            if(J<0)J=w-1;
                            if(J>=w)J=0;
                            if(I==i&&J==j) break;
                        }
                    }
                }
            }
        }
        string ans;
        for(auto p:M){
            // cout<<p.first<<' '<<p.second<<endl;
            if(p.second<=1) continue;
            else{
                string S = p.first;
                if(ans.size()<S.size()){
                    ans=S;
                }else if(ans.size()==S.size()){
                    ans=min(ans,S);
                }
            }
        }
        if(ans.size()==1)cout<<0<<endl;
        else cout<<ans<<endl;
    }
    return 0;
}

C++: //Name: The Sorcerer's Donut
//Level:
//Category:
//Note:

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <string>
#include <array>
#include <map>

using namespace std;

#define TIMES(i,n) for(int i = 0; i < (n); ++i)

const int DR[] = {
    0, -1, -1, -1, 0, 1, 1, 1
};
const int DC[] = {
    1, 1, 0, -1, -1, -1, 0, 1
};

array<array<bool,20>,10> visited;

string search(int r, int c, int dir, const vector<string> &s, map<string,int> &memo) {
    const int H = s.size();
    const int W = s[0].size();
    string res;
    TIMES(i, H) {
        TIMES(j, W) {
            visited[i][j] = false;
        }
    }
    while(!visited[r][c]) {
        visited[r][c] = true;
        res += s[r][c];
        if(res.size() > 1) memo[res]++;
        r = (r+DR[dir]+H) % H;
        c = (c+DC[dir]+W) % W;
    }
    return res;
}

bool solve() {
    int H, W;
    cin >> H >> W;
    if(!H && !W) return false;

    vector<string> s(H);
    TIMES(i, H) {
        cin >> s[i];
    }
    map<string,int> memo;
    for(int r = 0; r < H; ++r) {
        for(int c = 0; c < W; ++c) {
            for(int dir = 0; dir < 8; ++dir) {
                search(r, c, dir, s, memo);
            }
        }
    }
    string ans = "";
    for(const auto &p : memo) {
        if(p.second < 2) continue;
        if(p.first.size() > ans.size() || (p.first.size() == ans.size() && p.first < ans)) {
            ans = p.first;
        }
    }
    if(ans == "") ans = "0";
    cout << ans << endl;
    return true;
}

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

    while(solve()) ;
    return 0;
}

C++: #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];
string MAP[11];
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(cin>>H>>W,H){
    REP(i,H)cin>>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;
      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);
      }
    }
    cout<<res<<endl;
  }
}

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 (cx < 0)cx += H; if (cx >= H)cx -= H;
						if (cy < 0)cy += W; if (cy >= W)cy -= W;
						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;
}