/*author* Priyanshu Shrivastav (from IIT Palakkad) *
 * *_ __ ___  _ ______ ___  _ ____   ___  ___| |_  *
 * | '_ ` _ \| '__/ __/ _ \| '_ \ \ / / |/ __| __| *
 * | | | | | | | | (_| (_) | | | \ V /| | (__| |_  *
 * |_| |_| |_|_|(_)___\___/|_| |_|\_/ |_|\___|\__| *
When I wrote this, only God and I understood what I was doing
 ** * * * * * * * Now, only God knows * * * * * * */
#include         <bits/stdc++.h>
using namespace std;
#pragma GCC      optimize ("Ofast")
#pragma GCC      optimize ("unroll-loops")
#pragma GCC      target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

#define IOS      ios_base::sync_with_stdio(false); cin.tie (nullptr)
#define PREC     cout.precision (10); cout << fixed
#define bg(x)    " [ " << #x << " : " << (x) << " ] "
#define x        first
#define y        second
using ll = long long;
using ff = long double;
using pii = pair<int,int>;

#define debug(args...) { \
   /* WARNING : do NOT compile this debug func calls with following flags: // \
    * // -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_FORTIFY_SOURCE=2*/ \
   string _s = #args; replace(_s.begin(), _s.end(), ',', ' ');\
   stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); \
}
void err(istream_iterator<string> it) { it->empty();
   cerr << " (Line : " << __LINE__ << ")" << '\n';
}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
   cerr << fixed << setprecision(15) << " [ " <<  *it << " : " << a  << " ] "<< ' ';
   err(++it, args...);
}

const int MOD = (int)1e9 + 7;
const int N = 3004;
string s;
int n;
int dp[N][N];
int pref[N];

inline int add (int a, int b) {
   return (a + b)%MOD;
}

// dp[len][end] := no. of valid permutations of length 'len' such that
// permutation ends at 'end'
// dp is based upon some bijections
// permutation in this case mostly tells about the relative ordering
// of elements, so while inserting new elements some shift operations
// can be done to keep the order intact
//
// if (s[i] == '>')
// dp[i][j] -> Now we have to see how many ways can we end at j
// seeing from dp[i-1][k], if (k < j) it's not possible
// k == j, we can increase all elements in the permutation of dp[i-1][k] which
// are less than equal to k by 1, and put up j at last, so it counts
// if (k > j) it is always possible
//
//
// if (s[i] == '<')
// dp[i][j] -> again we have to see how many ways we can end at  j
// seeing from dp[i-1][k]
// if (k > j) we cannot use
// if (k == j) we cannot use like last time since after increasing k by 1
// // k + 1 will be > j but we want <
// if (k < j) not possible

void solve()
{
   // or dp[1][1] = 1;
   s = "##" + s; // for better indexing
   for (int i = 1; i <= n; ++i)
      dp[1][i] = 1;

   for (int i = 2; i <= n; ++i) {
      pref[0] = 0;
      for (int j = 1; j <= n; ++j)
         pref[j] = add(pref[j-1], dp[i-1][j]);

      for (int j = 1; j <= n; ++j) {
         dp[i][j] = 0;
         if (s[i] == '>')
            dp[i][j] = (pref[i-1] - pref[j-1] + MOD) % MOD;
         else
            dp[i][j] = pref[j-1];
      }
   }
   int total = 0;
   for (int i = 1; i <= n; ++i)
      total = add(total, dp[n][i]);
   cout << total << '\n';
}

signed main()
{
   IOS; PREC;
   cin >> n;
   cin >> s;
   assert(n - 1 == (int)s.size());
   solve();

   return EXIT_SUCCESS;
}


Measured memory_bytes: 35456