// Original C++ solution (slower):
#include<bits/stdc++.h>



using namespace std;



using int64 = long long;

const int mod = 1e9 + 7;

const int inf = (1 << 30) - 1;

const int64 infll = (1LL << 61) - 1;



struct IoSetup {

  IoSetup() {

    cin.tie(nullptr);

    ios::sync_with_stdio(false);

    cout << fixed << setprecision(10);

    cerr << fixed << setprecision(10);

  }

} iosetup;



template< typename T >

ostream &operator<<(ostream &os, const vector< T > &v) {

  for(int i = 0; i < (int) v.size(); i++) {

    os << v[i] << (i + 1 != v.size() ? " " : "");

  }

  return os;

}



template< typename T >

istream &operator>>(istream &is, vector< T > &v) {

  for(T &in : v) is >> in;

  return is;

}



template< typename T1, typename T2 >

inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }



template< typename T1, typename T2 >

inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }



template< typename T = int64 >

vector< T > make_v(size_t a) {

  return vector< T >(a);

}



template< typename T, typename... Ts >

auto make_v(size_t a, Ts... ts) {

  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));

}



template< typename T, typename V >

typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {

  t = v;

}



template< typename T, typename V >

typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {

  for(auto &e : t) fill_v(e, v);

}



template< int char_size >

struct TrieNode {

  int nxt[char_size + 1];



  int exist; // 子ども以下に存在する文字列の数の合計

  vector< int > accept; // その文字列id



  TrieNode() : exist(0) {

    memset(nxt, -1, sizeof(nxt));

  }

};



template< int char_size, int margin >

struct Trie {

  using Node = TrieNode< char_size >;



  vector< Node > nodes;

  int root;



  Trie() : root(0) {

    nodes.push_back(Node());

  }



  virtual void direct_action(int node, int id) {}



  virtual void child_action(int node, int child, int id) {}



  void update_direct(int node, int id) {

    nodes[node].accept.push_back(id);

    direct_action(node, id);

  }



  void update_child(int node, int child, int id) {

    ++nodes[node].exist;

    child_action(node, child, id);

  }



  void add(const string &str, int str_index, int node_index, int id) {

    if(str_index == str.size()) {

      update_direct(node_index, id);

    } else {

      const int c = str[str_index] - margin;

      if(nodes[node_index].nxt[c] == -1) {

        nodes[node_index].nxt[c] = (int) nodes.size();

        nodes.push_back(Node());

      }

      add(str, str_index + 1, nodes[node_index].nxt[c], id);

      update_child(node_index, nodes[node_index].nxt[c], id);

    }

  }



  void add(const string &str, int id) {

    add(str, 0, 0, id);

  }



  void add(const string &str) {

    add(str, nodes[0].exist);

  }



  void query(const string &str, const function< void(int) > &f, int str_index, int node_index) {

    for(auto &idx : nodes[node_index].accept) f(idx);

    if(str_index == str.size()) {

      return;

    } else {

      const int c = str[str_index] - margin;

      if(nodes[node_index].nxt[c] == -1) return;

      query(str, f, str_index + 1, nodes[node_index].nxt[c]);

    }

  }



  void query(const string &str, const function< void(int) > &f) {

    query(str, f, 0, 0);

  }



  int size() const {

    return (nodes[0].exist);

  }



  int nodesize() const {

    return ((int) nodes.size());

  }

};



template< int char_size, int margin >

struct AhoCorasick : Trie< char_size, margin > {

  using TRIE = Trie< char_size, margin >;

  static const int FAIL = char_size;

  vector< int > correct;



  AhoCorasick() : TRIE() {}



  void build(bool heavy = true) {

    correct.resize(TRIE::nodes.size());

    for(int i = 0; i < TRIE::nodes.size(); i++) {

      correct[i] = (int) TRIE::nodes[i].accept.size();

    }



    queue< int > que;

    for(int i = 0; i <= char_size; i++) {

      if(~TRIE::nodes[0].nxt[i]) {

        TRIE::nodes[TRIE::nodes[0].nxt[i]].nxt[FAIL] = 0;

        que.emplace(TRIE::nodes[0].nxt[i]);

      } else {

        TRIE::nodes[0].nxt[i] = 0;

      }

    }

    while(!que.empty()) {

      TrieNode< char_size > &now = TRIE::nodes[que.front()];

      correct[que.front()] += correct[now.nxt[FAIL]];

      que.pop();

      for(int i = 0; i < char_size; i++) {

        if(now.nxt[i] == -1) continue;

        int fail = now.nxt[FAIL];

        while(TRIE::nodes[fail].nxt[i] == -1) fail = TRIE::nodes[fail].nxt[FAIL];

        TRIE::nodes[now.nxt[i]].nxt[FAIL] = TRIE::nodes[fail].nxt[i];

        if(heavy) {

          auto &u = TRIE::nodes[now.nxt[i]].accept;

          auto &v = TRIE::nodes[TRIE::nodes[fail].nxt[i]].accept;

          vector< int > accept;

          set_union(begin(u), end(u), begin(v), end(v), back_inserter(accept));

          u = accept;

        }

        que.emplace(now.nxt[i]);

      }



    }

  }



