fn getline() -> String {
    let mut res = String::new();
    std::io::stdin().read_line(&mut res).ok();
    res
}

#[allow(unused_macros)]
macro_rules! readl {
    ($t: ty) => {
        {
            let s = getline();
            s.trim().parse::<$t>().unwrap()
        }
    };
    ($( $t: ty),+ ) => {
        {
            let s = getline();
            let mut iter = s.trim().split(' ');
            ($(iter.next().unwrap().parse::<$t>().unwrap(),)*)
        }
    };
}

#[allow(unused_macros)]
macro_rules! readlvec {
    ($t: ty) => {
        {
            let s = getline();
            let iter = s.trim().split(' ');
            iter.map(|x| x.parse().unwrap()).collect::<Vec<$t>>()
        }
    }
}

#[allow(unused_macros)]
macro_rules! debug {
    ($x: expr) => {
        println!("{}: {:?}", stringify!($x), $x)
    }
}

fn printiter<'a, T>(v: &'a T)
where
    &'a T: std::iter::IntoIterator,
    <&'a T as std::iter::IntoIterator>::Item: std::fmt::Display,
{
    for (i, e) in v.into_iter().enumerate() {
        if i != 0 {
            print!(" ");
        }
        print!("{}", e);
    }
    println!("");
}


#[allow(unused_imports)]
use std::cmp::{min, max};
#[allow(unused_imports)]
use std::collections::{BinaryHeap, BTreeMap, HashMap, HashSet};
#[allow(unused_imports)]
use std::collections::btree_map::Entry::{Occupied, Vacant};

use std::cmp::Ordering;
use std::clone::Clone;
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
struct Edge<Cost>
where
    Cost: std::clone::Clone,
{
    to: usize,
    cost: Cost,
}

impl<Cost> Ord for Edge<Cost>
where
    Cost: Ord + std::clone::Clone,
{
    fn cmp(&self, other: &Edge<Cost>) -> Ordering {
        (self.cost).cmp(&(other.cost)).reverse()
    }
}

impl<Cost> PartialOrd for Edge<Cost>
where
    Cost: std::clone::Clone,
    Edge<Cost>: Ord,
{
    fn partial_cmp(&self, other: &Edge<Cost>) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

trait Graph
where
    Self::Cost: Clone
{
    type Cost;
    fn len(&self) -> usize;
    fn get<'a>(&'a self, p: usize) -> std::slice::Iter<'a, Edge<Self::Cost>>;
    fn get_order(&self) -> Vec<usize>;
}

#[derive(Clone, Debug, Hash)]
struct AdjList<Cost: Clone> {
    adj: Vec<Vec<Edge<Cost>>>,
}

impl<Cost: Clone> std::ops::Index<usize> for AdjList<Cost> {
    type Output = Vec<Edge<Cost>>;

    fn index(&self, i: usize) -> &Vec<Edge<Cost>> {
        &self.adj[i]
    }
}

impl<Cost: Clone> std::ops::IndexMut<usize> for AdjList<Cost> {
    fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut Vec<Edge<Cost>> {
        &mut self.adj[i]
    }
}

impl<Cost: Clone> AdjList<Cost> {
    fn new(n: usize) -> AdjList<Cost> {
        AdjList {
            adj: vec![vec![]; n],
        }
    }

    fn add_edge(&mut self, from: usize, to_: usize, cost_: Cost) {
        self.adj[from].push(Edge {
            to: to_,
            cost: cost_,
        });
    }

    fn add_uedge(&mut self, from: usize, to_: usize, cost_: Cost) {
        self.add_edge(from, to_, cost_.clone());
        self.add_edge(to_, from, cost_);
    }
}

impl<Cost> Graph for AdjList<Cost>
where
    Cost: Clone
{
    type Cost = Cost;

    fn len(&self) -> usize {
        self.adj.len()
    }

    fn get<'a>(&'a self, p: usize) -> std::slice::Iter<'a, Edge<Cost>> {
        self.adj[p].iter()
    }

    fn get_order(&self) -> Vec<usize> {
        let mut res = Vec::with_capacity(self.len());
        let mut deg = vec![0; self.len()];
        let mut used = vec![false; self.len()];
        for from in 0..self.len() {
            for e in self.get(from) {
                deg[e.to] += 1;
            }
        }
        for s in 0..self.len() {
            if deg[s] != 0 || used[s] {
                continue;
            }
            let mut stack = Vec::new();
            used[s] = true;
            stack.push(s);
            while let Some(p) = stack.pop() {
                used[p] = true;
                res.push(p);
                for e in self.get(p) {
                    deg[e.to] -= 1;
                    if deg[e.to] == 0 {
                        stack.push(e.to);
                    }
                }
            }

        }
        // debug!(deg);
        res
    }
}

