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 <vector>
#include <algorithm>
#include <cstring>
#include <unordered_set>

using namespace std;
char field[1001][1001];
bool used[1001][1001];

int main(){
  int H,W;
  while(cin>>H>>W&&(H|W)){
    for(int i=0;i<H;i++)
      for(int j=0;j<W;j++)
	cin>>field[i][j];
    vector<string> vs;
    for(int dy=-1;dy<=1;dy++){
      for(int dx=-1;dx<=1;dx++){
	if(dy==0&&dx==0)continue;
	memset(used,0,sizeof(used));
	for(int i=0;i<H;i++){
	  for(int j=0;j<W;j++){
	    if(!(i==0||j==0||i==H-1||j==W-1))continue;
	    int cx=j;
	    int cy=i;
	    string s;
	    if(used[cy][cx])continue;
	    while(1){
	      used[cy][cx]=true;
	      s+=field[cy][cx];
	      cy+=dy;cx+=dx;
	      cy=(cy+H)%H;
	      cx=(cx+W)%W;
	      if(used[cy][cx])break;
	    }
	    vs.push_back(s);
	    //cout<<s<<endl;
	  }
	}
      }
    }
    unordered_set<string> us;
    string cand;
    for(int i=0;i<(int)vs.size();i++){
      for(int j=0;j<(int)vs[i].size();j++){
	for(int k=1;k<=(int)vs[i].size();k++){
	  string s;
	  for(int l=0;l<k;l++){
	    s+=vs[i][(j+l)%vs[i].size()];
	  }
	  if(us.count(s)==1){
	    if(cand==""||cand.size()<s.size())
	      cand=s;
	    else if(cand.size()==s.size()&&cand>s)
	      cand=s;
	  }
	  else if(us.count(s)==0)
	    us.insert(s);
	}
      }
    }
    if(cand.size()>1)cout<<cand<<endl;
    else cout<<0<<endl;
  }

  return 0;
}

C++: #include <bits/stdc++.h>
using namespace std;
#define SZ(x) (int)(x.size())
#define REP(i, n) for(int i=0;i<(n);++i)
#define FOR(i, a, b) for(int i=(a);i<(b);++i)
#define RREP(i, n) for(int i=(int)(n)-1;i>=0;--i)
#define RFOR(i, a, b) for(int i=(int)(b)-1;i>=(a);--i)
#define ALL(a) a.begin(),a.end()
#define DUMP(x) cerr<<#x<<" = "<<(x)<<endl
#define DEBUG(x) cerr<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<< endl;
using ll = long long;
using vi = vector<int>;
using vvi = vector<vi>;
using vll = vector<ll>;
using vvll = vector<vll>;
using P = pair<int, int>;
const double eps = 1e-8;
const ll MOD = 1000000007;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;
template <typename T1, typename T2>
bool chmax(T1 &a, const T2 &b) {
    if (a < b) { a = b; return true; }
    return false;
}
template <typename T1, typename T2>
bool chmin(T1 &a, const T2 &b) {
    if (a > b) { a = b; return true; }
    return false;
}
template<typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
    os << "[";
    REP(i, SZ(v)) {
        if (i) os << ", ";
        os << v[i];
    }
    return os << "]";
}
template<typename T1, typename T2>
ostream &operator<<(ostream &os, const map<T1, T2> &mp) {
    os << "{";
    int a = 0;
    for (auto &tp : mp) {
        if (a) os << ", "; a = 1;
        os << tp;
    }
    return os << "}";
}
template<typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
    os << p.first << ":" << p.second;
    return os;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);

    const int di[] = {0, 1, 0, -1, 1, 1, -1, -1};
    const int dj[] = {1, 0, -1, 0, 1, -1, 1, -1};

    for (;;) {
        int H, W; cin >> H >> W;
        if (H == 0) break;
        vector<string> S(H);
        REP(i, H) cin >> S[i];
        map<string,int> mp;

        REP(si, H) REP(sj, W) {
            REP(k, 8) {
                string s;
                int i = si, j = sj;
                do {
                    s += S[i][j];
                    mp[s] += 1;
                    (i += H + di[k]) %= H;
                    (j += W + dj[k]) %= W;
                } while (i != si or j != sj);
            }
        }
        int maxlen = 0;
        for (auto &tp : mp) {
            if (tp.second > 1) {
                chmax(maxlen, tp.first.size());
            }
        }
        if (maxlen == 1) {
            cout << 0 << endl;
            continue;
        }

        string ans;
        for (auto &tp : mp) {
            if (tp.second > 1 and tp.first.size() == maxlen) {
                ans = tp.first;
                break;
            }
        }
        cout << ans << endl;

    }

    return 0;

}

C++: #include <vector>
#include <iostream>
#include <utility>
#include <algorithm>
#include <string>
#include <deque>
#include <tuple>
#include <queue>
#include <functional>
#include <cmath>
#include <iomanip>
#include <map>
//cin.sync_with_stdio(false);
//streambuf
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;

constexpr int gcd(int a, int b){
	return b == 0 ? a : gcd(b, a%b);
}
int main() {
	int h, w;
	while (cin >> h >> w, h) {
		vector<string> map(h);
		for (auto &a : map)cin >> a;
		int dx[] = { 0,0,1,1,1,-1,-1,-1 };
		int dy[] = { 1,-1,0,-1,1,0,1,-1 };
		vector<tuple<string, int, int, int>> buf;
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				for (int d = 0; d < 8; d++) {
					buf.push_back(make_tuple((string)"" + map[i][j], j, i, d));
				}
			}
		}
		int l = 0;
		for (; l < h*w / gcd(h, w); l++) {
			sort(buf.begin(), buf.end());
			vector<tuple<string, int, int, int>> buf2;
			for (int i = 1; i < buf.size(); i++) {
				if (get<0>(buf[i - 1]).size() < l)continue;
				if (get<0>(buf[i - 1]) == get<0>(buf[i]))buf2.push_back(buf[i - 1]);
				for (; i<buf.size()&&get<0>(buf[i - 1]) == get<0>(buf[i]); i++)buf2.push_back(buf[i]);
			}
			if (buf2.empty())break;
			buf = move(buf2);
			for (auto &a : buf) {
				string str;
				int x, y, d;
				tie(str, x, y, d) = a;
				int x1 = ((x + dx[d]*l) % w + w) % w;
				int y1 = ((y + dy[d]*l) % h + h) % h;
				if (x1 == x && y1 == y)continue;
				str += map[y1][x1];
				a = make_tuple(str, x, y, d);
			}
		}
		if (l < 2)cout << 0 << endl;
		else {
			string str = get<0>(buf[0]);
			cout << str.substr(0, l-1) << endl;
		}
	}
	return 0;
}