  int match(const string &str, vector< int > &result, int now = 0) {

    result.assign(TRIE::size(), 0);

    int count = 0;

    for(auto &c : str) {

      while(TRIE::nodes[now].nxt[c - margin] == -1) now = TRIE::nodes[now].nxt[FAIL];

      now = TRIE::nodes[now].nxt[c - margin];

      count += correct[now];

      for(auto &v : TRIE::nodes[now].accept) ++result[v];

    }

    return (count);

  }



  int move(const char &c, int &now) {

    int count = 0;

    while(TRIE::nodes[now].nxt[c - margin] == -1) now = TRIE::nodes[now].nxt[FAIL];

    now = TRIE::nodes[now].nxt[c - margin];

    count += correct[now];

    return (count);

  }

};



vector< string > u;



void make(string s) {

  if(s.size() >= 3) {

    bool f = s.find("AGC") != string::npos;

    for(int i = 0; i + 1 < s.size(); i++) {

      swap(s[i], s[i + 1]);

      f |= s.find("AGC") != string::npos;

      swap(s[i], s[i + 1]);

    }

    if(f) {

      u.emplace_back(s);

    }

    if(s.size() >= 5) return;

  }

  make(s + "A");

  make(s + "G");

  make(s + "C");

  make(s + "T");

}



int main() {

  make("");

  AhoCorasick< 26, 'A' > aho;

  for(auto &p : u) aho.add(p);

  aho.build();

  int N;

  cin >> N;

  vector< int > dp(505);

  dp[0] = 1;

  for(int i = 0; i < N; i++) {

    vector< int > dp2(505);

    for(int j : string("AGCT")) {

      for(int k = 0; k < dp.size(); k++) {

        if(dp[k]) {

          int c = k;

          if(aho.move(j, c)) continue;

          dp2[c] += dp[k];

          dp2[c] %= mod;

        }

      }

    }

    dp.swap(dp2);

  }



  cout << accumulate(begin(dp), end(dp), 0LL) % mod << endl;

}




// Optimized solution to the same problem (faster):
#include<bits/stdc++.h>



using namespace std;



using int64 = long long;

const int mod = 1e9 + 7;

const int inf = (1 << 30) - 1;

const int64 infll = (1LL << 61) - 1;



struct IoSetup {

  IoSetup() {

    cin.tie(nullptr);

    ios::sync_with_stdio(false);

    cout << fixed << setprecision(10);

    cerr << fixed << setprecision(10);

  }

} iosetup;



template< typename T >

ostream &operator<<(ostream &os, const vector< T > &v) {

  for(int i = 0; i < (int) v.size(); i++) {

    os << v[i] << (i + 1 != v.size() ? " " : "");

  }

  return os;

}



template< typename T >

istream &operator>>(istream &is, vector< T > &v) {

  for(T &in : v) is >> in;

  return is;

}



template< typename T1, typename T2 >

inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }



template< typename T1, typename T2 >

inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }



template< typename T = int64 >

vector< T > make_v(size_t a) {

  return vector< T >(a);

}



template< typename T, typename... Ts >

auto make_v(size_t a, Ts... ts) {

  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));

}



template< typename T, typename V >

typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {

  t = v;

}



template< typename T, typename V >

typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {

  for(auto &e : t) fill_v(e, v);

}



template< int char_size >

struct TrieNode {

  int nxt[char_size + 1];



  int exist; // 子ども以下に存在する文字列の数の合計

  vector< int > accept; // その文字列id



  TrieNode() : exist(0) {

    memset(nxt, -1, sizeof(nxt));

  }

};



template< int char_size, int margin >

struct Trie {

  using Node = TrieNode< char_size >;



  vector< Node > nodes;

  int root;



  Trie() : root(0) {

    nodes.push_back(Node());

  }



  virtual void direct_action(int node, int id) {}



  virtual void child_action(int node, int child, int id) {}



  void update_direct(int node, int id) {

    nodes[node].accept.push_back(id);

    direct_action(node, id);

  }



  void update_child(int node, int child, int id) {

    ++nodes[node].exist;

    child_action(node, child, id);

  }



  void add(const string &str, int str_index, int node_index, int id) {

    if(str_index == str.size()) {

      update_direct(node_index, id);

    } else {

      const int c = str[str_index] - margin;

      if(nodes[node_index].nxt[c] == -1) {

        nodes[node_index].nxt[c] = (int) nodes.size();

        nodes.push_back(Node());

      }

      add(str, str_index + 1, nodes[node_index].nxt[c], id);

      update_child(node_index, nodes[node_index].nxt[c], id);

    }

  }



