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 <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;
}

C++: #include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

int h, w;
int dy[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dx[8] = {0, 1, 1, 1, 0, -1, -1, -1};
bool vis[10][20];
char dat[10][20];
vector<string> str;

void calc(int y, int x, int d){
  fill(vis[0], vis[10], false);
  string path;
  int ny = y;
  int nx = x;
  while(!vis[ny][nx]){
    vis[ny][nx] = true;
    path.push_back(dat[ny][nx]);
    ny = (ny + dy[d] + h) % h;
    nx = (nx + dx[d] + w) % w;
  }
  if(path.size() > 1) str.push_back(path);
}

int comp(string& a, string& b){
  int size = min(a.size(), b.size());
  for(int i=0;i<size;i++) if(a[i] != b[i]) return i;
  return size;
}

main(){
  while(cin >> h >> w && (h|w)){
    str.clear();
    for(int i=0;i<h;i++) for(int j=0;j<w;j++) cin >> dat[i][j];
    for(int i=0;i<h;i++) for(int j=0;j<w;j++) for(int k=0;k<8;k++) calc(i, j, k);
    sort(str.begin(), str.end());
    int ans = 0, id;
    for(int i=1;i<str.size();i++){
      int tmp = comp(str[i-1], str[i]);
      if(ans < tmp){
        ans = tmp;
        id = i;
      }
    }
    if(ans > 1) cout << str[id].substr(0, ans) << endl;
    else cout << 0 << endl;
  }
}

C++: #include <iostream>
#include <string>
#include <stdio.h>
#include <set>

using namespace std;

#define dirmax 8

int l[2];
int dir[8][2] = { {0,1}, {1,0}, {-1,0}, {0,-1}, {1,1}, {-1,1}, {1,-1}, {-1,-1} };
char ch[10][20];
int pos[2];
string ans;

void search(set<string> *v){

	for(int i = 0; i < dirmax; i++) {
		string str;
		int cpos[] = { pos[0], pos[1] };

		str += ch[pos[0]][pos[1]];

		while( 1 ) {
			for(int j = 0; j < 2; j++) {
				cpos[j] += dir[i][j];
				if( cpos[j] < 0 ) cpos[j] = l[j] - 1;
				if( cpos[j] >= l[j] ) cpos[j] = 0;
			}
			if( cpos[0] == pos[0] && cpos[1] == pos[1] ) break;

			str += ch[cpos[0]][cpos[1]];
			
			if( v->find(str) != v->end() ) {
 				if( ( str.length() > ans.length() ) || ( str.length() == ans.length() && str < ans ) ) {
					ans = str;
				}
			} else 
				v->insert(str);
		}
	}
}

int main(void){
	while(1){
		cin >> l[0] >> l[1];
		if( l[0] == 0 && l[1] == 0 ) break;

		ans = "";
		set< string > strs;

		for(int i = 0; i < l[0]; i++)
			cin >> ch[i];
		
		for(pos[0] = 0; pos[0] < l[0]; pos[0]++)
			for(pos[1] = 0; pos[1] < l[1]; pos[1]++)
				search( &strs );

		if(ans == "") 
			cout << 0 << endl;
		else 
			cout << ans << endl;
	}
	return 0;
}

C++: #include<iostream>
#include<vector>
#include<cstring>
using namespace std;

int lcm(int a, int b){
  return a/__gcd(a, b) * b;
}

int main(int argc, char *argv[]){
  int w, h;
  while(cin >> h >> w, h){
    string torus[30];
    string s[2222];
    for (int i = 0; i < h; i++) {
      cin >> torus[i];
    }
    int l = lcm(w, h);
    int num = 0;
    for (int i = 0; i < h; i++) {
      for (int j = 0; j < w; j++) {
        for (int k = 0; k < h; k++) {
          s[num].push_back(torus[(h + i + k)%h][j]);
          s[num + 1].push_back(torus[(h + i - k)%h][j]);
        }
        
        for (int k = 0; k < w; k++) {
          s[num + 2].push_back(torus[i][(w + j + k)%w]);
          s[num + 3].push_back(torus[i][(w + j - k)%w]);
        }
        
        for (int k = 0; k < l; k++) {
          s[num + 4].push_back(torus[(l*h + i + k)%h][(l*w + j + k)%w]);
          s[num + 5].push_back(torus[(l*h + i - k)%h][(l*w + j + k)%w]);
          s[num + 6].push_back(torus[(l*h + i + k)%h][(l*w + j - k)%w]);
          s[num + 7].push_back(torus[(l*h + i - k)%h][(l*w + j - k)%w]);
        }
        num += 8;
      }
    }
    sort(s, s + 8*w*h);
    string ans = s[0];
    for (int i = 0; i < 8*w*h - 1; i++) {
      int length = 0;
      for (int j = 0;
           j < min(s[i].length(), s[i + 1].length()) - 1; j++) {
        if(s[i][length] == s[i + 1][length])length++;
        else break;
      }
      if(length > ans.length())ans = s[i].substr(0,length);
    }
    if(ans.length() > 1)std::cout << ans << std::endl;
    else std::cout << 0 << std::endl;
  }
  return 0;
}

C++: #include<iostream>
#include<vector>
#include<string>
#include<algorithm>	
#include<map>
#include<set>
#include<utility>
#include<cmath>
#include<cstring>
#include<queue>
#include<cstdio>
#include<sstream>
#include<iomanip>
#define loop(i,a,b) for(int i=a;i<b;i++) 
#define rep(i,a) loop(i,0,a)
#define pb push_back
#define mp make_pair
#define all(in) in.begin(),in.end()
#define shosu(x) fixed<<setprecision(x)
using namespace std;
//kaewasuretyuui
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<pii> vp;
typedef vector<vp> vvp;
typedef pair<int,pii> pip;
typedef vector<pip>vip	;
const double PI=acos(-1);
const double EPS=1e-8;
const int inf=1e8;
int dx[]={1,1,1,0,0,-1,-1,-1};
int dy[]={1,0,-1,1,-1,1,0,-1};
int main(){
	int n,m;
	while(cin>>n>>m,n+m){
		vector<string>in(n);
		rep(i,n)cin>>in[i];
		set<string>out1,out2;
		string out="";
		rep(i,n)rep(j,m)rep(k,8){
			int sx=i,sy=j;
			string s="";
			s+=in[sx][sy];
			int nx=(sx+dx[k]+n)%n,ny=(sy+dy[k]+m)%m;
			while(nx!=sx||ny!=sy){
				s+=in[nx][ny];
				nx=(nx+dx[k]+n)%n,ny=(ny+dy[k]+m)%m;
				if(out1.find(s)!=out1.end()){
					if(out.size()==s.size()){
						if(s<out)out=s;
					}else if(out.size()<s.size()){
						out=s;
					}
				}else out1.insert(s);
			}
		}
		if(out=="")cout<<0<<endl;
		else cout<<out<<endl;
	}
}