Problem: You have to organize a wedding party. The program of the party will include a concentration game played by the bride and groom. The arrangement of the concentration game should be easy since this game will be played to make the party fun.

We have a 4x4 board and 8 pairs of cards (denoted by `A' to `H') for the concentration game:


+---+---+---+---+
|   |   |   |   |   A A B B
+---+---+---+---+   C C D D
|   |   |   |   |   E E F F
+---+---+---+---+   G G H H
|   |   |   |   |
+---+---+---+---+
|   |   |   |   |
+---+---+---+---+


To start the game, it is necessary to arrange all 16 cards face down on the board. For example:


+---+---+---+---+
| A | B | A | B |
+---+---+---+---+
| C | D | C | D |
+---+---+---+---+
| E | F | G | H |
+---+---+---+---+
| G | H | E | F |
+---+---+---+---+


The purpose of the concentration game is to expose as many cards as possible by repeatedly performing the following procedure: (1) expose two cards, (2) keep them open if they match or replace them face down if they do not.

Since the arrangements should be simple, every pair of cards on the board must obey the following condition: the relative position of one card to the other card of the pair must be one of 4 given relative positions. The 4 relative positions are different from one another and they are selected from the following 24 candidates:


(1, 0), (2, 0), (3, 0),
(-3, 1), (-2, 1), (-1, 1), (0, 1), (1, 1), (2, 1), (3, 1),
(-3, 2), (-2, 2), (-1, 2), (0, 2), (1, 2), (2, 2), (3, 2),
(-3, 3), (-2, 3), (-1, 3), (0, 3), (1, 3), (2, 3), (3, 3).


Your job in this problem is to write a program that reports the total number of board arrangements which satisfy the given constraint. For example, if relative positions (-2, 1), (-1, 1), (1, 1), (1, 2) are given, the total number of board arrangements is two, where the following two arrangements satisfy the given constraint:


X0  X1  X2  X3             X0  X1  X2  X3
+---+---+---+---+          +---+---+---+---+
Y0 | A | B | C | D |       Y0 | A | B | C | D |
+---+---+---+---+          +---+---+---+---+
Y1 | B | A | D | C |       Y1 | B | D | E | C |
+---+---+---+---+          +---+---+---+---+
Y2 | E | F | G | H |       Y2 | F | A | G | H |
+---+---+---+---+          +---+---+---+---+
Y3 | F | E | H | G |       Y3 | G | F | H | E |
+---+---+---+---+          +---+---+---+---+
the relative positions:    the relative positions:
A:(1, 1),  B:(-1, 1)       A:(1, 2),  B:(-1, 1)
C:(1, 1),  D:(-1, 1)       C:(1, 1),  D:(-2, 1)
E:(1, 1),  F:(-1, 1)       E:(1, 2),  F:( 1, 1)
G:(1, 1),  H:(-1, 1)       G:(-2, 1), H:(-1, 1)


Arrangements of the same pattern should be counted only once. Two board arrangements are said to have the same pattern if they are obtained from each other by repeatedly making any two pairs exchange their positions. For example, the following two arrangements have the same pattern:



X0  X1  X2  X3           X0  X1  X2  X3
+---+---+---+---+        +---+---+---+---+
Y0 | H | G | F | E |     Y0 | A | B | C | D |
+---+---+---+---+        +---+---+---+---+
Y1 | G | E | D | F |     Y1 | B | D | E | C |
+---+---+---+---+        +---+---+---+---+
Y2 | C | H | B | A |     Y2 | F | A | G | H |
+---+---+---+---+        +---+---+---+---+
Y3 | B | C | A | D |     Y3 | G | F | H | E |
+---+---+---+---+        +---+---+---+---+


where (1) `A' and `H', (2) `B' and `G', (3) `C' and `F', and (4) `D' and `E' exchange their positions respectively.



Input

The input contains multiple data sets, each representing 4 relative positions. A data set is given as a line in the following format.

x1| y1 | x2| y2 | x3| y3 | x4| y4
---|---|---|---|---|---|---|---

The i-th relative position is given by (xi, yi). You may assume that the given relative positions are different from one another and each of them is one of the 24 candidates.

The end of input is indicated by the line which contains a single number greater than 4.

Output

For each data set, your program should output the total number of board arrangements (or more precisely, the total number of patterns).

Each number should be printed in one line. Since your result is checked by an automatic grading program, you should not insert any extra characters nor lines on the output.

Examples

Input




Output




Input

-2 1 -1 1 1 1 1 2
1 0 2 1 2 2 3 3
5


Output

2
15

Solution (in JAVA):

Solution:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

//public class Problem1103_BoardArrangementsForConcentrationGames {
public class Main {
	
	public static void main(String[] args) {
		try {
		//	Problem1103_BoardArrangementsForConcentrationGames test = new Problem1103_BoardArrangementsForConcentrationGames();
			Main test = new Main();
			
			BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
			
			String line;
			while((line = reader.readLine()) != null) {
				String[] textArray = line.split(" ");
				if(textArray.length > 1) {
					int answer = test.checkBoard(test.createRelativePosition(textArray));
					System.out.println(answer);
				} else {
					int number = Integer.parseInt(textArray[0]);
					if(number > 4) {
						break;
					} else {
						throw new IllegalArgumentException();
					}
				}
			}
		} catch(IOException e) {
			e.printStackTrace();
		}
	}
	RelativePosition createRelativePosition(String[] textArray) {
		RelativePosition startPosition = new RelativePosition(Integer.parseInt(textArray[0]), Integer.parseInt(textArray[1]), null);
		RelativePosition position = startPosition;
		for(int i = 1; i < 4; i++) {
			position.setNext(new RelativePosition(Integer.parseInt(textArray[i*2]), Integer.parseInt(textArray[i*2 +1]), null));
			position = position.getNext();
		}
		
		return startPosition;
	}
	
	
	int checkBoard(RelativePosition start) {
		GameBoard gameBoard = new GameBoard();
		RelativePosition position = start;
		RelativePosition startPosition = start;
		
		int answerCount = 0;
		int puttedCount = 0;
		int x = 0, y = 0;  
		while(true) {
			while(puttedCount < 8) {
			//	System.out.println("ÇÁpÚF" + position.toString() + "  \tx:" + x + "\ty:" + y);
				if(gameBoard.isPutted(x,y)) {	//ÝuÏÝÅAputtedCount < 8 ÌÆ«ÍAª éÌÅ¸B
					position = startPosition;
					x = (x < 3 ? x+1 : 0);
					y = (x == 0 ? y+1 : y);
				} else if(gameBoard.put(x, y, position)){	//u¯êÎu­
					position = startPosition;
					x = (x < 3 ? x+1 : 0);
					y = (x == 0 ? y+1 : y);
					puttedCount++;
			//		System.out.println("ÇÁ" + puttedCount +"ÂÚ");
				} else {
					position = position.getNext();	//ÝuÅ«È¯êÎÊÌóâÅÝuµÄÝéB
					
					if(position == null) {	//SÄÌÚÅÝuÅ«È¢êBPÂßéB
			//			System.out.println("positionªÅãÜÅB");
						PuttedPoint removedPoint;
						
						while(true) {
							removedPoint = gameBoard.removeLast();
							if(removedPoint.getRelativePosition().getNext() == null) {
								if(removedPoint.getPreviousPoint() == null) {
			//						System.out.println("jIõI¹");
									return answerCount;
								} else {
									puttedCount--;
								}
							} else {
								position = removedPoint.getRelativePosition().getNext();
								x = removedPoint.getX();
								y = removedPoint.getY();
								puttedCount--;
			//					System.out.println("ßéF" + removedPoint.getRelativePosition() + "\tJE^F" + puttedCount);
								break;
							}
						}
					}
				}
			}
			
			//êñÜÁ½ê
			answerCount++;
		//	System.out.println("****ÜÁ½æ\t" + answerCount + "ñÚ****");
			for(int i = 8; -1 < i; i--) {
				PuttedPoint removedPoint = gameBoard.removeLast();
				position = removedPoint.getRelativePosition().getNext();
				puttedCount--;
				if(position == null) {	//óâªÈ¢ÌÈçà¤êÂßé
					if(i == 0) {	//i == 0@¦¿ASõI¹
			//			System.out.println("jIõI¹");
						return answerCount;
					} else {
						//loop more 	//à¤êÂßé
					}
				} else {
					x = removedPoint.getX();
					y = removedPoint.getY();
					break;	//fJ[và¤êñ
				}
			}
		}
	}
	private class GameBoard {
		private boolean[][] board;	//ÝuÏÝÈçfalse, ¢ÝuÌÆ«true
		private PuttedPoint lastPuttedPoint;
		
		GameBoard(int height, int width) {
			board = new boolean[height][width];
			for(boolean[] boardRow : board) {
				Arrays.fill(boardRow,true);
			}
			lastPuttedPoint= null;
		}
		GameBoard() {
			this(4,4);
		}
		boolean isPutted(int x, int y) {
			boolean result = board[x][y];
			return !result;	//½]Ó
		}
		boolean put(int x, int y, RelativePosition position) {
			if(canAdd(x,y,position)) {
				if(addPosition(x,y,position)) {
					lastPuttedPoint = new PuttedPoint(x, y, position, lastPuttedPoint);
			//		System.out.println("ÇÁF" + "  \tx:" + lastPuttedPoint.getX() + "\ty:" +  lastPuttedPoint.getY());
					return true;
				}
			}
			return false;
		}
		PuttedPoint removeLast() {
			PuttedPoint removedPoint = lastPuttedPoint;
			if(removedPoint == null) {
				return null;
			}
			if(removePosition(lastPuttedPoint.getX(), lastPuttedPoint.getY(), lastPuttedPoint.getRelativePosition())) {
			//	System.out.println("íF" + lastPuttedPoint.getRelativePosition() + "  \tx:" + lastPuttedPoint.getX() + "\ty:" +  lastPuttedPoint.getY());
				lastPuttedPoint = lastPuttedPoint.getPreviousPoint();
				
			/*	if(lastPuttedPoint == null) {
					return null;
				}*/
			} else {
				throw new IllegalStateException("í¸s");
			}
			return removedPoint;
		}
		/*
			øÌÊuÆAyAÌÊu¼ûª¢Ýu¾Á½êÉ true
		*/
		private boolean canAdd(int x, int y, RelativePosition position) {
			int pointX = x;
			int pointY = y;
			
			try {
				if(board[pointX][pointY] && board[x + position.getX()][y + position.getY()]) {
					return true;
				} else {
					return false;
				}
			} catch(IndexOutOfBoundsException e) {
				return false;
			}
		}
		/*
			³ÝuÅ«½çtrue	AµAaddÌêªÝu¢Ýu©Ç¤©mFµÈ¢B
		*/
		private boolean addPosition(int x, int y, RelativePosition position) {
			int pointX = x;
			int pointY = y;
			int pointPairX = pointX + position.getX();
			int pointPairY = pointY + position.getY();
			
			try {
				board[x][y] = false;
				board[pointPairX][pointPairY] = false;
				
				return true;
			} catch(IndexOutOfBoundsException e) {
				return false;
			}
		}
		/*
			³íÅ«½çtrue	AµAremoveÌêªÝuÏÝ©Ç¤©mFµÈ¢B
		*/
		private boolean removePosition(int x, int y, RelativePosition position) {
			int pointX = x;
			int pointY = y;
			int pointPairX = pointX + position.getX();
			int pointPairY = pointY + position.getY();
			
			try {
				board[x][y] = true;
				board[pointPairX][pointPairY] = true;
				
				return true;
			} catch(IndexOutOfBoundsException e) {
				return false;
			}
		}
	}
	private class PuttedPoint {
		private int x;
		private int y;
		
		private PuttedPoint previousPoint;
		private RelativePosition puttedRelativePosition;
		
		PuttedPoint(int x, int y, RelativePosition point, PuttedPoint previous) {
			this.x = x;
			this.y = y;
			puttedRelativePosition = point;
			previousPoint = previous;
		}
		int getX() {
			return x;
		}
		int getY() {
			return y;
		}
		RelativePosition getRelativePosition() {
			return puttedRelativePosition;
		}
		PuttedPoint getPreviousPoint() {
			return previousPoint;
		}
	}
	private class RelativePosition {
		private int x;
		private int y;
		
		private RelativePosition nextPosition;
		
		RelativePosition(int x, int y, RelativePosition next) {
			this.x = x;
			this.y = y;
			nextPosition = next;
		}
		int getX() {
			return x;
		}
		int getY() {
			return y;
		}
		void setNext(RelativePosition position) {
			nextPosition = position;
		}
		RelativePosition getNext() {
			return nextPosition;
		}
		@Override
		public String toString() {
			return "(" + x + "," + y + ")";
		}
	}
}