trait Zero {
    fn zero() -> Self;
}

impl Zero for i64 {
    fn zero() -> i64 {
        0
    }
}

trait Max {
    fn max_value() -> Self;
}

impl Max for i64 {
    fn max_value() -> i64 {
        std::i64::MAX
    }
}

trait GraphHavingOrderedCost: Graph
where
    Self::Cost: Ord + Add<Self::Cost, Output = Self::Cost> + Zero + Max + Copy,
{
    fn get_shortest_path(&self, from: usize) -> (Vec<Self::Cost>, Vec<usize>);
    fn get_shortest_path_graph(&self, dist: &Vec<Self::Cost>) -> AdjList<Self::Cost>;
}

use std::ops::Add;
impl<T> GraphHavingOrderedCost for T
where
    T: Graph,
    T::Cost: Ord + Add<T::Cost, Output = T::Cost> + Zero + Max + Copy,
    Edge<T::Cost>: Ord,
{
    fn get_shortest_path(&self, from: usize) -> (Vec<Self::Cost>, Vec<usize>) {
        let n = self.len();

        let mut dist = vec![Self::Cost::max_value(); n];
        let mut pre = vec![n as usize; n];
        let mut heap = std::collections::BinaryHeap::new();
        heap.push(Edge {
            to: from,
            cost: Self::Cost::zero(),
        });
        dist[from] = Self::Cost::zero();
        while let Some(p) = heap.pop() {
            for e in self.get(p.to) {
                if p.cost + e.cost >= dist[e.to] {
                    continue;
                }
                heap.push(Edge {
                    to: e.to,
                    cost: p.cost + e.cost,
                });
                dist[e.to] = p.cost + e.cost;
                pre[e.to] = p.to;
            }
        }
        (dist, pre)
    }

    fn get_shortest_path_graph(&self, dist: &Vec<Self::Cost>) -> AdjList<Self::Cost> {
        let n = self.len();

        let mut res = AdjList::new(n);
        for from in 0..n {
            for e in self.get(from) {
                if dist[from] + e.cost == dist[e.to] {
                    res.add_edge(from, e.to, e.cost);
                }
            }
        }
        res
    }
}


macro_rules! make_modint {
    ($MOD: expr, $name: ident) => {
        #[derive(Ord, Hash, Eq, PartialOrd, PartialEq)]
        struct $name {
            val: i64,
        }

        impl $name {
            fn new(x: i64) -> $name {
                let x = x%$MOD;
                $name{val: if x < 0 { x+$MOD } else { x }}
            }

            fn pow(&self, x: i64) -> $name {
                let mut res = $name::new(1);
                let mut tmp = x;
                let mut p = *self;
                while tmp != 0 {
                    if tmp&1 == 1 {
                        res *= p;
                    }
                    tmp = tmp>>1;
                    p = p*p;
                }
                res
            }

            fn inv(&self) -> $name {
                assert!(self.val != 0);
                let mut a = self.val;
                let mut b = $MOD;
                let mut u = 1;
                let mut v = 0;
                use std::mem::swap;
                while b != 0 {
                    let t = a/b;
                    a -= t*b;
                    swap(&mut a, &mut b);
                    u -= t*v;
                    swap(&mut u, &mut v);
                }
                $name::new(u)
            }
        }

        impl std::clone::Clone for $name {
            fn clone(&self) -> $name {
                $name{ val: self.val }
            }
        }

        impl std::marker::Copy for $name { }

        impl std::ops::Add for $name {
            type Output = $name;
            fn add(self, y: $name) -> $name {
                let tmp = self.val+y.val;
                $name{val: if tmp >= $MOD {tmp-$MOD} else {tmp}}
            }
        }

        impl std::ops::Neg for $name {
            type Output = $name;
            fn neg(self) -> $name {
                $name::new(self.val)
            }
        }

        impl std::ops::Sub for $name {
            type Output = $name;
            fn sub(self, other: $name) -> $name{
                let tmp = self.val-other.val;
                $name{val: if tmp < 0 {tmp+$MOD} else {tmp}}
            }
        }

        impl std::ops::Mul for $name {
            type Output = $name;
            fn mul(self, y: $name) -> $name {
                $name{val: (self.val*y.val)%$MOD}
            }
        }

        impl std::ops::Div for $name {
            type Output = $name;
            fn div(self, other: $name) -> $name {
                self*other.inv()
            }
        }

        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(f, "{}", self.val)
            }
        }

        impl std::ops::AddAssign for $name {
        fn add_assign(&mut self, other: $name) {
            *self = *self+other;
        }
        }

        impl std::ops::SubAssign for $name {
            fn sub_assign(&mut self, other: $name) {
                *self = *self-other;
            }
        }

        impl std::ops::MulAssign for $name {
            fn mul_assign(&mut self, other: $name) {
                *self = *self*other;
            }
        }

        impl std::ops::DivAssign for $name {
            fn div_assign(&mut self, other: $name) {
                *self = *self*other.inv();
            }
        }

        impl std::fmt::Debug for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(f, "{}", self.val)
            }
        }
    }
}

