#if 1
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <stack>
#include <array>
#include <deque>
#include <algorithm>
#include <utility>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <numeric>
#include <assert.h>
#include <bitset>
#include <list>
#include <cmath>
#include <queue>
#include <vector>
#include <functional>
#include <utility>
#include <algorithm>
#include <iterator>

auto & in = std::cin;
auto& out = std::cout;
#define all_range(C) std::begin(C), std::end(C)
const double PI = 3.141592653589793238462643383279502884197169399375105820974944;


template<typename T, typename U>
std::enable_if_t<std::rank<T>::value == 0> fill_all(T & arr, const U & v) {
	arr = v;
}
template<typename ARR, typename U>
std::enable_if_t<std::rank<ARR>::value != 0> fill_all(ARR & arr, const U & v) {
	for (auto& i : arr) {
		fill_all(i, v);
	}
}

int32_t N;



using COST_T = uint32_t;
constexpr uint32_t N_MAX = 110000;
constexpr COST_T INF = 310000;//std::numeric_limits<double>::infinity()

#if defined(_MSC_VER) && defined(_DEBUG)
#endif

struct edge {
	std::pair<uint32_t, uint32_t> to;
	COST_T cost;
	edge() {}
	edge(std::pair<uint32_t, uint32_t> to_, COST_T cost_ = 1)
		:to(to_), cost(cost_) {}
};
std::vector<edge> graph[N_MAX][3];

//ダイクストラ
COST_T D[N_MAX][3];
void Dijkstra(uint32_t s)
{
	using P = std::pair<COST_T, std::pair<uint32_t, uint32_t>>;//cost pos
	std::priority_queue<P, std::vector<P>, std::greater<>> que;
	fill_all(D, INF);

	D[s][0] = 0;
	que.push({ 0, { s,0 } });
	while (!que.empty())
	{
		auto p = que.top(); que.pop();
		const auto& nowpos = p.second;
		const auto& nowcost = p.first;
		if (D[nowpos.first][nowpos.second] < nowcost) { continue; }

		//for (int32_t to = 0; to < N; ++to)
		//{
		//	auto cost = nowcost + graph[nowpos][to];
		//	if (cost < D[to]) {
		//		D[to] = cost;
		//		que.emplace(D[to], to);
		//	}
		//}

		for (const auto& e : graph[nowpos.first][nowpos.second])
		{
			auto cost = nowcost + e.cost;
			auto& dd = D[e.to.first][e.to.second];
			if (cost < dd) {
				dd = cost;
				que.emplace(cost, e.to);
			}
		}

	}
}

template<typename T = int_fast32_t>
struct Range {
private:
	using This_T = Range<T>;
	using value_type  = T;
	value_type b, e;
public:
	Range(value_type end) :b(0), e(end) {}
	Range(value_type begin, value_type end):b(begin),e(end){}
	struct iterator {
	public:
		using value_type        = This_T::value_type;
		using pointer           = value_type *;
		using reference         = value_type &;
		using const_reference   = const value_type &;
		using iterator_category = std::input_iterator_tag;
	private:
		value_type i;
		friend This_T;
		constexpr iterator(value_type init)noexcept :i(init) {}
	public:
		constexpr iterator()noexcept :i(){}
		
		constexpr iterator& operator++()noexcept { ++i; return *this; }
		constexpr iterator operator++(int)noexcept { auto tmp = i; ++i; return iterator(tmp); }
		constexpr const_reference operator*() const noexcept { return i; }

		constexpr bool operator==(const iterator& b) const noexcept { return **this == *b; }
		constexpr bool operator!=(const iterator& b) const noexcept { return !((*this) == b); }
	};

	constexpr iterator begin()const noexcept { return iterator(b); }
	constexpr iterator end()const noexcept { return iterator(e); }
};

int main()
{
	using std::endl;
	in.sync_with_stdio(false);
	out.sync_with_stdio(false);
	in.tie(nullptr);
	out.tie(nullptr);
	int M;
	in >> N >> M;

	for (auto& _ : Range<>(M))
	{
		int a, b;
		in >> a >> b; --a; --b;
		for (auto& i : Range<>(3)) {
			graph[a][i].push_back({ { b,(i+1)%3 } });
		}
	}
	int s, t;
	in >> s >> t; --s; --t;
	Dijkstra(s);
	if (D[t][0] == INF) {
		out << "-1\n";
	}
	else {
		assert(D[t][0] % 3 == 0);
		out << D[t][0] / 3 << endl;
	}

	return 0;
}
#endif


Measured memory_bytes: 18688