#![allow(unused_imports)]
use std::cmp::{self, Ord, Ordering};
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};

#[derive(PartialEq, Eq, Debug)]
struct Rev<T>(T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Self) -> Ordering {
        other.0.cmp(&self.0)
    }
}

fn main() {
    let stdin = std::io::stdin();
    let mut sc = nyan::Scanner::new(stdin.lock());

    let n: usize = sc.read();
    let m: usize = sc.read();

    let expand = 3;

    // s -> g[s] に辺がある
    let mut g = vec![Vec::new(); n * expand];
    for _ in 0..m {
        let u: usize = sc.read();
        let v: usize = sc.read();
        for s in 0..expand {
            let t = if s == expand - 1 { 0 } else { s + 1 };
            g[(u - 1) * expand + s].push((v - 1) * expand + t);
        }
    }
    let g = g;

    let s: usize = sc.read();
    let s = (s - 1) * expand;
    let t: usize = sc.read();
    let t = (t - 1) * expand;

    // println!("{:?}", g);

    // d[i] = s -> i の最短距離
    let mut d = vec![None; n * expand];
    d[s + 0] = Some(0);

    let mut q = VecDeque::new(); // (d, v)
    q.push_back(Rev((0, s + 0)));

    while let Some(Rev((d_su, u))) = q.pop_front() {
        let d_suu = d[u].unwrap();
        if d_su > d_suu {
            continue;
        }

        for &v in &g[u] {
            d[v] = d[v].or(Some(1_000_000_007)).map(|d_svv| {
                if d_svv > d_suu + 1 {
                    q.push_back(Rev((d_suu + 1, v)));
                    d_suu + 1
                } else {
                    d_svv
                }
            });
        }
    }

    if let Some(v) = d[t] {
        println!("{}", v / 3);
    } else {
        println!("{}", -1);
    }
}

#[allow(dead_code)]
mod nyan {
    use std::cmp;
    use std::fmt::Debug;
    use std::io::Read;
    use std::iter::FromIterator;
    use std::str::FromStr;

    pub struct Scanner<R: Read> {
        reader: R,
    }

    impl<R: Read> Scanner<R> {
        pub fn new(reader: R) -> Scanner<R> {
            Scanner { reader: reader }
        }

        fn chars<'a>(&'a mut self) -> Box<Iterator<Item = char> + 'a> {
            Box::new(self.reader.by_ref().bytes().map(|b| b.unwrap() as char))
        }

        // since Rust 1.26
        // fn chars<'a>(&'a mut self) -> impl Iterator<Item = char> + 'a {
        //     self.reader.by_ref().bytes().map(|b| b.unwrap() as char)
        // }

        pub fn next<T: FromIterator<char>>(&mut self) -> T {
            self.chars()
                .skip_while(|c| c.is_whitespace())
                .take_while(|c| !c.is_whitespace())
                .collect()
        }

        pub fn next_line<T: FromIterator<char>>(&mut self) -> T {
            self.chars()
                .skip_while(|c| c.is_whitespace())
                .take_while(|c| !c.is_whitespace() || c == &' ')
                .collect()
        }

        pub fn read<T>(&mut self) -> T
        where
            T: FromStr,
            <T as FromStr>::Err: Debug,
        {
            self.next::<String>().parse().unwrap()
        }

        pub fn read_vec<T, U>(&mut self, n: usize) -> T
        where
            T: FromIterator<U>,
            U: FromStr,
            <U as FromStr>::Err: Debug,
        {
            (0..n).map(|_| self.read()).collect()
        }

        pub fn read_vec2d<T, U, V>(&mut self, m: usize, n: usize) -> T
        where
            T: FromIterator<U>,
            U: FromIterator<V>,
            V: FromStr,
            <V as FromStr>::Err: Debug,
        {
            (0..m).map(|_| self.read_vec(n)).collect()
        }

        pub fn read_line<T: FromIterator<char>>(&mut self) -> T {
            self.next_line()
        }

        pub fn read_lines<T, U>(&mut self, n: usize) -> T
        where
            T: FromIterator<U>,
            U: FromIterator<char>,
        {
            (0..n).map(|_| self.read_line()).collect()
        }
    }

    pub fn gcd(a: u64, b: u64) -> u64 {
        if b == 0 {
            a
        } else {
            gcd(b, a % b)
        }
    }

    // Extended Euclidean algorithm
    // ax + by = gcd(x, y)
    pub fn extended_gcd(a: u64, b: u64) -> (u64, i64, i64) {
        if b == 0 {
            (a, 1, 0)
        } else {
            let (m, y, x) = extended_gcd(b, a % b);
            (m, x, y - (a / b) as i64 * x)
        }
    }

    pub fn lcm(a: u64, b: u64) -> u64 {
        (a * b) / gcd(a, b)
    }

    pub struct UnionFind {
        n: usize,
        root: Vec<usize>,
        rank: Vec<usize>,
        size: Vec<usize>,
    }

    impl UnionFind {
        pub fn new(n: usize) -> UnionFind {
            UnionFind {
                n: n,
                root: (0..n).collect(),
                rank: vec![0; n],
                size: vec![1; n],
            }
        }

        pub fn root(&mut self, x: usize) -> usize {
            let r = self.root[x];
            if r == x {
                r
            } else {
                self.root[x] = self.root(r);
                self.root[x]
            }
        }

        pub fn merge(&mut self, x: usize, y: usize) {
            let rx = self.root(x);
            let ry = self.root(y);
            if rx == ry {
                return;
            }

            if self.rank[rx] < self.rank[ry] {
                self.root[rx] = ry;
                self.size[ry] += self.size[rx];
            } else {
                self.root[ry] = rx;
                self.size[rx] += self.size[ry];
                if self.rank[rx] == self.rank[ry] {
                    self.rank[rx] += 1;
                }
            }
        }

        pub fn size(&mut self, x: usize) -> usize {
            let rx = self.root(x);
            self.size[rx]
        }
    }
}


Measured memory_bytes: 24956