make_modint!(1_000_000_000 + 7, ModInt);

fn mint(x: i64) -> ModInt {
    ModInt::new(x)
}


use std::io::prelude::*;
impl<Cost: Clone> AdjList<Cost> {
    fn vizualize(&self, name: &str) {
        let path = std::path::Path::new("tmp.dot");
        {
            let mut file = std::fs::File::create(path).unwrap();
            let n = self.len();
            file.write_all("digraph graph_name {\n".as_bytes()).unwrap();
            for p in 0..n {
                let s = ["    ".to_string(), p.to_string(), "[];\n".to_string()].connect("");
                file.write_all(s.as_bytes()).unwrap();
            }
            for p in 0..n {
                for e in &self[p] {
                    file.write_all(b"    ").unwrap();
                    file.write_all(p.to_string().as_bytes()).unwrap();
                    file.write_all(b" -> ").unwrap();
                    file.write_all(e.to.to_string().as_bytes()).unwrap();
                    file.write_all(b"\n").unwrap();
                }
            }
            file.write(b"}\n").unwrap();
        }
        let mut cmd = std::process::Command::new("dot");
        cmd.arg("-T");
        cmd.arg("png");
        cmd.arg("tmp.dot");
        cmd.arg("-o");
        cmd.arg(name);
        cmd.status().expect("commend failed to start");
    }
}


fn main() {
    use std::io::Write;
    let out = std::io::stdout();
    let mut out = std::io::BufWriter::new(out.lock());
    macro_rules! printf { ($($arg:tt)*) => (write!(out, $($arg)*).unwrap()); }
    macro_rules! printfln { () => (writeln!(out).unwrap()); ($($arg:tt)*) => (writeln!(out, $($arg)*).unwrap()); }
    let (n, m) = readl!(usize, usize);
    let (s, t) = readl!(usize, usize);
    let s = s-1;
    let t = t-1;
    let mut g = AdjList::new(n);
    for _ in 0..m {
        let (u, v, d) = readl!(usize, usize, i64);
        g.add_uedge(u-1, v-1, d);
    }
    let g = g;
    
    let (ds, _) = g.get_shortest_path(s);
    let gs = g.get_shortest_path_graph(&ds);

    let (dt, _) = g.get_shortest_path(t);
    let gt = g.get_shortest_path_graph(&dt);
    
    let mut dps = vec![mint(0); n];
    dps[s] = mint(1);
    for p in gs.get_order() {
        for e in gs.get(p) {
            dps[e.to] += dps[p];
        }
    }
    // gs.vizualize("2.png");
    let dps = dps;
    // debug!(dps);

    let mut dpt = vec![mint(0); n];
    dpt[t] = mint(1);
    for p in gt.get_order() {
        // debug!(p);
        for e in gt.get(p) {
            dpt[e.to] += dpt[p];
        }
    }
    // gt.vizualize("3.png");
    let dpt = dpt;
    // debug!(dpt);

    let mut ans = dps[t]*dps[t];
    let d = ds[t];
    for from in 0..n {
        for e in gs.get(from) {
            if 2*ds[from] < d && d < 2*(d-dt[e.to]) && ds[from]+e.cost+dt[e.to] == d {
                let t = dps[from]*dpt[e.to];
                ans -= t*t;
            }
        }
    }
    for v in 0..n {
        if ds[v] == dt[v] {
            let t = dps[v]*dpt[v];
            ans -= t*t;
        }
    }
    printfln!("{}", ans);
}


Measured memory_bytes: 43260