/+ dub.sdl:
    name "E"
    dependency "dunkelheit" version=">=0.9.0"
+/

import std.stdio, std.algorithm, std.range, std.conv;
// import dkh.foundation, dkh.scanner;

// import dkh.graph.dijkstra;

int main() {
    Scanner sc = new Scanner(stdin);
    scope(exit) sc.read!true;

    int a, b;
    sc.read(a, b);

    int[][] mp = new int[][a];
    foreach (i; 0..a) {
        sc.read(mp[i]);
    }

    import std.typecons;
    alias E = Tuple!(int, "to", int, "dist", char, "type");

    int s = 0, t = 220;
    E[][] g = new E[][](221);

    int getD(int x, int y) {
        foreach (i; 0..221) {
            foreach (ref e; g[i]) {
                if (e.type == 'N') continue;
                if (e.type == 'X') e.dist = x;
                if (e.type == 'Y') e.dist = y;
            }
        }
        auto dist = dijkstra!int(g, s).dist;
        return dist[t];
    }

    foreach (i; 0..109) {
        g[i] ~= E(i+1, 0, 'X');
        g[t-i-1] ~= E(t-i, 0, 'Y');
    }

    foreach (i; 0..107) {
        foreach (j; 0..107) {
            int mi = 0;
            foreach (r; 0..a) {
                foreach (c; 0..b) {
                    mi = max(mi, mp[r][c] - i*(r+1) - j*(c+1));
                }
            }
            g[i] ~= E(t-j, mi, 'N');
        }
    }

    foreach (i; 0..a) {
        foreach (j; 0..b) {
            int u = getD(i+1, j+1);
            if (u != mp[i][j]) {
                writeln("Impossible");
                return 0;
            }
        }
    }

    writeln("Possible");
    int m = iota(221).map!(i => g[i].length.to!int).sum;
    writeln(221, " ", m);
    foreach (i; 0..221) {
        foreach (e; g[i]) {
            string st;
            if (e.type == 'N') st = e.dist.to!string;
            else {
                st ~= e.type;
            }
            writeln(i+1, " ", e.to+1, " ", st);
        }
    }
    writeln(s+1, " ", t+1);
    return 0;
}
/* IMPORT /home/yosupo/Program/dunkelheit/source/dkh/foundation.d */
 
// module dkh.foundation;

 
static if (__VERSION__ <= 2070) {
    /*
    Copied by https://github.com/dlang/phobos/blob/master/std/algorithm/iteration.d
    Copyright: Andrei Alexandrescu 2008-.
    License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
    */
    template fold(fun...) if (fun.length >= 1) {
        auto fold(R, S...)(R r, S seed) {
            import std.algorithm : reduce;
            static if (S.length < 2) {
                return reduce!fun(seed, r);
            } else {
                import std.typecons : tuple;
                return reduce!fun(tuple(seed), r);
            }
        }
    }
     
}
/* IMPORT /home/yosupo/Program/dunkelheit/source/dkh/scanner.d */
// module dkh.scanner;

// import dkh.container.stackpayload;

 
class Scanner {
    import std.stdio : File;
    import std.conv : to;
    import std.range : front, popFront, array, ElementType;
    import std.array : split;
    import std.traits : isSomeChar, isStaticArray, isArray; 
    import std.algorithm : map;
    File f;
    this(File f) {
        this.f = f;
    }
    char[512] lineBuf;
    char[] line;
    private bool succW() {
        import std.range.primitives : empty, front, popFront;
        import std.ascii : isWhite;
        while (!line.empty && line.front.isWhite) {
            line.popFront;
        }
        return !line.empty;
    }
    private bool succ() {
        import std.range.primitives : empty, front, popFront;
        import std.ascii : isWhite;
        while (true) {
            while (!line.empty && line.front.isWhite) {
                line.popFront;
            }
            if (!line.empty) break;
            line = lineBuf[];
            f.readln(line);
            if (!line.length) return false;
        }
        return true;
    }

    private bool readSingle(T)(ref T x) {
        import std.algorithm : findSplitBefore;
        import std.string : strip;
        import std.conv : parse;
        if (!succ()) return false;
        static if (isArray!T) {
            alias E = ElementType!T;
            static if (isSomeChar!E) {
                 
                 
                auto r = line.findSplitBefore(" ");
                x = r[0].strip.dup;
                line = r[1];
            } else static if (isStaticArray!T) {
                foreach (i; 0..T.length) {
                    bool f = succW();
                    assert(f);
                    x[i] = line.parse!E;
                }
            } else {
                StackPayload!E buf;
                while (succW()) {
                    buf ~= line.parse!E;
                }
                x = buf.data;
            }
        } else {
            x = line.parse!T;
        }
        return true;
    }

