#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <queue>
#include <unordered_map>

#define lli long long int
#define REP(i,n) for(lli i=0;i<n;i++)

#define NUM 1000000

using namespace std;

int length = 0;

int max1(int a, int b){
	if (a >= b)return a;
	else return b;
}

int isIn(int x, int y, int w, int h){
	if (x < 0 || w <= x || y < 0 || h <= y){
		return 0;
	}
	else{
		return 1;
	}
}

int isNum(int x, int y, string *data){
	if ('0' <= data[y].at(x) && data[y].at(x) <= '9'){
		return 1;
	}
	else{
		return 0;
	}
}

string emitZero(string str){

	string rStr = "";
	REP(i, str.size()){
		if (str.at(i) != '0'){
			rStr = str.substr(i, str.size());
			break;
		}
	}

	return rStr;

}

string largeStr(string a, string b){
	if (a.size() > b.size()){
		return a;
	}
	else if (a.size() == b.size()){
		if (a >= b){
			return a;
		}
		else{
			return b;
		}
	}
	else{
		return b;
	}
}


/*
void solve(int x, int y,int w,int h,string now,string *data, vector<string> *v,int **flag){
	
	if (!isIn(x,y,w,h) || isNum(x,y,data)==0){
		//cout << now << endl;
		now = emitZero(now);
		//cout << now << endl;
		//cout << "now.size = " << now.size() << endl;
		length = max1(length, now.size());
		v->push_back(now);
		return;
	}
	else{
		flag[y][x] = 1;
		string next = now + data[y].at(x);
		solve(x + 1, y, w, h, next, data, v,flag);
		solve(x, y + 1, w, h, next, data, v,flag);
	}
}
*/

class Point{

private:
	int x, y;
public:
	void set(int sX, int sY){
		x = sX;
		y = sY;
	}
	int getX(){ return x; }
	int getY(){ return y; }

	bool operator < (const Point & right)const{
		return x + y*NUM < right.x + right.y*NUM;
	}

	void show(){
		cout << "X=" << x << " Y=" << y << endl;
	}
};

class now{
private:
	Point p;
	string str;
public:

	void set(int sX, int sY, string sStr){
		p.set(sX, sY);
		str = sStr;
	}

	Point getPoint(){ return p; }
	string getStr(){ return str; }

};

int main(){


	
	int w, h;

	while (cin >> w >> h){
		if (w == 0 && h == 0)break;
		length = 0;
		string *data;
		data = new string[h];

		REP(i, h){
			cin >> data[i];
		}
		int **flag = new int *[h];
		REP(i, h){
			flag[i] = new int[w];
		}
		vector<string> v;
		queue<Point> q;
		string firstStr;
		map<Point, string> m;
		Point p;
		p.set(w - 1, h - 1);
		q.push(p);
		//q.front().show();

		REP(i, 100){
			REP(j, 100){
				Point temp;
				temp.set(i, j);
				m[temp] = "";
			}
		}
		REP(i, h){
			REP(j, w){
				flag[i][j] = 0;
			}
		}

		while (q.size() != 0){

			int unko;
			//cin >> unko;
			p = q.front();
			q.pop();
			flag[p.getY()][p.getX()] = 1;
			//p.show();


			if (isNum(p.getX(), p.getY(), data) == 1){
				Point right, down;
				right.set(p.getX() + 1, p.getY());
				down.set(p.getX(), p.getY() + 1);

				//cout << data[p.getY()][p.getX()] << endl;

				m[p] = largeStr(m[p],data[p.getY()][p.getX()]+largeStr(m[right], m[down]));
				//cout << m[p] << endl;
			}

			if (p.getX() - 1 >= 0 && flag[p.getY()][p.getX()-1]==0){
				Point left;
				left.set(p.getX() - 1, p.getY());
				q.push(left);
				flag[left.getY()][left.getX()] = 1;
			}
			if (p.getY() - 1 >= 0 && flag[p.getY()-1][p.getX()]==0){
				Point up;
				up.set(p.getX(), p.getY() - 1);
				q.push(up);
				flag[up.getY()][up.getX()] = 1;
			}
		}

		int length = 0;
		REP(i, h){
			REP(j, w){
				Point tmp;
				tmp.set(j, i);
				string tmpStr = m[tmp];
				tmpStr = emitZero(tmpStr);

				v.push_back(tmpStr);
				length = max1(length, tmpStr.size());
			}
		}

		vector<string> ans;

		REP(i, v.size()){
			if (length == v.at(i).size()){
				ans.push_back(v[i]);
			}
		}

		sort(ans.begin(), ans.end());

		cout << ans.back() << endl;


	}

	return 0;
}

Measured memory_bytes: 4580