#include <cmath>
#include <cstdio>
#include <vector>
#include <iterator>
#include <iostream>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stdio.h>
#include <functional>
#include <chrono>
using namespace std;

#define rep(i,s,n) for(ll i=s;i<(n);++i)
using ll = long long;
using pll = pair<ll, ll>;
constexpr ll INF = (1LL << 60);
constexpr ll MAX_INF = 9223372036854775807;
//constexpr ll MOD = (1e9 + 7);
constexpr ll MOD = (998244353);

using vl = vector<ll>;
using vvl = vector<vector<ll>>;

template<class T>
vector<vector<T>> vvt(T init, ll m, ll n) {
	vector<vector<T>> ans = vector<vector<T>>(m, vector<T>(n, init));
	return move(ans);
}

template<class T>
vector<T> vt(T init, ll n) {
	vector<T> ans = vector<T>(n, init);
	return move(ans);
}

template<class T>
T maxVec(vector<T>& v) {
	T ans = -INF;
	rep(i, 0, v.size()) {
		ans = max(ans, v[i]);
	}
	return ans;
}

// 素数判定
bool judge(ll n) {
	for (ll i = 2; i * i <= n; i++) if (n %= i)return false;
	return true;
}


template <class C>
void print(const C & c, std::ostream & os = std::cout)
{
	std::copy(std::begin(c), std::end(c), std::ostream_iterator<typename C::value_type>(os, ", "));
	os << std::endl;
}
/*
ll count(ll n,ll r) {
	ll ans = 0,check = 1;
	rep(i,0, r) {
		if ((n & check) > 0) {
			ans++;
		}
		check = check << 1;
	}
	return ans;
}
*/
bool sortreverse(ll a, ll b) {
	return a > b;
}


ll kiriage(ll a, ll b) {
	if (a % b == 0)return a / b;
	return a / b + 1;
}

ll n, m, t, q, s,k,h,w,x,y;

void warshall_floyd(ll v_num,vector<vector<long long>> &d) {
	for (long long k = 0; k < v_num; k++) {       // 経由する頂点
		for (long long i = 0; i < v_num; i++) {    // 始点
			for (long long j = 0; j < v_num; j++) {  // 終点
				d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
			}
		}
	}
}

// グラフは<頂点,コスト>
void Dijkstra(ll v, vector<vector<pll>> graph, ll s, vl& ans) {
	auto comp = [](const pll a, const pll b) { return a.first > b.first; };
	priority_queue<pll, vector<pll>, decltype(comp)> que(comp);
	ans = vl(v, INF);
	ans[s] = 0;
	que.push(pll{ 0, s });
	pll a;
	while (!que.empty()) {
		ll c = que.top().first, p = que.top().second;
		que.pop();
		rep(i, 0, graph[p].size()) {
			a = graph[p][i];
			if (ans[a.first] > a.second + c) {
				ans[a.first] = a.second + c;
				que.push(pll{ a.second + c,a.first });
			}
		}
	}
}
ll r, l;

ll kosu(ll yakusu) {
	if (yakusu == 0)return l - r + 1;
	return r - l + 1 - r / yakusu + (l - 1) / yakusu;
}

ll gcd(ll a, ll b) {
	if (a == 0 || b == 0)return a + b;
	if (a < b) return gcd(b, a);
	ll r;
	while ((r = a % b)) {
		a = b;
		b = r;
	}
	return b;
}

ll lcm(ll a, ll b) {
	return a * b / gcd(a, b);
}


ll solv(vvl& dp, ll x, ll y) {
	//printf("%lld %lld\n", x, y);
	if (dp[x][y] >= 0){
		return dp[x][y];
	}
	
	ll x_ = (solv(dp, x - 1, y) * y) % MOD;
	ll y_ = (solv(dp, x, y - 1) * x) % MOD;

	ll ref = (x_ + y_) % MOD;


	ref %= MOD;
	ref += MOD;
	ref -= ((((x - 1) * (y - 1)) % MOD) * solv(dp, x - 1, y - 1)) % MOD;

	ref %= MOD;
	dp[x][y] = ref;

	return ref;
}


int main() {
	// ↓この２行が追加部分
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	
	ll a, b, c, d;
	cin >> a >> b >> c >> d;
	vvl dp(3001, vl(3001,-1));

	rep(i, 0, 3001) {
		rep(j, 0, 3001) {
			if (i < a || j < b) {
				dp[i][j] = 0;
			}
		}
	}
	dp[a][b] = 1;
	printf("%lld\n", solv(dp,c, d));
}

Measured memory_bytes: 74064