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 <algorithm>
#include <set>
#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 <algorithm>
#include <string>
#include <map>
#include <vector>
using namespace std;


struct Str2 {
  string s;
  Str2() {}
  Str2(string s) : s(s) {}
  bool operator < (const Str2 &str) const {
    if(s.size() != str.s.size()) return s.size() > str.s.size();
    return s < str.s;
  }
};

const int MAX_H = 20;
const int MAX_W = MAX_H;
int H, W;
char G[MAX_H][MAX_W];
map<string, int> M;
vector<Str2> V;


string solve() {
  M.clear();
  V.clear();
  for(int i = 0; i < H; ++i) {
    for(int j = 0; j < W; ++j) {
      for(int dx = -1; dx <= 1; ++dx) {
	for(int dy = -1; dy <= 1; ++dy) {
	  if(dx == 0 && dy == 0) continue;
	  int x = j;
	  int y = i;
	  string s = "";
	  do {
	    s += G[y][x];
	    if(s.size() >= 2 && ++M[s] == 2) {
	      V.push_back(Str2(s));
	    }
	    int nx = (x+dx+W)%W;
	    int ny = (y+dy+H)%H;
	    x = nx;
	    y = ny;
	  } while(!(x == j && y == i));
	}
      }
    }
  }
  if(V.size() == 0) return "0";
  sort(V.begin(), V.end());
  return V[0].s;
}

int main() {
  while(cin >> H >> W && (H | W)) {
    for(int i = 0; i < H; ++i) {
      for(int j = 0; j < W; ++j) {
	cin >> G[i][j];
      }
    }
    cout << solve() << endl;
  }
  return 0;
}

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

int main() {
  for (int h, w; cin >> h >> w, h;) {
    vector<string> s(h);
    rep(i, h) cin >> s[i];
    multiset<string> st;
    auto f = [&](int i, int j) { return s[i % h][j % w]; };
    auto g = [](string t) {
      int n = t.length();
      rep(i, n / 2) {
        if (t[i] != t[n - 1 - i]) return false;
      }
      return true;
    };
    auto calc = [&](string t) {
      rep(i, t.length() - 1) {
        auto tmp = t.substr(0, i + 2);
        st.insert(tmp);
      }
    };
    string t;
    P cur, goal;
    rep(i, h) rep(j, w) {
      goal = {i, j};

      t = "";
      rep(k, h) t += f(i + k, j);
      calc(t);
      reverse(all(t));
      calc(t);

      t = "";
      rep(k, w) t += f(i, j + k);
      calc(t);
      reverse(all(t));
      calc(t);

      t = "";
      cur = {i, j};
      while (true) {
        t += f(cur.first, cur.second);
        cur = {(cur.first + 1) % h, (cur.second + 1) % w};
        if (cur == goal) break;
      }
      calc(t);
      reverse(all(t));
      calc(t);

      t = "";
      cur = {i, j};
      while (true) {
        t += f(cur.first, cur.second);
        cur = {(cur.first + 1) % h, (cur.second - 1 + w) % w};
        if (cur == goal) break;
      }
      calc(t);
      reverse(all(t));
      calc(t);
    }
    int m = 0;
    for (auto x : st) {
      if (st.count(x) >= 2) m = max(m, (int)x.length());
    }
    bool ok = false;
    for (auto x : st) {
      // cerr << x << ' ' << st.count(x) << endl;
      if (x.length() != m || st.count(x) < 2) continue;
      cout << x << endl;
      ok = true;
      break;
    }
    if (!ok) cout << 0 << endl;
  }
}

C++: #include <algorithm>
#include <cmath>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
#include <cassert>
#include <functional>

using namespace std;

#define LOG(...) printf(__VA_ARGS__)
//#define LOG(...)
#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);++i)
#define REP(i,n) for(int i=0;i<(int)(n);++i)
#define ALL(a) (a).begin(),(a).end()
#define RALL(a) (a).rbegin(),(a).rend()
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
#define RSORT(c) sort((c).rbegin(),(c).rend())
#define CLR(a) memset((a), 0 ,sizeof(a))

typedef long long ll;
typedef unsigned long long ull;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<vb> vvb;
typedef vector<vi> vvi;
typedef vector<vll> vvll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

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


int main() {
	int n, m;
	while (cin >> n >> m, n){
		int ma = 2;
		vector<string> code(n);
		vector<string> spell;
		set<string> ss;
		REP(i, n){
			cin >> code[i];
		}
		REP(i, n){
			REP(j, m){
				REP(k, 8){
					string s = "";
					int y=i;
					int x=j;
					while (1){
						s += code[y][x];
						if (s.length() >= ma){
							if (ss.find(s) == ss.end()){
								ss.insert(s);
							}else{
								if (ma < s.length()){
									ma = s.length();
									spell.clear();
								}
								spell.push_back(s);
								}
						}
						y += dy8[k]+n;
						y%=n;
						x +=dx8[k]+m;
						x%=m;
						if (y==i&&x==j)break;
					}
				}
			}
		}
		
		
		if (spell.empty())
			cout << "0"<<endl;
		else{
			SORT(spell);
			cout << spell[0] << endl;
		}
	}
}