#include <vector>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <utility>
#include <functional>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <climits>
#include <cassert>
using namespace std;
inline int toInt(string s) {int v; istringstream sin(s);sin>>v;return v;}
template<class T> inline string toString(T x) {ostringstream sout;sout<<x;return sout.str();}
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<string> vs;
typedef pair<int, int> pii;
typedef long long ll;
#define ALL(a) (a).begin(),(a).end()
#define RALL(a) (a).rbegin(),(a).rend()
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
const double EPS = 1e-9;
const double PI  = acos(-1.0);

int w,h;

struct piece{
	set<pii> blocks;
	vector<piece*> children;
	int lx,rx;
	piece(set<pii> blocks):blocks(blocks),lx(-1),rx(-1){}

	void construct_tree(vector<piece> &pieces,int index){
		REP(i,pieces.size()){
			if(i==index)continue;
			bool ischild=false;
			for(set<pii>::iterator mb=blocks.begin();mb!=blocks.end();mb++){
				for(set<pii>::iterator ob=pieces[i].blocks.begin();ob!=pieces[i].blocks.end();ob++){
					if(mb->first==ob->first+1&&mb->second==ob->second){
						ischild=true;
						goto found;
					}
				}
			}
			found:
			if(ischild){
				children.push_back(&(pieces[i]));
			}
		}
	}

	void set_x(){
		REP(i,children.size()){
			children[i]->lx=INT_MAX,children[i]->rx=INT_MIN;
			for(set<pii>::iterator it=children[i]->blocks.begin();it!=children[i]->blocks.end();it++){
				if(EXIST(blocks,make_pair(it->first+1,it->second))){
					children[i]->lx=min(children[i]->lx,it->second);
					children[i]->rx=max(children[i]->rx,it->second+1);
				}
			}
		}
	}

	int get_weight_pos(){
		int ret=0;
		for(set<pii>::iterator it=blocks.begin();it!=blocks.end();it++){
			ret+=it->second;
		}
		REP(i,children.size()){
			ret+=children[i]->get_weight_pos();
		}
		return ret;
	}

	int get_total_pieces(){
		int ret=4;
		REP(i,children.size()){
			ret+=children[i]->get_total_pieces();
		}
		return ret;
	}

	double get_center(){
		return (double)get_weight_pos()/get_total_pieces()+0.5;
	}

	bool ok(){
		double center=get_center();
		return lx+EPS<center&&center<rx-EPS;
	}
};

int dx[]={-1,0,1,0},dy[]={0,-1,0,1};
piece construct_piece(vs &pp,int y,int x,vvi &used){
	char c=pp[y][x];
	set<pii> blocks;
	queue<pii> q;
	q.push(make_pair(y,x));
	while(!q.empty()){
		pii p=q.front();q.pop();
		REP(d,4){
			int y=p.first+dy[d];
			int x=p.second+dx[d];
			pii block=make_pair(y,x);
			if(y>=0&&x>=0&&y<h&&x<w&&pp[y][x]==c&&!EXIST(blocks,block)){
				blocks.insert(block);
				q.push(block);
				used[y][x]=1;
			}
		}
	}
	return piece(blocks);
}

int main(){
	while(cin>>w>>h,w|h){
		vs p(h);
		REP(i,h){
			cin>>p[i];
		}
		vector<piece> pieces;
		vvi used(h,vi(w));
		REP(i,h){
			REP(j,w){
				if(p[i][j]!='.'&&!used[i][j]){
					pieces.push_back(construct_piece(p,i,j,used));
				}
			}
		}
		REP(i,pieces.size()){
			pieces[i].construct_tree(pieces,i);
		}
		REP(i,pieces.size()){
			pieces[i].set_x();
		}
		REP(i,pieces.size()){
			if(pieces[i].lx==-1){
				int lx=INT_MAX,rx=INT_MIN;
				for(set<pii>::iterator it=pieces[i].blocks.begin();it!=pieces[i].blocks.end();it++){
					if(it->first==h-1){
						lx=min(lx,it->second);
						rx=max(rx,it->second+1);
					}
				}
				pieces[i].lx=lx;
				pieces[i].rx=rx;
			}
		}
		bool ok=true;
		REP(i,pieces.size()){
			if(!pieces[i].ok()){
				ok=false;
				break;
			}
		}
		cout<<(ok?"STABLE":"UNSTABLE")<<endl;
	}
}

Measured memory_bytes: 1264