#include <iostream>
#include <complex>
#include <sstream>
#include <string>
#include <algorithm>
#include <deque>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <vector>
#include <set>
#include <limits>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
#define REP(i, j) for(int i = 0; i < (int)(j); ++i)
#define FOR(i, j, k) for(int i = (int)(j); i < (int)(k); ++i)
#define P pair<int, int>
#define SORT(v) sort((v).begin(), (v).end())
#define REVERSE(v) reverse((v).begin(), (v).end())
const int MAX_N = 61;

int my[] = {-1, 1, 0, 0};
int mx[] = {0, 0, 1, -1};

class C{
  public: 
    int cnt, sum, parent;
    double p_xl, p_xr;
    vector<P> cs;
    C(int _p, vector<P> _cs, double _p_xl, double _p_xr){
      parent = _p;
      cs = _cs;
      cnt = (int)(cs.size());
      sum = 0;
      REP(i, cs.size()){
        sum += cs[i].second;
      }
      p_xl = _p_xl;
      p_xr = _p_xr;
    }
    C(){};
};

int W, H;
string f[MAX_N];
vector<C> blocks;
vector< set<int> > children;

void find_block(int y, int x, char c, vector<P> &v){
  f[y][x] = '.';
  v.push_back(P(y, x));
  REP(i, 4){
    int ny = y + my[i], nx = x + mx[i];
    if(ny >= 0 && nx >= 0 && ny < H && nx < W && f[ny][nx] == c)
      find_block(ny, nx, c, v);
  }
}

int find_parent(int now){
  int ret = -1;
  vector<P> cs;
  REP(i, blocks.size()){
    if(i == now) continue;
    REP(j, blocks[now].cs.size()){
      REP(k, blocks[i].cs.size()){
        int now_y = blocks[now].cs[j].first;
        int now_x = blocks[now].cs[j].second;
        int block_y = blocks[i].cs[k].first;
        int block_x = blocks[i].cs[k].second;
        if(now_x == block_x && now_y + 1 == block_y){
          ret = i;
          cs.push_back(P(block_y, block_x));
          //blocks[now].p_xl = 100.0;
          //blocks[now].p_xr = -1.0;
          //REP(j, blocks[i].cs.size()){
            //TODO: 以下のif文で本当に合ってる？
            //if(blocks[i].cs[j].first == block_y){
            //  blocks[now].p_xl = min(blocks[now].p_xl, (double)blocks[i].cs[j].second - 0.5);
            //  blocks[now].p_xr = max(blocks[now].p_xr, (double)blocks[i].cs[j].second + 0.5);
            //}
          //}
          //return i;
        }
      }
    }
  }
  if(ret != -1){
    double xl = 100, xr = -1;
    REP(i, cs.size()){
      xl = min(xl, cs[i].second - 0.5);
      xr = max(xr, cs[i].second + 0.5);
    }
    blocks[now].p_xl = xl;
    blocks[now].p_xr = xr;
  }
  return ret;
  //return -1;
}

void find_children(int now, set<int> &c){
  REP(i, blocks.size()){
    if(blocks[i].parent == now && c.find(i) == c.end()){
      c.insert(i);
      find_children(i, c);
    }
  }
}

bool is_valid_tree(int now){
  int a = blocks[now].sum, b = blocks[now].cnt;
  for(set<int>::iterator it = children[now].begin(); it != children[now].end(); ++it){
    C block = blocks[(*it)];
    a += block.sum;
    b += block.cnt;
  }
  double m = (double)a / b;
  //cout <<now <<" : " <<blocks[now].p_xl <<", " <<m <<", " <<blocks[now].p_xr <<endl;
  return (m > blocks[now].p_xl && m < blocks[now].p_xr ? true : false);
}

int main() {
  while(cin >>W >>H && H){
    blocks.clear();
    REP(i, H) cin >>f[i];
    REP(i, W){
      if(isdigit(f[H - 1][i])){
        vector<P> cs;
        find_block(H - 1, i, f[H - 1][i], cs);
        double xl = 100, xr = -1;
        REP(k, cs.size()){
          if(cs[k].first == H - 1){
            xl = min(xl, cs[k].second - 0.5);
            xr = max(xl, cs[k].second + 0.5);
          }
        }
        C tmp = C(-1, cs, xl, xr);
        blocks.push_back(tmp);
      }
    }
    //REP(i, blocks[0].cs.size()) cout <<blocks[0].cs[i].first <<", " <<blocks[0].cs[i].second <<", " <<blocks[0].p_xl <<", " <<blocks[0].p_xr <<endl;
    for(int i = H - 1; i >= 0; --i){
      for(int j = W - 1; j >= 0; --j){
        if(isdigit(f[i][j])){
          vector<P> cs;
          find_block(i, j, f[i][j], cs);
          blocks.push_back(C(-1, cs, -1, 100));
        }
      }
    }
    FOR(i, 1, blocks.size())
      blocks[i].parent = find_parent(i);
    //REP(i, blocks.size()){
    //  cout <<i <<" : " <<endl;
    //  cout <<"parent = " <<blocks[i].parent <<", xl = " <<blocks[i].p_xl <<", xr = " <<blocks[i].p_xr <<endl;
    //  REP(j, blocks[i].cs.size()) cout <<blocks[i].cs[j].first <<", " <<blocks[i].cs[j].second <<" | ";
    //  cout <<endl;
    //}
    children = vector< set<int> >((int)(blocks.size()));
    FOR(i, 1, blocks.size()) children[0].insert(i);
    FOR(i, 1, blocks.size()) find_children(i, children[i]);
    //REP(i, blocks.size()){
    //  cout <<i <<" : ";
    //  for(set<int>::iterator it = children[i].begin(); it != children[i].end(); ++it) cout <<(*it) <<", ";
    //  cout <<endl;
    //}
    bool isok = true;
    REP(i, blocks.size()){
      if(!is_valid_tree(i)){
        isok = false;
        break;
      }
    }
    cout <<(isok ? "STABLE" : "UNSTABLE") <<endl;
  }
  return 0;
}

Measured memory_bytes: 1264