#ifdef __GNUC__ 
#pragma GCC optimize(2)
#endif

#include <cassert>
#include <iostream>
#include <functional>
#include <iomanip>
#include <set>
#include <unordered_map>
#include <map>
#include <queue>
#include <stack>
#include <complex>
#include <vector>
#include <deque>
#include <algorithm>
#include  <cstring>
#include <string>
#include <cmath> 
#include <random>

#pragma warning(disable: 4996)

using namespace std;
 
namespace Bigcat {
	template <typename T> inline void max_s(T&a, const T&b) { a = max(a, b); }
	template <typename T> inline void min_s(T&a, const T&b) { a = min(a, b); }

	template <typename T>  void sort_v(T & x) { sort(x.begin(), x.end()); }
	template <typename T>  void erase_dup(T & x) { x.erase(unique(x.begin(), x.end()), x.end()); }    // erase duplicate
	template <typename T, typename V>  int pos_l(const T & x, const V & v) { return lower_bound(x.begin(), x.end(), v) - x.begin(); }
	template <typename T, typename V>  int pos_u(const T & x, const V & v) { return upper_bound(x.begin(), x.end(), v) - x.begin(); }

	inline unsigned rand_g() {
		static mt19937 mt_rand((int)time(0));
		return mt_rand();
	}
	using LL = long long;
	using VI = vector<int>;
	using VVI = vector< VI >;
	using VL = vector<LL>;
	using PII = pair<int, int>;
	using VPII = vector< PII >;
}
#define Rep(i, a) for(int i = 0; i < (int)(a); i++)
#define Loop(i, a, b) for(int i = (int)(a); i < (int)(b); i++)
#define Loop_r(i, n) for(int i = (int)(n) - 1; i >= 0; i--)

    using namespace Bigcat;
const LL base = LL(1e9 + 7);
const LL INFL =  1LL << 62;
const int INF = 1 << 30 ;
const int MAX = int ( 2e5 + 100 ) ;

struct Node {
	int x, y, w;
};
bool operator < (const Node & n0, const Node & n1) {
	return n0.x< n1.y;
}

void test(int m) {
	
	int z = m*(m - 1) / 2;
	int tot = 1 << z;
	for (int g = 0; g < tot; ++g) {
		VI zt(m);
		int x = g;
		VPII zr;
		for (int i = 0; i < m; ++i) {
			for (int j = i + 1; j < m; ++j) {
				int s = x & 1;
				x /= 2;
				if (!s) continue;
				zt[i] += j + 1;
				zt[j] += i + 1;
				zr.push_back({ i + 1, j + 1 });
			}
		}
		bool ok = true;
		Rep(i, m) {
			if (zt[i] != zt[0]) {
				ok = false;
				break;
			}
		}
		if (ok) {
			cout << zt[0]<<endl;
			for (auto x : zr) {
				cout << x.first << ' ' << x.second << endl;
			}
		}
	}
}
void solve1() {
	//test(4);
	LL result = 0;
	int n;

	cin >> n;
	VPII zr;
	if (n % 2 == 1) {
		for (int i = 1; i < n; ++i) {
			for (int j = i+1; j <= n; ++j) {
				if (j == i) continue;
				if (i + j == n) continue;
				zr.push_back({ i,j });
			} 
		}
	}
	else {
		for (int i = 1; i <=n; ++i) {
			for (int j = i+1; j <= n; ++j) {
				if (j == i) continue;
				if (i + j == n+1) continue;
				zr.push_back({ i,j });
			}
		}
	}
	cout << zr.size() << endl;
	for (auto x : zr) {
		cout << x.first << ' ' << x.second << '\n';
	}

}
void solve() {
	int t = 1;
	//cin >> t;
#ifdef _DEBUG
	cerr << " now base "<< base << endl;
#endif
	for (int i = 0; i < t; ++i) {
 #ifdef _DEBUG
    cerr<<" tasks: " << i+1<<endl;
#endif       
		solve1();
	}
    int x = 1;
}

void io_init() {
   	const int inId = 0;
	const int outId = 0;
	if (inId>0) {
		cerr << "redirect stdin to input " << inId << endl;
		string s = "input";
		s += to_string(inId);
		s += ".txt";
		auto r = freopen(s.c_str(), "r", stdin);
		if (r == nullptr) {
			cerr << "invalid input file " << s << endl;;
			r = freopen("CON", "r", stdin); // to do  con??
		}
	}
	if (outId>0) {
		cerr << "redirect stdout to stdout " << outId << endl;
		string s = "stdout";
		s += to_string(outId);
		s += ".txt";
		auto r = freopen(s.c_str(), "w", stdout);
		if (r == nullptr) {
			cerr << "invalid output file " << s << endl;;
			r = freopen("CON", "w", stdout);
		}
	}
}

int main(int argc,  char * argv[]) {
    
#ifdef _DEBUG    
	if (argc ==1) {
		io_init();
	}
#endif
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); // close sync between cout and printf
	cout.precision(11); 
    
	solve();
}


Measured memory_bytes: 384