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 <bits/stdc++.h>
using namespace std;
using ll=long long;
using vb=vector<bool>;
using vvb=vector<vb>;
using vd=vector<double>;
using vvd=vector<vd>;
using vi=vector<int>;
using vvi=vector<vi>;
using vl=vector<ll>;
using vvl=vector<vl>;
using pll=pair<ll,ll>;
using tll=tuple<ll,ll>;
using tlll=tuple<ll,ll,ll>;
using vs=vector<string>;
#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define rep(i,n) range(i,0,n)
#define rrep(i,n) for(ll i=(n)-1;i>=0;i--)
#define range(i,a,n) for(ll i=(a);i<(n);i++)
#define LINF ((ll)1ll<<60)
#define INF ((int)1<<30)
#define EPS (1e-9)
#define MOD (1000000007ll)
#define fcout(a) cout<<setprecision(a)<<fixed
#define fs first
#define sc second
#define PI (3.1415926535897932384)

int dx[]={1,0,-1,0,1,-1,-1,1},dy[]={0,1,0,-1,1,1,-1,-1};
template<class T>bool chmax(T&a,T b){if(a<b){a=b; return true;}return false;}
template<class T>bool chmin(T&a,T b){if(a>b){a=b; return true;}return false;}
template<class S>S sum(vector<S>&a){return accumulate(all(a),S());}
template<class S>S max(vector<S>&a){return *max_element(all(a));}
template<class S>S min(vector<S>&a){return *min_element(all(a));}
ll max(int a,ll b){return max((ll)a,b);} ll max(ll a,int b){return max(a,(ll)b);}
int sgn(const double&r){return (r>EPS)-(r<-EPS);} // a>0  : sgn(a)>0
int sgn(const double&a,const double&b){return sgn(a-b);} // b<=c : sgn(b,c)<=0

template<class T>void puta(T&&t){cout<<t<<"\n";}
template<class H,class...T>void puta(H&&h,T&&...t){cout<<h<<' ';puta(t...);}
template<class S,class T>void tf(bool b,S t,T f){if(b)puta(t);else puta(f);}
void YN(bool b){tf(b,"YES","NO");}
void Yn(bool b){tf(b,"Yes","No");}
void yn(bool b){tf(b,"yes","no");}
template<class S,class T>ostream&operator<<(ostream&os,pair<S,T>p){os<<"["<<p.first<<", "<<p.second<<"]";return os;};
template<class S>auto&operator<<(ostream&os,vector<S>t){bool a=1;for(auto s:t){os<<(a?"":" ")<<s;a=0;}return os;}
template<class S>auto&operator>>(istream&is,vector<S>&t){for(S&a:t)cin>>a;return is;}

/*他のライブラリを入れる場所*/


int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    ll n,m;
    while(cin>>n>>m, n){
        vs f(n);cin>>f;
        vs ss;
        rep(i,n)rep(j,m){
            for(auto vy:vl{n-1,0,1})for(auto vx:vl{m-1,0,1})if(vy or vx){
                vvb v=vvb(n,vb(m,false));
                string s = "";
                ll y=i, x=j;
                while(!v[y][x]){
                    s+=f[y][x];
                    v[y][x]=true;
                    y=(y+vy)%n;
                    x=(x+vx)%m;
                }
                ss.push_back(s+"/");
            }
        }
        sort(all(ss));
        vs sss;
        sss.push_back("0");

        rep(i,ss.size()-1){
            rep(j, min(ss[i].size(), ss[i+1].size())){
                if(ss[i][j]!=ss[i+1][j] or ss[i][j]=='/'){
                    sss.push_back(ss[i].substr(0,j));
                    break;
                }
            }
        }
        sort(all(sss), [](string a, string b){return a.size()>b.size() or (a.size()==b.size() and a<b);});
        puta(sss[0]);
    }
    return 0;
}

C++: #include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <vector>
#include <string>
#include <memory.h>
using namespace std;

#define rep(i, n) for(int i = 0; i < n; i++)
typedef pair<int, int> P;
typedef pair<int, P> state;
const int INF = 1 << 28;

map<string, int> cnt;
bool used[20][20];
string s[20];
int h, w;
int dx[] = {1, 1, 1, 0, 0, -1, -1, -1};
int dy[] = {0, -1, 1, -1, 1, 0, -1, 1};

void make_string(int y, int x){
  
  rep(k, 8){
    int i = y;
    int j = x;
    string str;
    memset(used, 0, sizeof(used));
    while(!used[i][j]){
      str += s[i][j];
      cnt[str]++;
      used[i][j] = true;
      i += dy[k];
      j += dx[k];
      i = (i + h) % h;
      j = (j + w) % w;
    }
  }
}

int main(){
  while(cin >> h >> w && (h || w)){
    string res = "";
    cnt.clear();
    rep(i, h) cin >> s[i];
    rep(i, h)rep(j, w){
      make_string(i, j);
    }
    
    for(map<string, int>::iterator iter = cnt.begin(); iter != cnt.end(); iter++){
      if(iter->second > 1 && (iter->first).size() > res.size()) res = iter->first;      
    }
  
    if((int)res.size() < 2) res = "0";
    cout << res << endl;
  }
  return 0;
}

C++: #include <iostream>
#include <algorithm>
#include <iomanip>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

static const int MOD = 1000000007;
using ll = long long;
using u32 = uint32_t;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max() / 32 * 15 + 208;

string maximum(string &a, string &b){
    if(a.size() != b.size()) return (a.size() > b.size() ? a : b);
    return min(a, b);
}

bool is_parindrome(const string &s){

    return true;
}

int main() {
    int h, w;
    array<int, 8> dy{-1, -1, -1, 0, 0, 1, 1, 1},
                  dx{-1, 0, 1, -1, 1, -1, 0, 1};
    while(cin >> h >> w, h){
        vector<string> v(h);
        for (int i = 0; i < h; ++i) {
            cin >> v[i];
        }
        string ans;
        map<string, int> m;
        for (int i = 0; i < h; ++i) {
            for (int j = 0; j < w; ++j) {
                for (int k = 0; k < 8; ++k) {
                    int y = i, x = j;
                    string s;
                    vector<vector<int>> visited(h, vector<int>(w, 0));
                    while(!visited[y][x]){
                        s += v[y][x];
                        visited[y][x] = 1;
                        y = (y+dy[k]+h)%h;
                        x = (x+dx[k]+w)%w;
                    }
                    for (int l = 1; l <= s.size(); ++l) {
                        m[s.substr(0, l)]++;
                    }
                }
            }
        }
        for (auto &&i : m) {
            if(i.second >= 2){
                string s = i.first;
                ans = maximum(ans, s);
            }
        }
        cout << (ans.size() <= 1 ? "0" : ans) << "\n";
    }
    return 0;
}