/+ dub.sdl:
    name "A"
    dependency "dcomp" version=">=0.1.2"
+/

import std.stdio, std.datetime, std.range, std.algorithm, std.conv;
import std.numeric;

// import dcomp.scanner;
// import dcomp.numeric.modint, dcomp.numeric.primitive;
// import dcomp.graph.dfsinfo, dcomp.graph.ariticulation;

alias Mint = ModInt!(10^^9 + 7);

struct Edge {
    int to;
}

immutable int N = 1000;

Mint[] fact, iFac;
static this() {
    fact = new Mint[](N);
    iFac = new Mint[](N);
    fact[0] = Mint(1);
    foreach (i; 1..N) {
        fact[i] = fact[i-1] * Mint(i);
    }
    iFac[N-1] = Mint.inv(fact[N-1]);
    foreach_reverse (i; 0..N-1) {
        iFac[i] = iFac[i+1] * Mint(i + 1);
    }
}

Mint C(int n, int k) {
    if (n < k || n < 0) return Mint(0);
    return fact[n] * iFac[k] * iFac[n-k];
}

Mint cycle(int n, int k) {
    Mint sm = 0;
    foreach (i; 0..n) {
        int gc = gcd(n, i);
        sm += pow(Mint(k), gc);
    }
    return sm / Mint(n);
}

int main(string[] argv) {
    auto sc = new Scanner();
    int n, m, k;
    sc.read(n, m, k);
    Edge[][] g = new Edge[][](n);
    int[2][] edges;
    foreach (i; 0..m) {
        int a, b;
        sc.read(a, b); a--; b--;
        g[a] ~= Edge(b);
        g[b] ~= Edge(a);
        edges ~= [a, b];
    }
    auto info = g.dfsInfo(-1);
    auto arit = g.ariticulation(info);
    
    int[] dps = new int[n];
    foreach (p; info.vlis) {
        foreach (d; info.tr[p]) {
            dps[d] = max(dps[p]+1, dps[d]);
        }
    }

    int[] vc = new int[n]; vc[] = 1;
    int[] ec = new int[n];
    foreach (e; edges) {
        int a = e[0], b = e[1];
        if (dps[a] < dps[b]) swap(a, b);
        ec[a]++;
    }

    Mint ans = 1;
    foreach_reverse (p; info.vlis) {        
        foreach (d; info.tr[p]) {
            vc[p] += vc[d];
            ec[p] += ec[d];
        }
        if (dps[p] == 1 || arit.isDiv[p]) {
//            writeln(vc[p]+1, " ", ec[p]);
            int v = vc[p]+1, e = ec[p];
            if (v > e) {
                ans *= pow(Mint(k), e);
            } else if (v == e) {
                ans *= cycle(v, k);
            } else {
                // e + v-1 C v-1
                ans *= C(e + k-1, k-1);
            }
            vc[p] = 0;
            ec[p] = 0;
        }
    }
    writeln(ans.v);
    return 0;
}
/* IMPORT /Users/yosupo/Program/dcomp/source/dcomp/numeric/primitive.d */
// module dcomp.numeric.primitive;

T pow(T, U)(T x, U n, T e) {
    while (n) {
        if (n & 1) e *= x;
        x *= x;
        n /= 2;
    }
    return e;
}

T pow(T, U)(T x, U n) {
    return pow(x, n, T(1));
}

T lcm(T)(in T a, in T b) {
    import std.numeric : gcd, abs;
    return a / gcd(a,b) * b;
}

//a*T[0]+b*T[1]=T[2], T[2]=gcd
//todo: to binary extgcd
T[3] extGcd(T)(T a, T b) {
    if (b==0) {
        return [1, 0, a];
    } else {
        auto e = extGcd(b, a%b);
        return [e[1], e[0]-a/b*e[1], e[2]];
    }
}
/* IMPORT /Users/yosupo/Program/dcomp/source/dcomp/numeric/modint.d */
// module dcomp.numeric.modint;

// import dcomp.numeric.primitive;

struct ModInt(uint MD) {
    import std.conv : to;
    uint v;
    this(int v) {this.v = (v%MD+MD)%MD;}
    this(long v) {this.v = (v%MD+MD)%MD;}
    auto normS(uint x) {return (x<MD)?x:x-MD;}
    auto make(uint x) {ModInt m; m.v = x; return m;}
    auto opBinary(string op:"+")(ModInt r) {return make(normS(v+r.v));}
    auto opBinary(string op:"-")(ModInt r) {return make(normS(v+MD-r.v));}
    auto opBinary(string op:"*")(ModInt r) {return make((v.to!long*r.v%MD).to!uint);}
    auto opBinary(string op:"/")(ModInt r) {return this*inv(r);}
    auto opOpAssign(string op)(ModInt r) {return mixin ("this=this"~op~"r");}
    static ModInt inv(ModInt x) {return ModInt(extGcd(x.v, MD)[0]);}
    string toString() {return v.to!string;}
}