  void add(const string &str, int id) {

    add(str, 0, 0, id);

  }



  void add(const string &str) {

    add(str, nodes[0].exist);

  }



  void query(const string &str, const function< void(int) > &f, int str_index, int node_index) {

    for(auto &idx : nodes[node_index].accept) f(idx);

    if(str_index == str.size()) {

      return;

    } else {

      const int c = str[str_index] - margin;

      if(nodes[node_index].nxt[c] == -1) return;

      query(str, f, str_index + 1, nodes[node_index].nxt[c]);

    }

  }



  void query(const string &str, const function< void(int) > &f) {

    query(str, f, 0, 0);

  }



  int size() const {

    return (nodes[0].exist);

  }



  int nodesize() const {

    return ((int) nodes.size());

  }

};



template< int char_size, int margin >

struct AhoCorasick : Trie< char_size, margin > {

  using TRIE = Trie< char_size, margin >;

  static const int FAIL = char_size;

  vector< int > correct;



  AhoCorasick() : TRIE() {}



  void build(bool heavy = true) {

    correct.resize(TRIE::nodes.size());

    for(int i = 0; i < TRIE::nodes.size(); i++) {

      correct[i] = (int) TRIE::nodes[i].accept.size();

    }



    queue< int > que;

    for(int i = 0; i <= char_size; i++) {

      if(~TRIE::nodes[0].nxt[i]) {

        TRIE::nodes[TRIE::nodes[0].nxt[i]].nxt[FAIL] = 0;

        que.emplace(TRIE::nodes[0].nxt[i]);

      } else {

        TRIE::nodes[0].nxt[i] = 0;

      }

    }

    while(!que.empty()) {

      TrieNode< char_size > &now = TRIE::nodes[que.front()];

      correct[que.front()] += correct[now.nxt[FAIL]];

      que.pop();

      for(int i = 0; i < char_size; i++) {

        if(now.nxt[i] == -1) continue;

        int fail = now.nxt[FAIL];

        while(TRIE::nodes[fail].nxt[i] == -1) fail = TRIE::nodes[fail].nxt[FAIL];

        TRIE::nodes[now.nxt[i]].nxt[FAIL] = TRIE::nodes[fail].nxt[i];

        if(heavy) {

          auto &u = TRIE::nodes[now.nxt[i]].accept;

          auto &v = TRIE::nodes[TRIE::nodes[fail].nxt[i]].accept;

          vector< int > accept;

          set_union(begin(u), end(u), begin(v), end(v), back_inserter(accept));

          u = accept;

        }

        que.emplace(now.nxt[i]);

      }



    }

  }



  int match(const string &str, vector< int > &result, int now = 0) {

    result.assign(TRIE::size(), 0);

    int count = 0;

    for(auto &c : str) {

      while(TRIE::nodes[now].nxt[c - margin] == -1) now = TRIE::nodes[now].nxt[FAIL];

      now = TRIE::nodes[now].nxt[c - margin];

      count += correct[now];

      for(auto &v : TRIE::nodes[now].accept) ++result[v];

    }

    return (count);

  }



  int move(const char &c, int &now) {

    int count = 0;

    while(TRIE::nodes[now].nxt[c - margin] == -1) now = TRIE::nodes[now].nxt[FAIL];

    now = TRIE::nodes[now].nxt[c - margin];

    count += correct[now];

    return (count);

  }

};



vector< string > u;



void make(string s) {

  if(s.size() >= 3) {

    bool f = s.find("AGC") != string::npos;

    for(int i = 0; i + 1 < s.size(); i++) {

      swap(s[i], s[i + 1]);

      f |= s.find("AGC") != string::npos;

      swap(s[i], s[i + 1]);

    }

    if(f) {

      u.emplace_back(s);

    }

    if(s.size() >= 4) return;

  }

  make(s + "A");

  make(s + "G");

  make(s + "C");

  make(s + "T");

}



int main() {

  make("");

  AhoCorasick< 26, 'A' > aho;

  for(auto &p : u) aho.add(p);

  aho.build();

  int N;

  cin >> N;

  vector< int > dp(aho.nodesize());

  dp[0] = 1;

  for(int i = 0; i < N; i++) {

    vector< int > dp2(aho.nodesize());

    for(int j : string("AGCT")) {

      for(int k = 0; k < dp.size(); k++) {

        if(dp[k]) {

          int c = k;

          if(aho.move(j, c)) continue;

          dp2[c] += dp[k];

          dp2[c] %= mod;

        }

      }

    }

    dp.swap(dp2);

  }



  cout << accumulate(begin(dp), end(dp), 0LL) % mod << endl;

}




// Fastest known solution for this problem: