// Arup Guha
// 3/8/2022
// Solution to 2021 SER D1 Problem: Fail Them All

import java.util.*;

public class failthemall {

	public static int numS;
	public static int numQ;
	public static char[][] ans;
	
	// Store implications here.
	public static ArrayList<pair> imps;
	
	public static void main(String[] args) {
	
		// Get basic info.
		Scanner stdin = new Scanner(System.in);
		numS = stdin.nextInt();
		numQ = stdin.nextInt();
		
		// Get all answers.
		ans = new char[numS][];
		for (int i=0; i<numS; i++)
			ans[i] = stdin.next().toCharArray();
			
		// Store all required implications here.
		imps = new ArrayList<pair>();
		
		// All students.
		for (int i=0; i<numS; i++) {
		
			// All pairs of responses. Notice that if the first is true, the second must be false...
			for (int j=0; j<numQ; j++) {
				for (int k=0; k<numQ; k++) {
					if (j == k) continue;
					if (ans[i][j] == 'X' || ans[i][k] == 'X') continue;
					imps.add(new pair(ans[i][j]=='T',j,ans[i][k]=='F',k));
				}
			}
		}
	
		// Store answer here.
		char[] res = new char[numQ];
		Arrays.fill(res, '-');
		
		// Try with no forces.
		boolean tmp = canDo(res, 0);
		
		// Oops, doesn't work.
		if (!tmp)
			System.out.println(-1);
		
		// Get lexicographically first answer.
		else {
		
			// Go question by question.
			for (int i=0; i<numQ; i++) {
				
				// We've done this one already.
				if (res[i] != '-') continue;
			
				// Try false first.
				res[i] = 'F';
				tmp = canDo(res, i+1);
				
				// Great it works!
				if (tmp) {

					// Fill any anything forced by this answer.
					putInForces(i, res);
					continue;
				}
				
				// We know this must work and fill in anything forced.
				res[i] = 'T';
				putInForces(i, res);
			}
			
			// Ta da!
			System.out.println(new String(res));
		}
	}
	
	// Places all items that are forced by res[idx] for indexes greater than idx.
	public static void putInForces(int idx, char[] res) {
		
		// Look at who answered this one right.
		for (int i=0; i<numS; i++) {
			if (ans[i][idx] == res[idx]) {
				
				// Look at future answers, all must be wrong! So put them in our answer array!
				for (int j=idx+1; j<numQ; j++) {
					if (ans[i][j] == 'X') continue;
					res[j] = ans[i][j] == 'T' ? 'F' : 'T';
				}
			}
		}
	}
	
	// Returns true iff there exists a way to satisfy all the implications with the first k truth assignments in current.
	public static boolean canDo(char[] current, int k) {
	
		// Put in original items.
		TwoSat exp = new TwoSat(numQ);
		for (pair p: imps)
			exp.addImpl(p.val1,p.id1,p.val2,p.id2);
			
		// Add forces.
		for (int i=0; i<k; i++)
			exp.addForce(i, current[i] == 'T');
			
		// Ta da!
		return exp.solve();
	}
}

class pair {

	public boolean val1;
	public int id1;
	public boolean val2;
	public int id2;

	public pair(boolean v1, int i1, boolean v2, int i2) {
		val1 = v1;
		id1 = i1;
		val2 = v2;
		id2 = i2;
	}
}

// UCF Hackpack Two-Sat Code
class TwoSat {
	int n, n2;  byte[] vals, cvals;  SCC scc;

	public TwoSat(int nn) {  n2 = 2 * (n = nn);  scc = new SCC(n2);  vals = new byte[n2];}

	// Example: (true, 0, false, 1) => 0 --> !1
	public void addImpl(boolean va, int a, boolean vb, int b) {
		a <<= 1; b <<= 1;  if (!va) a++;  if (!vb) b++;
		scc.add(a, b);  scc.add(b ^ 1, a ^ 1);
	}

	//# Add (a NAND b)
	public void addNand(boolean va, int a, boolean vb, int b) {
		addImpl(va, a, !vb, b);
	}//$

	//# Add (a OR b)
	public void addOr(boolean va, int a, boolean vb, int b) {
		addImpl(!va, a, vb, b); // ~a -> b
	}//$

	//# Add (a XOR b)
	public void addXor(boolean va, int a, boolean vb, int b) {
		addImpl(!va, a, vb, b); // ~a -> b
		addImpl(va, a, !vb, b); // a -> ~b
	}//$

	//# Forces a to have whatever value va is
	public void addForce(int a, boolean va) {
		addImpl(!va, a, va, a);
	}//$

	// Returns the value of the variable v
	public boolean getVal(int v) {
		return vals[v << 1] == 1;
	}

	public boolean solve() {
		int map[] = scc.go();
		for(int i = 0; i < n; i++) {
			if(map[2*i] == map[2*i+1]) return false;
		}
		for(int i = 0; i < n2; i++) vals[i] = (byte)-1;
		for(int i = 0; i < scc.cs; i++) {
			for(int v : scc.comp[i]) {
				if(vals[v] == -1) {
					vals[v] = 1;
				}
				vals[v^1] = (byte)(vals[v]^1);
			}
		}
		return true;
	}
}

// UCF HackPack SCC Code
class SCC {
  ArrayList<Integer>[] adj;
  ArrayList<Integer>[] comp;
  int n;
  int idx, cs;
  boolean[] u;
  int[] pre, low, map;
  ArrayDeque<Integer> s;
  public SCC(int nn) {
    adj = new ArrayList[n = nn];
    for (int curr = 0; curr < n; ++curr)
      adj[curr] = new ArrayList<>();
  }
  void add(int v1, int v2) {
    adj[v1].add(v2); 
  }
  int[] go() {
  comp = new ArrayList[n];
    idx = 1; cs = 0;
    pre = new int[n]; low = new int[n]; map = new int[n];
    u = new boolean[n];
    s = new ArrayDeque<Integer>();
    for (int i = 0; i < n; ++i)
      if (pre[i] == 0)
        dfs(i);
    return map;
  }

  void dfs(int v) {
    pre[v] = low[v] = idx++;
    s.push(v);
    u[v] = true;
    for (int to : adj[v]) {
      if (pre[to] == 0) {
        dfs(to);
        low[v] = Math.min(low[v], low[to]);
      } else if (u[to]) {
        low[v] = Math.min(low[v], pre[to]);
      }
    }
    if (low[v] == pre[v]) {
      int next;
      comp[cs] = new ArrayList<>();
      do {
        next = s.pop();
        u[next] = false;
        map[next] = cs;
        comp[cs].add(next);
      } while (next != v);
      cs++;
    }
  }

  //# Make sure to call go() before calling this function.
  // Function returns a new graph such that all SCCs are
  // compressed into one node and only the edges connecting
  // two components are in the new graph.
  // nodeMapping is an integer array that will store the mapping
  // for each node in the old graph into the new graph.//$
  ArrayList[] compressSCC() {
    ArrayList<Integer>[] g = new ArrayList[cs];
    for(int i = 0; i < cs; i++) g[i] = new ArrayList<Integer>();
    int[] added = new int[cs];
    Arrays.fill(added, -1);
    for(int i = 0; i < cs; i++) {
      for(int v : comp[i]) {
        for(int to : adj[v]) {
          int mapTo = map[to];
          if(mapTo != i && added[mapTo] != i) {
            g[i].add(mapTo);
            added[mapTo] = i;
          }
        }
      }
    }
    return g;
  }
}