#include <bits/stdc++.h>
#pragma GCC optimize("O3")
using namespace std;
const int bs = 1000000007;
const int N = 200031;
int n, ptr;
vector<pair<int, int> > ans;
vector<int> generate_block(int levels) {
  vector<int> cur;
  for (int i = 0; i < (1 << levels); i++) {
    cur.push_back(ptr);
    ++ptr;
  }
  for (int lev = 0; lev < levels; lev++) {
    for (int i = 0; i < cur.size(); i++) {
      if (!(i & (1 << lev)))
        ans.push_back(make_pair(cur[i], cur[i + (1 << lev)]));
    }
  }
  return cur;
}
vector<vector<int> > blocks;
void doubling_strategy() {
  vector<int> tail;
  tail = blocks.back();
  blocks.pop_back();
  vector<int> othr;
  for (int i = 0; i < tail.size(); i++) {
    othr.push_back(blocks[0].back());
    blocks[0].pop_back();
  }
  for (int i = 0; i < tail.size(); i++) {
    ans.push_back(make_pair(tail[i], othr[i]));
  }
  for (int i = 0; i < othr.size(); i++) {
    tail.push_back(othr[i]);
  }
  blocks.push_back(tail);
}
void merge_tail() {
  vector<int> v1 = blocks[blocks.size() - 1];
  vector<int> v2 = blocks[blocks.size() - 2];
  blocks.pop_back();
  blocks.pop_back();
  for (int i = 0; i < v1.size(); i++) {
    ans.push_back(make_pair(v1[i], v2[i]));
  }
  for (int i = 0; i < v2.size(); i++) {
    v1.push_back(v2[i]);
  }
  blocks.push_back(v1);
}
int main() {
  cin >> n;
  ptr = 1;
  for (int i = 15; i >= 0; --i) {
    if (n & (1 << i)) {
      vector<int> v = generate_block(i);
      blocks.push_back(v);
    }
  }
  while (blocks.size() > 2) {
    while (blocks[blocks.size() - 2].size() !=
           blocks[blocks.size() - 1].size()) {
      doubling_strategy();
    }
    merge_tail();
  }
  cout << ans.size() << endl;
  for (int i = 0; i < ans.size(); i++) {
    printf("%d %d\n", ans[i].first, ans[i].second);
  }
  return 0;
}
