unittest
{
	assert( [ "3" ].parse.expand.solve == "2\n1 3\n2 3" );
	
	assert( [ "4" ].parse.expand.solve == "4\n1 2\n1 3\n2 4\n3 4" );												// 追加ケース
	assert( [ "5" ].parse.expand.solve == "8\n1 2\n1 3\n1 5\n2 4\n2 5\n3 4\n3 5\n4 5" );							// 追加ケース
	assert( [ "6" ].parse.expand.solve == "12\n1 2\n1 3\n1 4\n1 5\n2 3\n2 4\n2 6\n3 5\n3 6\n4 5\n4 6\n5 6" );		// 追加ケース
}



import std.conv;
import std.format;
import std.range;
import std.stdio;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto n = input.front.to!( long );
	return tuple( n );
}

auto solve( long n )
{
	// nが奇数のときは頂点aは頂点(n-a)以外に辺を張る。頂点nだけは他の頂点全部に辺を張る。
	// nが偶数のときは頂点aは頂点(n-a+1)以外に辺を張る。
	auto anss = new string[ ( n * ( n - 1 ) / 2 ) - ( n / 2 ) ];
	auto ansi = 0L;
	for( auto a = 1L; a <= n; a++ )
	{
		auto una = n - a + ( n % 2 == 0 );
		for( auto b = a + 1; b <= n; b++ )
		{
			if( b == una ) continue;
			anss[ ansi ] = format( "%s %s", a, b );
			ansi++;
		}
	}
	return format( "%s\n%s", ansi, anss.join( "\n" ) );
}
