use std::rc::Rc;
use std::ops::DivAssign;
use std::ops::MulAssign;
use std::ops::SubAssign;
use std::collections::BinaryHeap;
use std::str::FromStr;
use std::collections::HashSet;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::ops::Neg;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Add;
use std::ops::{AddAssign, Sub};
use std::cmp::max;
use std::collections::VecDeque;
use std::cmp::min;
use std::collections::{HashMap, BTreeSet};
use std::cmp::Ordering;
use std::fmt::Debug;

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer.trim().to_owned()
}
fn read_lines<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.trim().parse().ok().expect("Can't Parse"));
        buffer.clear();
    }
    vec
}
fn read_tabulate<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
        buffer.clear();
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split_whitespace().map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };
}
macro_rules! read_map {
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
}
macro_rules! read {
    (mut $ident: ident: String) => {
        let mut $ident = read_value::<String>();
    };
    ($ident: ident: String) => {
        let $ident = read_value::<String>();
    };
    (mut $ident: ident: [$ty:ty]) => {
        let mut $ident = read_values::<$ty>();
    };
    ($ident: ident: [$ty:ty]) => {
        let $ident = read_values::<$ty>();
    };
    (mut $ident: ident: [[$ty:ty]; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    ($ident: ident: [[$ty:ty]; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$ty:ty; $size:expr]) => {
        let mut $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$ty:ty; $size:expr]) => {
        let $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    ($($token: tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        read_from_iter!(iter; $($token)*);
    };
}
macro_rules! read_from_iter {
    ($iter:expr; mut $ident:ident:$ty:ty, $($rest:tt)*) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; $ident:ident:$ty:ty, $($rest:tt)*) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; mut $ident:ident:$ty:ty) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter:expr; $ident:ident:$ty:ty) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter: expr; ) => {};
}
struct KeyValue<K, V> {
    key: K,
    value: V
}
impl <K: PartialOrd, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialOrd, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.key.partial_cmp(&other.key).ok_or("Can't Compare").unwrap()
    }
}
fn compare_as_digit(a: &Vec<usize>, b: &Vec<usize>) -> Ordering {
    if a.len() > b.len() {
        for i in b.len() .. a.len() {
            if a[i] > 0 {
                return Ordering::Greater;
            }
        }
    }else if a.len() < b.len() {
        for i in a.len() .. b.len() {
            if b[i] > 0 {
                return Ordering::Less;
            }
        }
    }
    let min_len = min(a.len(), b.len());
    for i in (0 .. min_len).rev() {
        if a[i] != b[i] {
            return a[i].cmp(&b[i]);
        }
    }
    return Ordering::Equal
}
fn compare_as_successor(a: &Vec<usize>, b: &Vec<usize>) -> Ordering {
    if a.len() != b.len() {return a.len().cmp(&b.len());}
    compare_as_digit(a, b)
}
fn max_code(x: usize, y: usize,  state: &Vec<Vec<char>>, memo: &mut Vec<Vec<Option<Vec<usize>>>>) -> Vec<usize> {
    if state.len() <= y || state[y].len() <= x {return vec![];}
    if let Some(ref cache) = memo[y][x] {
        return cache.clone();
    }
    if let Some(d) = state[y][x].to_digit(10) {
        let mut right = max_code(x + 1, y, state, memo);
        let mut left = max_code(x, y + 1, state, memo);
        match compare_as_successor(&right, &left) {
            Ordering::Less => {
                left.push(d as usize);
                memo[y][x] = Some(left.clone());
                left
            }
            _ => {
                right.push(d as usize);
                memo[y][x] = Some(right.clone());
                right
            }
        }
    }else {
        return vec![];
    }
}
fn main() {
    loop {
        read!(width: usize, height: usize);
        if width == 0 && height == 0{break;}
        read_map!(state: [{
            read!(line: String);
            line.chars().collect::<Vec<_>>()
        }; height]);
        let mut memo: Vec<Vec<Option<Vec<usize>>>> = vec![vec![None; width]; height];
        let mut max = vec![];
        for y in 0 .. height {
            for x in 0 .. width {
                let temp = max_code(x, y, &state, &mut memo);
                if !temp.is_empty() && compare_as_digit(&temp, &max) == Ordering::Greater {
                    max = temp.clone();
                }
            }
        }
        println!("{}", max.into_iter().rev().skip_while(|&d| d == 0).map(|d| d.to_string()).collect::<Vec<_>>().join(""));
    }
}


Measured memory_bytes: 5060