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 <string>
#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];
char MAP[11][22];
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(scanf("%d%d",&H,&W),H){
    REP(i,H)scanf("%s",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);
      }
    }
    puts(res.c_str());
  }
}

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;

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 = 1;
		for (;; 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 < 3)cout << 0 << endl;
		else {
			string str = get<0>(buf[0]);
			cout << str.substr(0, l-1) << endl;
		}
	}
	return 0;
}

C++: #include <bits/stdc++.h>
using namespace std;

void dicch(vector<string> d){
    vector<map<string,int>> lis(1);
    vector<string> ans;
    map<string, int> mp;
    lis.push_back(mp);
    int maxl=1,leng=1;
    for(string x:d){
        if(x.size()>=maxl){
            if(x.size()>leng){
                leng=x.size();
                lis.resize(leng);
                map<string,int> tmp;
                tmp[x]=1;
                lis.push_back(tmp);
            }
            else{
                if( lis[x.size()-1].find(x)!=lis[x.size()-1].end() ){
                    if(x.size()>maxl){
                        ans.clear();
                        maxl=x.size();
                    }
                    ans.push_back(x);
                }
                else{
                    lis[x.size()-1][x]=1;
                }
            }
        }
    }
    sort(ans.begin(),ans.end());
    cout << ((ans.empty())?"0":*ans.begin())<<endl;
}

void dicmk(vector<string> d){
    vector<string> pass;
    for(string x:d){
        string xx=x+x;
        for(int i=2;i<=x.size();i++){
            for(int j=0;j<x.size();j++){
                string str=xx.substr(j,i);
                pass.push_back(str);
            }
        }
    }
    dicch(pass);
}


void check(vector<vector<char>> d,int h,int w){
    vector<string> dic;
    int x,y;
    for(int i=0;i<w;i++){
        string str;
        for(int j=0;j<h;j++){
            str.push_back(d[j][i]);
        }
        dic.push_back(str);
    }
    for(int i=0;i<h;i++){
        string str;
        for(int j=0;j<w;j++){
            str.push_back(d[i][j]);
        }
        dic.push_back(str);
    }
    vector<bool> s1(w,true);
    for(int i=0;i<w;i++){
        if(s1[i]){
            string str;
            x=i;
            y=0;
            str.push_back(d[y][x]);
            x+=1;x=(x+w)%w;
            y+=1;y=(y+h)%h;
            while(!(x==i&&y==0)){
                if(y==0){
                    s1[x]=false;
                }
                str.push_back(d[y][x]);
                x+=1;x=(x+w)%w;
                y+=1;y=(y+h)%h;
            }
            dic.push_back(str);
        }
    }
    vector<bool> s2(w,true);
    for(int i=0;i<w;i++){
        if(s2[i]){
            string str;
            x=i;
            y=0;
            str.push_back(d[y][x]);
            x-=1;x=(x+w)%w;
            y+=1;y=(y+h)%h;
            while(!(x==i&&y==0)){
                if(!y){
                    s2[x]=false;
                }
                str.push_back(d[y][x]);
                x-=1;x=(x+w)%w;
                y+=1;y=(y+h)%h;
            }
            dic.push_back(str);
        }
    }
    int siz=dic.size();
    for(int i=0;i<siz;i++){
        string rev=dic[i];
        reverse(rev.begin(), rev.end());
        dic.push_back(rev);
    }
    dicmk(dic);
}

void slove(int h,int w){
    vector<vector<char>> d; 
    char t;
    for(int i=0;i<h;i++){
        vector<char> tmp;
        for(int j=0;j<w;j++){
            cin >> t;
            tmp.push_back(t);
        }
        d.push_back(tmp);
    }
    check(d,h,w);
}


int main(void){
    int h,w;
    while(cin>>h>>w,h){
        slove(h,w);
    }
}