    int unsafeRead(T, Args...)(ref T x, auto ref Args args) {
        if (!readSingle(x)) return 0;
        static if (args.length == 0) {
            return 1;
        } else {
            return 1 + read(args);
        }
    }
    void read(bool enforceEOF = false, T, Args...)(ref T x, auto ref Args args) {
        import std.exception;
        enforce(readSingle(x));
        static if (args.length == 0) {
            enforce(enforceEOF == false || !succ());
        } else {
            read!enforceEOF(args);
        }
    }
    void read(bool enforceEOF = false, Args...)(auto ref Args args) {
        import std.exception;
        static if (args.length == 0) {
            enforce(enforceEOF == false || !succ());
        } else {
            enforce(readSingle(args[0]));
            read!enforceEOF(args);
        }
    }
}


 
 

 
/* IMPORT /home/yosupo/Program/dunkelheit/source/dkh/container/radixheap.d */
// module dkh.container.radixheap;

// import dkh.container.stackpayload;

import std.functional : unaryFun;
import std.traits : isSigned, isUnsigned;

 
template RadixHeap(T, alias pred = "a") {
    alias _pred = unaryFun!pred;  
    alias K = typeof(_pred(T()));  
     
    static if (isUnsigned!K) {
         

        struct RadixHeap {
            static struct Payload {
                StackPayload!T[K.sizeof*8+1] v;
                size_t len;
                K last;

                 
                private static int bsr1(K x) {
                    import core.bitop : bsr;
                    return (x == 0) ? 0 : bsr(x)+1;
                }
                private void assign(T item) {
                    K key = _pred(item);
                    assert(last <= key);
                    v[bsr1(key^last)] ~= item;
                }
                private void pull() {
                    import std.range, std.algorithm;
                    if (v[0].length) return;
                    auto i = iota(K.sizeof*8+1).find!(a => v[a].length).front;
                     
                    last = v[i].data[].map!_pred.reduce!min;
                    v[i].data.each!(a => assign(a));
                    v[i].clear();
                }

                void insert(T item) {
                    len++;
                    assign(item);
                }
                T front() {
                    pull();
                    return v[0].back;
                }
                void removeFront() {
                    pull();
                    len--;
                    v[0].removeBack();
                }
            }
            Payload* p;

            @property bool empty() const { return (!p || p.len == 0); }  
            @property size_t length() const { return (!p ? 0 : p.len); }  
            alias opDollar = length;  

             
            T front() {
                assert(!empty, "RadixHeap.front: heap is empty");
                return p.front;
            }
            void insert(T item) {
                if (!p) p = new Payload();
                p.insert(item);
            }  
            void removeFront() {
                assert(!empty, "RadixHeap.removeFront: heap is empty");
                p.removeFront();
            }  
        }
    } else static if (isSigned!K) {
         
        import std.traits : Unsigned;
        static Unsigned!K pred2(in T item) {
            return _pred(item) ^ (K(1) << (K.sizeof*8 - 1));
        }
        alias RadixHeap = RadixHeap!(T, pred2);
    } else {
        static assert(false);
    }
}

 
 

 

 
/* IMPORT /home/yosupo/Program/dunkelheit/source/dkh/container/stackpayload.d */
// module dkh.container.stackpayload;

 
struct StackPayload(T, size_t MINCAP = 4) if (MINCAP >= 1) {
    import core.exception : RangeError;

    private T* _data;
    private uint len, cap;

    @property bool empty() const { return len == 0; }
    @property size_t length() const { return len; }
    alias opDollar = length;

     
    inout(T)[] data() inout { return (_data) ? _data[0..len] : null; }
    
    ref inout(T) opIndex(size_t i) inout {
        version(assert) if (len <= i) throw new RangeError();
        return _data[i];
    }  
    ref inout(T) front() inout { return this[0]; }  
    ref inout(T) back() inout { return this[$-1]; }  

    void reserve(size_t newCap) {
        import core.memory : GC;
        import core.stdc.string : memcpy;
        import std.conv : to;
        if (newCap <= cap) return;
        void* newData = GC.malloc(newCap * T.sizeof);
        cap = newCap.to!uint;
        if (len) memcpy(newData, _data, len * T.sizeof);
        _data = cast(T*)(newData);
    }  
    void free() {
        import core.memory : GC;
        GC.free(_data);
    }  
     
    void clear() {
        len = 0;
    }

    void insertBack(T item) {
        import std.algorithm : max;
        if (len == cap) reserve(max(cap * 2, MINCAP));
        _data[len++] = item;
    }  
    alias opOpAssign(string op : "~") = insertBack;  
    void removeBack() {
        assert(!empty, "StackPayload.removeBack: Stack is empty");
        len--;
    }  
}

 
/* IMPORT /home/yosupo/Program/dunkelheit/source/dkh/graph/dijkstra.d */
// module dkh.graph.dijkstra;

// import dkh.algorithm, dkh.container.radixheap;

struct DijkstraInfo(T) {
    T[] dist;
    int[] from;
    this(int n, T inf) {
        dist = new T[n]; dist[] = inf;
        from = new int[n];
    }
}

