#include <bits/stdc++.h>
using namespace std; inline void fileio(const char* in, const char* out) { freopen(in, "r", stdin); freopen(out, "w", stdout); } 
#define TD typedef
#define forx(i,n) for(int i = 0; i < (n); ++i)
TD long long ll; TD long double ld; TD pair<int,int> pii; TD pair<ll, ll> pll; TD vector<int> VI; TD vector<bool> VB; TD vector<ll> VL;
const char nl = '\n'; const int INF = 0x3f3f3f3f; const ll LINF = 0x3f3f3f3f3f3f3f3fll; const ld EPS = 1e-9, PI = acos(-1);
#define ff first
#define ss second

class ModInt {
  int val; static const int MOD = 1e9+7; static_assert(MOD > 0, "Modulus not set!");
  int modInverse(int a) { // simplified extended GCD, only solving for x
    int b = MOD, x = 0, x_ = 1, q; while (a != 0) { q = b / a; swap(b, a); a %= b;
    swap(x, x_); x_ -= q * x; } assert(b == 1); return (x %= MOD) < 0 ? (x + MOD) : x; }
  public: ModInt() : val(0) { } ModInt(int v) : val(v) { if ((val %= MOD) < 0) val += MOD; }
    ModInt& operator += (const ModInt& b) { if ((val += b.val) >= MOD) val -= MOD; return *this; }
    ModInt& operator -= (const ModInt& b) { if ((val -= b.val) < 0) val += MOD; return *this; }
    ModInt& operator *= (const ModInt& b) { val = ((ll)val*(ll)b.val) % MOD; return *this; }
    ModInt& operator /= (const ModInt& b) {
      return (*this) *= modInverse(b.val);
      //if (((val *= modInverse(b.val)) %= MOD) < 0) val += MOD; return *this;
    }
#define _op(op, btype, op2) ModInt operator op (btype b) const { ModInt ans = *this; return ans op2 b; }
    _op(+, const ModInt&, +=); _op(-, const ModInt&, -=); _op(*, const ModInt&, *=); _op(/, const ModInt&, /=);
    _op(+, int, +=); _op(-, int, -=); _op(*, int, *=); _op(/, int, /=);
#undef _op
    operator int() const { assert(0 <= val && val < MOD); return val; }
};

// INITIALIZATION:
// Graph(N,D)
//    constructs a graph with 'N' nodes and Edge dimension 'D', ie. edges can hold 'D' long long data values
// add_edge(u,v, [undirected], [data])
//    adds an edge from 'u' to 'v' (undirected by default) and with the optionally given intial edge data values
//
// Edge:
//   operator[i] returns the ith data value associated with this edge (by reference)
//   nodeFrom(f) returns the node that would be reached from node 'f' via this edge.
// 
// USAGE:
// Graph algorithms will take in a graph, relevant inputs (eg. source and target node) as well as data indices. eg. wIdx, cIdx
// These indicate which index the edge data is stored in. eg. wIdx=0 means edge weights will be accessed using Edge[0];
struct Graph {
  class Edge { Graph* owner; const int idx; public: const int u, v; Edge() : owner(0), idx(-1), u(-1), v(-1) { } Edge(Graph* owner, int idx, int u, int v) :
    owner(owner), idx(idx), u(u), v(v) { } ll& operator[](int i) { return owner->getEdgeData(idx, i); }
    int nodeFrom(int f) const { return f^u^v; } }; TD vector<Edge> VE;
  class EdgeIt { VI* adj; VE* edge_list; public: EdgeIt(VI* adj, VE* edge_list) : adj(adj), edge_list(edge_list) {}
    class Iterator { VI* adj; VE* edge_list; int idx; public: Iterator(VI* adj, VE* edge_list, int idx=0) : adj(adj), edge_list(edge_list), idx(idx) {}
    bool operator == (const Iterator& b) const { return adj == b.adj && idx == b.idx; } bool operator != (const Iterator& b) const { return !(*this == b); }
    Iterator operator ++() { auto temp = *this; ++idx; return temp; } Edge& operator *() { return (*edge_list)[(*adj)[idx]]; } };
    Iterator begin() const { return Iterator(adj, edge_list); } Iterator end() const { return Iterator(adj, edge_list, adj->size()); } };
  class NodeIt { EdgeIt it; int u; public: NodeIt(VI* adj, VE* edge_list, int u) : it(adj, edge_list), u(u) {} class Iterator { EdgeIt::Iterator iter; int u;
    public: Iterator(EdgeIt::Iterator iter, int u) : iter(iter), u(u) { } bool operator == (const Iterator& b) const { return iter == b.iter && u == b.u; }
    bool operator != (const Iterator& b) const { return !(*this == b); } Iterator operator ++() { auto temp = *this; ++iter; return temp; }
    int operator *() { return (*iter).nodeFrom(u); } }; Iterator begin() const { return Iterator(it.begin(), u); }
    Iterator end() const { return Iterator(it.end(), u); } };

