import std.algorithm;
import std.array;
import std.range;
import std.stdio;

immutable int NA = -1;

auto mult (int [] p, int [] q)
{
	auto n = p.length;
	auto res = new int [n];
	foreach (i; 0..n)
	{
		if (q[i] != NA)
		{
			res[i] = p[q[i]];
		}
	}
	return res;
}

void main ()
{
	immutable int scale = 2; // 1 for testing, 2 for the actual problem
	immutable int n = 14 * scale;
	immutable int parts = 2 * scale;
	immutable int num1Right = 2 * scale;
	immutable int num3Right = 4 * scale;
	auto b = n.iota.array;
	foreach (j; 0..parts)
	{
		bringToFront (b[j * 7 + 0..j * 7 + 1],
		    b[j * 7 + 1..j * 7 + 7]);
	}
	debug {writeln (b);}
	auto bi = new int [n];
	foreach (i; 0..n)
	{
		bi[b[i]] = i;
	}
	auto ab = new int [n];
	ab[] = NA;
	auto u = new bool [n];

	bool check ()
	{
		foreach (i; 0..n)
		{
			if (ab[i] != NA)
			{
				if (ab[i] == i)
				{
					return false;
				}
				if (ab[ab[i]] != NA)
				{
					if (ab[ab[i]] != i)
					{
						return false;
					}
				}
			}
		}

		auto a = mult (ab, bi);
		int num1 = 0;
		int num3 = 0;
		foreach (i; 0..n)
		{
			if (a[i] != NA)
			{
				if (a[i] == i)
				{
					num1 += 1;
					if (num1 > num1Right)
					{
						return false;
					}
				}
				else
				{
					if (a[a[i]] != NA)
					{
						if (a[a[i]] == i)
						{
							return false;
						}
						else if (a[a[a[i]]] != NA)
						{
							if (a[a[a[i]]] == i)
							{
								num3 += 1;
								if (num3 > num3Right)
								{
									return false;
								}
							}
							else
							{
								return false;
							}
						}
					}
				}
			}
		}

		return true;
	}

	void recur (int k)
	{
		if (k == n)
		{
			writeln (ab);
			return;
		}
		auto a = mult (ab, bi);
//		debug {writeln (a);}
		foreach (i; 0..n)
		{
			if (a[i] != NA && a[i] != i &&
			    a[a[i]] != NA)
			{
				if (a[a[a[i]]] == NA)
				{
//					a[a[a[i]]] = i;
					ab[bi[a[a[i]]]] = i;
					a = mult (ab, bi);
					assert (a[a[a[i]]] == i);
					recur (k);
					ab[bi[a[a[i]]]] = NA;
					return;
				}
			}
		}
		if (ab[k] != NA)
		{
			recur (k + 1);
			return;
		}
		debug {writeln (ab);}
		if (!check ())
		{
			return;
		}
		foreach (i; 0..n)
		{
			if (!u[i])
			{
				if (i == k || ab[i] != NA)
				{
					continue;
				}
				u[i] = true;
				ab[k] = i;
				ab[i] = k;
				recur (k + 1);
				ab[i] = NA;
				ab[k] = NA;
				u[i] = false;
			}
		}
	}

	recur (0);
}