DijkstraInfo!D dijkstra(D, T)(T g, int s, D inf = D.max) {
    import std.conv : to;
    import std.typecons : Tuple;
    import std.container : make, Array, heapify;
    import std.container.binaryheap : BinaryHeap;
    import std.traits : isIntegral;

    int V = g.length.to!int;
    auto dijk = DijkstraInfo!D(V, inf);
    with (dijk) {        
        alias P = Tuple!(int, "to", D, "dist");
        auto q = (){
            static if (isIntegral!D) {
                return RadixHeap!(P, "a.dist")();
            } else {
                return heapify!"a.dist>b.dist"(make!(Array!P));
            }
        }();
        q.insert(P(s, D(0)));
        dist[s] = D(0);
        from[s] = -1;
        while (!q.empty) {
            P p = q.front; q.removeFront();
            if (dist[p.to] < p.dist) continue;
            foreach (e; g[p.to]) {
                if (p.dist+e.dist < dist[e.to]) {
                    dist[e.to] = p.dist+e.dist;
                    from[e.to] = p.to;
                    q.insert(P(e.to, dist[e.to]));
                }
            }
        }
    }
    return dijk;
}

DijkstraInfo!D dijkstraDense(D, T)(T g, int s, D inf = D.max) {
    import std.conv : to;
    import std.typecons : Tuple;
    import std.container : make, Array, heapify;
    import std.range : enumerate;
    import std.algorithm : filter;

    int V = g.length.to!int;
    auto dijk = DijkstraInfo!D(V, inf);
    with (dijk) {
        alias P = Tuple!(int, "to", D, "dist");

        bool[] used = new bool[](V);
        dist[s] = D(0);
        from[s] = -1;
        while (true) {
             
            auto rng = dist.enumerate.filter!(a => !used[a.index]);
            if (rng.empty) break;
            auto nx = rng.minimum!"a.value < b.value";
            used[nx.index] = true;
            P p = P(nx.index.to!int, nx.value); 
            if (p.dist == inf) continue;
            foreach (e; g[p.to]) {
                if (p.dist+e.dist < dist[e.to]) {
                    dist[e.to] = p.dist+e.dist;
                    from[e.to] = p.to;
                }
            }
        }
    }
    return dijk;
}

 

 
/* IMPORT /home/yosupo/Program/dunkelheit/source/dkh/algorithm.d */
// module dkh.algorithm;

import std.traits : isFloatingPoint, isIntegral;

 
T binSearch(alias pred, T)(T l, T r) if (isIntegral!T) {
    while (r-l > 1) {
        T md = l + (r-l) / 2;
        if (!pred(md)) l = md;
        else r = md;
    }
    return r;
}

 
T binSearch(alias pred, T)(T l, T r, int cnt = 60) if (isFloatingPoint!T) {
    foreach (i; 0..cnt) {
        T md = (l+r)/2;
        if (!pred(md)) l = md;
        else r = md;
    }
    return r;
}

 
 

import std.range.primitives;

 
E minimum(alias pred = "a < b", Range, E = ElementType!Range)(Range range, E seed)
if (isInputRange!Range && !isInfinite!Range) {
    import std.algorithm, std.functional;
    return reduce!((a, b) => binaryFun!pred(a, b) ? a : b)(seed, range);
}

 
ElementType!Range minimum(alias pred = "a < b", Range)(Range range) {
    assert(!range.empty, "minimum: range must not empty");
    auto e = range.front; range.popFront;
    return minimum!pred(range, e);
}

 
 

 
E maximum(alias pred = "a < b", Range, E = ElementType!Range)(Range range, E seed)
if (isInputRange!Range && !isInfinite!Range) {
    import std.algorithm, std.functional;
    return reduce!((a, b) => binaryFun!pred(a, b) ? b : a)(seed, range);
}

 
ElementType!Range maximum(alias pred = "a < b", Range)(Range range) {
    assert(!range.empty, "maximum: range must not empty");
    auto e = range.front; range.popFront;
    return maximum!pred(range, e);
}

 
 

 
Rotator!Range rotator(Range)(Range r) {
    return Rotator!Range(r);
}

 
struct Rotator(Range)
if (isForwardRange!Range && hasLength!Range) {
    size_t cnt;
    Range start, now;
    this(Range r) {
        cnt = 0;
        start = r.save;
        now = r.save;
    }
    this(this) {
        start = start.save;
        now = now.save;
    }
    @property bool empty() const {
        return now.empty;
    }
    @property auto front() const {
        assert(!now.empty);
        import std.range : take, chain;
        return chain(now, start.take(cnt));
    }
    @property Rotator!Range save() {
        return this;
    }
    void popFront() {
        cnt++;
        now.popFront;
    }
}

 
 

/*
This source code generated by dunkelheit and include dunkelheit's source code.
dunkelheit's Copyright: Copyright (c) 2016- Kohei Morita. (https://github.com/yosupo06/dunkelheit)
dunkelheit's License: MIT License(https://github.com/yosupo06/dunkelheit/blob/master/LICENSE.txt)
*/