  Graph(int N, int D=0) : edge_list(0), adj_list(N), edge_data(0), dimens(D) { edge_list.reserve(N); edge_data.reserve(D*N); }
  Edge& add_edge(int u, int v, bool undirected=true, initializer_list<ll> data = { }) {
    int i = edge_list.size();
    adj_list[u].push_back(i);
    if (undirected)
      adj_list[v].push_back(i);
    edge_list.emplace_back(this, i, u, v);
    int j = edge_data.size();
    edge_data.resize(j+dimens);
    for (ll val : data) edge_data[j++] = val;
    return edge_list.back();
  }
  ll& getEdgeData(int eIdx, int dIdx) { static ll dummy; return (dIdx < 0 || dIdx >= dimens) ? dummy : edge_data[eIdx*dimens + dIdx]; }
  // Number of nodes and edges, and dimension of each edge respectively
  ll N() const { return adj_list.size(); }
  ll M() const { return edge_list.size(); }
  ll D() const { return dimens; }
  // AdjVec is the edge indices
  VI& getAdjVec(int u) { return adj_list[u]; }
  EdgeIt getAdjEdge(int u) { return EdgeIt(&adj_list[u], &edge_list); }
  NodeIt getAdjNode(int u) { return NodeIt(&adj_list[u], &edge_list, u); }
  VE& edges() { return edge_list; }
  // Degree of a node (for directed graph, out degree)
  int degree(int u) const { return adj_list[u].size(); }
  Edge& getEdge(int i) { return edge_list[i]; }
  Edge& operator[](int i) { return edge_list[i]; }
  // returns true if u's only neighbor is p
  bool isLeaf(int u, int p) const { return adj_list[u].size() == 1 && edge_list[adj_list[u][0]].nodeFrom(u) == p; }
private: VE edge_list; vector<VI> adj_list; VL edge_data; const int dimens; }; typedef Graph::Edge Edge;

const int N = 1e5 + 7;
ModInt mem[N][2]; //mem[i][c] is the number of ways to color node i with color c
                  // color true == black
//DFS
ModInt solve(Graph& g, int node, bool color, int par = -1) {
  if (g.isLeaf(node, par)) {
    //doesn't matter which color, just 1 way
    return 1;
  }
  if (!mem[node][color]) {
    mem[node][color] = 1;
    for (int u : g.getAdjNode(node)) {
      if (u == par) continue;
      //can always color white
      ModInt temp = solve(g, u, false, node);
      //if not black, can also color black
      if (!color) 
        temp += solve(g, u, true, node);
      mem[node][color] *= temp;
    }
  }
  return mem[node][color];
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  // Emily <3
  int n;
  cin >> n;
  Graph g(n);
  int u, v;
  forx(i,n-1) {
    cin >> u >> v;
    g.add_edge(u-1, v-1);
  }
  if (n == 1) {
    cout << 2 << nl;
  } else {
    //arbitrarily rooted at 0
    cout << solve(g, 0, false) + solve(g, 0, true) << nl;
  }

  cerr << "Time: " << (ld)clock() / CLOCKS_PER_SEC << nl;
  return 0;
}



Measured memory_bytes: 18560