struct DModInt {
    import std.conv : to;
    uint MD, v;
    this(int v, uint md) {
        MD = md;
        this.v = (v%MD+MD)%MD;
    }
    this(long v, uint md) {
        MD = md;
        this.v = ((v%MD+MD)%MD).to!uint;
    }
    auto normS(uint x) {return (x<MD)?x:x-MD;}
    auto make(uint x) {DModInt m; m.MD = MD; m.v = x; return m;}
    auto opBinary(string op:"+")(DModInt r) {
        assert(MD == r.MD);
        return make(normS(v+r.v));
    }
    auto opBinary(string op:"-")(DModInt r) {
        assert(MD == r.MD);
        return make(normS(v+MD-r.v));
    }
    auto opBinary(string op:"*")(DModInt r) {
        assert(MD == r.MD);
        return make((v.to!long*r.v%MD).to!uint);
    }
    auto opBinary(string op:"/")(DModInt r) {
        assert(MD == r.MD);
        return this*inv(r);
    }
    auto opOpAssign(string op)(DModInt r) {return mixin ("this=this"~op~"r");}
    static DModInt inv(DModInt x) {
        return DModInt(extGcd(x.v, x.MD)[0], x.MD);
    }
    string toString() {return v.to!string;}
}
/* IMPORT /Users/yosupo/Program/dcomp/source/dcomp/scanner.d */
// module dcomp.scanner;

class Scanner {
    import std.stdio : File, stdin;
    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 = stdin) {
        this.f = f;
    }
    string[] buf;
    private bool succ() {
        while (!buf.length) {
            if (f.eof) return false;
            buf = f.readln.split;
        }
        return true;
    }
    private bool readSingle(T)(ref T x) {
        if (!succ()) return false;
        static if (isArray!T) {
            alias E = ElementType!T;
            static if (isSomeChar!E) {
                //string or char[10] etc
                x = buf.front;
                buf.popFront;
            } else {
                static if (isStaticArray!T) {
                    //static
                    assert(buf.length == T.length);
                }
                x = buf.map!(to!E).array;
                buf.length = 0;                
            }
        } else {
            x = buf.front.to!T;
            buf.popFront;            
        }
        return true;
    }
    int read(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);
        }
    }
}

unittest {
    import std.path : buildPath;
    import std.file : tempDir;
    import std.algorithm : equal;
    import std.stdio : File;
    string fileName = buildPath(tempDir, "kyuridenanmaida.txt");
    auto fout = File(fileName, "w");
    fout.writeln("1 2 3");
    fout.writeln("ab cde");
    fout.writeln("1.0 1.0 2.0");
    fout.close;
    Scanner sc = new Scanner(File(fileName, "r"));
    int a;
    int[2] b;
    char[2] c;
    string d;
    double e;
    double[] f;
    sc.read(a, b, c, d, e, f);
    assert(a == 1);
    assert(equal(b[], [2, 3]));
    assert(equal(c[], "ab"));
    assert(equal(d, "cde"));
    assert(e == 1.0);
    assert(equal(f, [1.0, 2.0]));
}
/* IMPORT /Users/yosupo/Program/dcomp/source/dcomp/graph/ariticulation.d */
// module dcomp.graph.ariticulation;

// import dcomp.graph.dfsinfo;

struct Ariticulation {
    bool[] isArit; // is Ariticulation point
    bool[] isDiv; // is Div when parent remove
};

Ariticulation ariticulation(T)(T g) {
    return ariticulation(g, dfsInfo(g, -1));
}

Ariticulation ariticulation(T)(T g, DFSInfo info) {
    Ariticulation arit;
    size_t V = g.length;
    arit.isArit.length = V;
    arit.isDiv.length = V;
    foreach (p ; info.vlis) {
        if (info.par[p] == -1) {
            //root
            arit.isArit[p] = (info.tr[p].length >= 2);
            foreach (d; info.tr[p]) {
                arit.isDiv[d] = true;
            }
        } else {
            arit.isArit[p] = false;
            foreach (d; info.tr[p]) {
                if (info.low[d] >= info.ord[p]) {
                    arit.isArit[p] = true;
                    arit.isDiv[d] = true;
                }
            }
        }
    }    
    return arit;
}
/* IMPORT /Users/yosupo/Program/dcomp/source/dcomp/graph/dfsinfo.d */
// module dcomp.graph.dfsinfo;

struct DFSInfo {
    int r;
    int[] low, ord, par, vlis; //low, ord, parent, visitList
    int[][] tr; //dfs tree
}

DFSInfo dfsInfo(T)(T g, int r) {
    import std.algorithm : min;
    import std.conv : to;
    const size_t V = g.length;
    DFSInfo info;
    info.r = r;
    info.low.length = V;
    info.ord.length = V;
    info.par.length = V;
    info.tr.length = V;
    
    int co = 0;
    bool[] used = new bool[](V);
    void dfs(int p, int b) {
        used[p] = true;
        bool rt = true;
        info.low[p] = info.ord[p] = co++;
        info.par[p] = b;
        info.vlis ~= p; //optimize?

        foreach (e; g[p]) {
            int d = e.to;
            if (rt && d == b) {
                rt = false;
                continue;
            }
            if (!used[d]) {
                info.tr[p] ~= d;
                dfs(d, p);
                info.low[p] = min(info.low[p], info.low[d]);
            } else {
                info.low[p] = min(info.low[p], info.ord[d]);
            }
        }
    }
        
    if (r != -1) {
        dfs(r, -1);
    } else {
        foreach (i; 0..V) {
            if (used[i]) continue;
            dfs(i.to!int, -1);
        }
    }
    return info;
}
