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

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]++;
	index.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();
		index.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(index.begin(),index.end());
		index.erase(unique(index.begin(),index.end()),index.end());
		string res="0";
		for(int i=0;i<index.size();i++){
			if(cnt[index[i]]>=2 && index[i].size()>=2){
				if(res.size()<index[i].size() || (res.size()==index[i].size() && index[i]<res)){
					res=index[i];
				}
			}
		}
		cout << res << endl;
	}
	return 0;
}

C++: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"

using namespace std;

constexpr long long int MOD = 1000000007;
//constexpr int MOD = 1000000007;
//constexpr int MOD = 998244353;
//constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-12;

//int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;

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

struct Node {
	int x, y, d;
	Node(int a, int b, int c) {
		x = a, y = b, d = c;
	}
	bool operator<(const Node&n)const {
		return make_pair(x, y) < make_pair(n.x, n.y);
	}
};

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

	while (cin >> H >> W, H) {
		vector<string>s(H);
		for (auto &i : s)cin >> i;
		map<string, set<Node>>st;
		for (int i = 0; i < H; i++) {
			for (int j = 0; j < W; j++) {
				for (int k = 0; k < 8; k++) {
					string box;
					vector<vector<int>>visited(H, vector<int>(W));
					int ny = i, nx = j;
					while (!visited[ny][nx]) {
						visited[ny][nx] = 1;
						box.push_back(s[ny][nx]);
						ny += dy[k];
						nx += dx[k];
						if (ny < 0)ny += H;
						if (ny >= H)ny -= H;
						if (nx < 0)nx += W;
						if (nx >= W)nx -= W;
						st[box].insert(Node(i, j, k));
					}
				}
			}
		}
		string ans = "";
		for (auto i : st) {
			if (i.second.size() == 1)continue;
			if (ans.size() < i.first.size())ans = i.first;
		}
		if (ans.size() <= 1) {
			cout << 0 << endl;
		}
		else cout << ans << endl;
	}
}

C++: #include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <complex>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <iomanip>
#include <assert.h>
#include <array>
#include <cstdio>
#include <cstring>
#include <random>
#include <functional>
#include <numeric>
#include <bitset>
 
using namespace std;
 
struct before_main{before_main(){cin.tie(0); ios::sync_with_stdio(false);}} before_main;
 
#define REP(i,a,b) for(int i=a;i<(int)b;i++)
#define rep(i,n) REP(i,0,n)
#define all(c) (c).begin(), (c).end()
#define zero(a) memset(a, 0, sizeof a)
#define minus(a) memset(a, -1, sizeof a)
template<class T1, class T2> inline bool minimize(T1 &a, T2 b) { return b < a && (a = b, 1); }
template<class T1, class T2> inline bool maximize(T1 &a, T2 b) { return a < b && (a = b, 1); }
 
typedef long long ll;
int const inf = 1<<29;
 
int H, W;
vector<string> F;
 
int dx[8] = {-1,0,1,0,-1,1,1,-1};
int dy[8] = {0,-1,0,1,-1,-1,1,1};
 
unordered_map<string, int> mp;
 
void go(int y, int x, int dir, int sy, int sx) {
  string s;
  while(1) {
    s += F[y][x];
    int ny = y + dy[dir];
    int nx = x + dx[dir];
    if(ny >= H) { ny = 0; }
    if(ny < 0) { ny = H-1; }
    if(nx >= W) { nx = 0; }
    if(nx < 0) { nx = W-1; }
    if(ny == sy && nx == sx) { break; }
    y = ny, x = nx;
    mp[s]++;
  }
  mp[s] ++;
}
 
int main() {
 
  for(; cin >> H >> W && (H | W);) {
 
    F.clear(); rep(i, H) F.resize(H);
    vector<string> v;
    rep(i, H) cin >> F[i];
    mp.clear();
    rep(i, H) rep(j, W) {
      rep(k, 8) {
        go(i, j, k, i, j);
      }
    }
 
    vector<string> u;
    for(auto && e: mp) {
      if(e.first.size() > 1 && e.second > 1) {
        u.push_back(e.first);
      }
    }
 
    if(u.empty()) {
      cout << 0 << endl;
    }
    else {
      sort(all(u), [&](string const& s, string const& t){ int n=s.size(),m=t.size(); return n != m ? n > m : s < t; });
      cout << u[0] << 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;
}