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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;

typedef struct List{
	int cnt;
	char s[210];
}LIST;
struct comp{
	bool operator() (const List& a, const List& b) const{  //free
		if(a.cnt!=b.cnt)
			return a.cnt>b.cnt ? true : false;
		for(int i=0;i<a.cnt;i++)
			if(a.s[i]!=b.s[i])
				return a.s[i]>b.s[i] ? true : false;
		return false;
	}
};
LIST now,ans;
map <List,int,comp> MAP;

char ss[15][25];
int visit[15][25],op[8][2] = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	
	int N,n,M,m,i,j,mark,maxi,nx,ny,now_cnt;
	while(~scanf(" %d %d",&N,&M) && (N+M)){
		gets(ss[0]);
		for(n=0;n<N;n++)
			gets(ss[n]);
		MAP.clear();
		ans.cnt = 0;
		now_cnt = 0;
		memset(visit,0,sizeof(visit));
		mark = 0;
		for(n=0;n<N;n++){
			for(m=0;m<M;m++){
				for(i=0;i<8;i++){
					mark++;
					now.cnt = 1;
					now.s[0] = ss[n][m];
					visit[n][m] = mark;
					nx = (n+op[i][0]+N)%N;
					ny = (m+op[i][1]+M)%M;
					while(visit[nx][ny]!=mark){
						visit[nx][ny] = mark;
						now.s[now.cnt++] = ss[nx][ny];
						nx = (nx+op[i][0]+N)%N;
						ny = (ny+op[i][1]+M)%M;
						if(now.cnt>1 && now.cnt>=ans.cnt){
							if(MAP.find(now)==MAP.end()){
								MAP[now] = n*M+m;
							}
							else{
								if(now.cnt>ans.cnt){
									ans = now;
								}
								else if(now.cnt==ans.cnt){
									int which = 1;
									for(j=0;j<now.cnt;j++){
										if(ans.s[j]==now.s[j])
											continue;
										else{
											if(ans.s[j]<now.s[j])
												which = 1;
											else
												which = 2;
										}
									}
									if(which==2)
										ans = now;
								}
							}
						}
					}
				}
			}
		}
		//printf("==============================================\n");
		if(ans.cnt>1){
			int re = 0;
			for(i=0,j=ans.cnt-1;i<=j;i++,j--){
				if(ans.s[i]!=ans.s[j]){
					re = ans.s[i]>ans.s[j] ? 1 : 2;
					break;
				}
			}
			if(re==2 || re==0)
				for(i=0;i<ans.cnt;i++)
					printf("%c",ans.s[i]);
			else
				for(i=ans.cnt-1;i>=0;i--)
					printf("%c",ans.s[i]);
			printf("\n");
		}
		else
			printf("0\n");
	}
	
	return 0;
}

C++: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define all(x) (x).begin(),(x).end()
const int mod=1000000007,MAX=100005,INF=1<<30;
vector<int> dh={-1,0,1,1,1,0,-1,-1},dw={1,1,1,0,-1,-1,-1,0};

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int H,W;cin>>H>>W;
        if(H+W==0) break;
        map<string,int> MA;
        string ans="";
        
        vector<string> S(H);
        for(int i=0;i<H;i++) cin>>S[i];
        
        for(int a=0;a<H;a++){
            for(int b=0;b<W;b++){
                for(int k=0;k<8;k++){
                    string T;
                    int hnow=a,wnow=b;
                    while(1){
                        T+=S[hnow][wnow];
                        MA[T]++;
                        
                        hnow+=dh[k];
                        wnow+=dw[k];
                        
                        if(hnow<0) hnow+=H;
                        if(hnow>=H) hnow-=H;
                        
                        if(wnow<0) wnow+=W;
                        if(wnow>=W) wnow-=W;
                        
                        if(hnow==a&&wnow==b) break;
                    }
                }
            }
        }
        
        for(auto it=MA.begin();it!=MA.end();it++){
            if((*it).second>=2){
                if(ans.size()==(*it).first.size()){
                    ans=min(ans,(*it).first);
                }else if(ans.size()<(*it).first.size()){
                    ans=(*it).first;
                }
            }
        }
        
        if(ans.size()>=2) cout<<ans<<endl;
        else cout<<0<<endl;
    }
}

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

int N,M,L,K,A,H;
bool re[100];
int cost[100][100];

struct Node{
	int total,rem,pos,total_b;
};

bool operator < (Node a,Node b){
	return a.total>b.total;
}


void solve()
{
	memset(re,false,sizeof(re));
	memset(cost,-1,sizeof(cost));
	re[A]=re[H]=true;
	for(int i=0;i<L;i++){int t;cin>>t;re[t]=true;}

	for(int i=0;i<K;i++){
		int in,out,c;cin>>in>>out>>c;
		cost[in][out]=cost[out][in]=c;
	}

	vector<vector<Node> >V(N);
	Node first;
	first.rem=M; first.total=0; first.pos=A;first.total_b=0;
	priority_queue<Node> Q;
	Q.push(first);
//	cout<<endl<<endl;

	while(!Q.empty()){
		Node now=Q.top();
		Q.pop();
//		cout<<now.pos<<" "<<now.rem<<" "<<now.total<<endl;
		if(now.rem<0) continue;
		if(now.pos==H){cout<<now.total-min(now.total_b,now.rem)<<endl; return;}
		bool ok=true;
		for(int i=0;i<V[now.pos].size();i++){
			if(V[now.pos][i].rem>=now.rem && V[now.pos][i].total<=now.total){
				ok=false;
				break;
			}
		}
		if(!ok) continue;
		V[now.pos].push_back(now);

		for(int i=0;i<N;i++){
			if(cost[now.pos][i]==-1) continue;
			Node next;
			if(re[i]){
				if(now.rem<cost[now.pos][i]) continue;
				next.rem=M;
				next.total=now.total+cost[now.pos][i]+M-now.rem+cost[now.pos][i];
				next.pos=i;
				next.total_b=now.total_b+M-now.rem+cost[now.pos][i];
			}
			else{
				next.rem=now.rem-cost[now.pos][i];
				next.total=now.total+cost[now.pos][i];
				next.pos=i;
				next.total_b=now.total_b;
			}
			Q.push(next);
		}

	}

	cout<<"Help!"<<endl;
}



int main(){
	while(cin>>N>>M>>L>>K>>A>>H){
		if(N==0) break;
		solve();
	}
	return 0;
}