let N = Int(readLine()!)!
let ball: [(Int, Int)] = (0..<N).map { _ in
	let input = readLine()!.characters.split(" ").map{Int(String($0))!}
	return (input[0], input[1])
}
var dic = [String : Int]()
for i in ball {
	for j in ball {
		if i != j {
			let key = "\(i.0 - j.0),\(i.1 - j.1)"
			dic[key] = (dic[key] ?? 0) + 1
		}
	}
}
print(N - (dic.values.maxElement() ?? 0))


let N = Int(readLine()!)!
let ball: [(Int, Int)] = (0..<N).map { _ in
	let input = readLine()!.characters.split(" ").map{Int(String($0))!}
	return (input[0], input[1])
}
var dic = [String : Int]()
for i in ball {
	for j in ball {
    	if i != j {
			let key = "\(i.0 - j.0),\(i.1 - j.1)"
			dic[key] = (dic[key] ?? 0) + 1
        }
	}
}
print(N - (dic.values.maxElement() ?? 0))


import Foundation

func readWords<T>(_ f: (Substring) -> T) -> [T] {
    return readLine()!.split(separator: " ").map(f)
}

func main() {
    let n = Int(readLine()!)!

    let points = (1...n).map { _ -> (Int, Int) in
        let xy = readWords { Int($0)! }
        let x = xy[0]
        let y = xy[1]

        return (x, y)
    }

    var distances = [[Int]: Int]()
    for (p, q) in points {
        for (b, d) in points {
            if (p, q) == (b, d) {
                continue
            }
            let pb = p - b
            let qd = q - d
            distances[[pb, qd], default: 0] += 1
        }
    }
    let v = distances.values.max()!
    print(n - v)
}

main()


let N = Int(readLine()!)!
let ball: [(Int,Int)] = (0..<N).map { _ in
	let input = readLine()!.characters.split(" ").map{Int(String($0))!}
	return (input[0],input[1])
}
let dic: [String : Int] = ball.map { i in
	ball.filter{$0 != i}.map { j in
		let key = "\(i.0-j.0),\(i.1-j.1)"
		return (dic[key] ?? 0)+1
	}
}
print(N-(dic.values.maxElement() ?? 0))


let N = Int(readLine()!)!
let ball: [(Int,Int)] = (0..<N).map { _ in
	let input = readLine()!.characters.split(" ").map{Int(String($0))!}
	return (input[0],input[1])
}
let dic: [String : Int] = ball.map { i in
	ball.filter{$0 != i}.map { j in
		let key = "\(i.0-j.0),\(i.1-j.1)"
		return dic[key]=(dic[key] ?? 0)+1
	}
}
print(N-(dic.values.maxElement() ?? 0))


let N = Int(readLine()!)!
let ball: [(Int, Int)] = (0..<N).map { _ in
	let input = readLine()!.characters.split(" ").map{Int(String($0))!}
	return (input[0], input[1])
}
var dic = [String : Int]()
for i in ball {
	for j in ball {
		let key = "\(i.0 - j.0),\(i.1 - j.1)"
		dic[key] = (dic[key] ?? 0) + 1
	}
}
print(N - (dic.values.maxElement() ?? 0))


import * as fs from 'fs';

class Reader {
    lines: string[];
    currentLine: number;

    constructor() {
        this.lines = fs.readFileSync("/dev/stdin", "utf8").trim().split("\n");
        this.currentLine = 0;
    }

    readLine(): string {
        return this.lines[this.currentLine++];
    }

    readInt(): number {
        return Number(this.readLine());
    }

    readInts(): number[] {
        return this.readLine().split(" ").map(Number);
    }
}

class DisjointSet {
    components: number;
    parents: number[];
    constructor(readonly size: number) {
        this.components = size;
        this.parents = new Array(size).fill(-1).map((value, index) => index);
    }

    find(node: number): number {
        if (node != this.parents[node])
            this.parents[node] = this.find(this.parents[node]);
        return this.parents[node];
    }

    union(node1: number, node2: number): void {
        let parent1 = this.find(node1),
            parent2 = this.find(node2);
        if (parent1 != parent2) {
            this.parents[parent1] = parent2;
            this.components -= 1;
        }
    }
}

function solve(): number {
    let reader = new Reader();
    let N = reader.readInt();
    let points: {x: number, y: number}[] = [];

    for (let i = 0; i < N; i++) {
        let [x, y] = reader.readInts();
        points.push({x: x, y: y});
    }

    if (N == 1)
        return 1;

    let minComponents = Number.POSITIVE_INFINITY;

    for (let i = 0; i < N; i++) {
        for (let j = i + 1; j < N; j++) {
            let p = points[j].x - points[i].x,
                q = points[j].y - points[i].y;
            let disjointSet = new DisjointSet(N);
            for (let k = 0; k < N; k++) {
                for (let l = k + 1; l < N; l++) {
                    if ((points[l].x - points[k].x == p && points[l].y - points[k].y == q) ||
                        (points[k].x - points[l].x == p && points[k].y - points[l].y == q)) {
                        disjointSet.union(l, k);
                    }
                }
            }
            minComponents = Math.min(minComponents, disjointSet.components);
        }
    }
    return minComponents;
};

console.log(solve());


import { readFileSync } from 'fs'

function permutation<T>(list: T[], n: number = list.length) {
  if (n === 0) return []
  if (n === 1) return list.map(v => [v])

  let result = [] as T[][]

  list.forEach((value, index) => {
    const otherValues = list.filter((_, i) => i !== index)
    const remainList = permutation(otherValues, n - 1).map((list) => [value, ...list])

    result.push(...remainList)
  })

  return result
}

function main(input: string) {
  const [[N], ...list] = input.split('\n').map(v => v.split(' ').map(Number))

  if (N === 1) {
    console.log(1)
    return
  }

  const data = permutation(list, 2)
    .map(([[ax, ay], [bx, by]]) => [ax - bx, ay - by])
    .map(v => JSON.stringify(v))

  const countList = Array.from(new Set(data))
    .map(str => data.filter(v => v === str).length)

  const max = Math.max(...countList)

  console.log(N - max)
}

main(readFileSync('/dev/stdin', 'utf8').trim())


import * as fs from 'fs';

class Reader {
    lines: string[];
    currentLine: number;

    constructor() {
        this.lines = fs.readFileSync("/dev/stdin", "utf8").trim().split("\n");
        this.currentLine = 0;
    }

    readLine(): string {
        return this.lines[this.currentLine++];
    }

    readInt(): number {
        return Number(this.readLine());
    }

    readInts(): number[] {
        return this.readLine().split(" ").map(Number);
    }
}

let reader = new Reader();
let N = reader.readInt();
let points: {x: number, y: number}[] = [];

for(let i=0; i<N; i++) {
    let [x, y] = reader.readInts();
    points.push({x: x, y: y});
}

class DisjointSet {
    components: number;
    parents: number[];
    constructor(readonly size: number) {
        this.components = size;
        this.parents = new Array(size).fill(-1).map((value, index) => index);
    }

    find(node: number): number {
        if (node != this.parents[node])
            this.parents[node] = this.find(this.parents[node]);
        return this.parents[node];
    }

    union(node1: number, node2: number): void {
        let parent1 = this.find(node1),
            parent2 = this.find(node2);
        if (parent1 != parent2) {
            this.parents[parent1] = parent2;
            this.components -= 1;
        }
    }
}

let minComponents = Number.POSITIVE_INFINITY;

for(let i=0; i<N; i++) {
    for(let j=i+1; j<N; j++) {
        let p = points[j].x-points[i].x,
            q = points[j].y-points[i].y;
        let disjointSet = new DisjointSet(N);
        for(let k=0; k<N; k++) {
            for(let l=k+1; l<N; l++) {
                if ((points[l].x-points[k].x == p && points[l].y-points[k].y == q) ||
                    (points[k].x-points[l].x == p && points[k].y-points[l].y == q)) {
                    disjointSet.union(l, k);
                }
            }
        }
        minComponents = Math.min(minComponents, disjointSet.components);
    }
}

console.log(minComponents);


import { readFileSync } from 'fs'

function main(input: string) {
  const [[N], ...list] = input.split('\n').map(v => v.split(' ').map(Number))

  const data = list.map(([x, y]) => ({ x, y }))
  const hash = {} as Record<string, number>

  for (const a of data) {
    for (const b of data) {
      if (a === b) continue

      const key = `${a.x - b.x} ${a.y - b.y}`

      hash[key] = (hash[key] || 0) + 1
    }
  }

  const max = Math.max(...Object.keys(hash).map(key => hash[key]))

  console.log(N - max)
}

main(readFileSync('/dev/stdin', 'utf8').trim())


import { readFileSync } from 'fs'

function main(input: string) {
  const [[N], ...list] = input.split('\n').map(v => v.split(' ').map(Number))

  const data = list.map(([x, y]) => ({ x, y }))
  const hash = {} as Record<string, number>

  for (const a of data) {
    for (const b of data) {
      if (a === b) continue

      const key = `${a.x - b.x} ${a.y - b.y}`

      hash[key] = (hash[key] || 0) + 1
    }
  }

  const max = Math.max(...Object.values(hash))

  console.log(N - max)
}

main(readFileSync('/dev/stdin', 'utf8').trim())


a,b,c,d=map(int,input().split())
ans=max((a*c),(a*d),(b*c),(b*d))
print(ans)


a, b, c, d = map(int, input().split())
e = max(a*c,a*d,b*c,b*d)
print(e)


a, b, c, d = map(int, input().split())
print(max(a * c, a * d, b * c, b * d))


a, b, c, d = map(int, input().split())
ans = 0
if b != 0 and d != 0:
    if c < 0:
        ans = a * d
    else:
        ans = b * d
else:
    ans = min(a, b) * min(c, d)

print(ans)


arr = list(map(int, input().split()))
arr.sort()

mini = arr[0] * arr[1]
maxi = arr[-1] * arr[-2]

print(max(mini, maxi))


a,b,c,d = map(int, input().split())
import numpy as np
A = np.matrix([[a],[b]])
C = np.matrix([c,d])
print(A.shape)
print(C.shape)
X = np.dot(A,C)
print(np.max(X))


import java.util.*;
import java.io.*;

public class Main {
	static FastReader in = new FastReader();

	public static void main(String[] args) {
		solve();
	}

	static void solve() {
		long a = in.nextLong(), b = in.nextLong(), c = in.nextLong(), d = in.nextLong();

		long fin1 = Math.max(a * c, a * d);
		long fin2 = Math.max(b * c, b * d);
		System.out.println(Math.max(fin1, fin2));
	}

	static class FastReader {
		BufferedReader br;
		StringTokenizer st;

		public FastReader() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}

		String next() {
			while (st == null || !st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}

		String nextLine() {
			String str = "";
			try {
				str = br.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return str;
		}

		int[] readarr(int abc) {
			int[] temp = new int[abc];
			for (int i = 0; i < abc; i++)
				temp[i] = nextInt();
			return temp;
		}
	}
}


import java.io.*;import java.util.*;import java.math.*;
public class Main
{
	static long mod=1000000007l;
    static int max=Integer.MAX_VALUE,min=Integer.MIN_VALUE;
    static long maxl=Long.MAX_VALUE,minl=Long.MIN_VALUE;
    static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static StringBuilder sb;

    static public void main(String[] args)throws Exception
    {
    	st=new StringTokenizer(br.readLine());
    	int a=i();
    	int b=i();
    	int c=i();
    	int d=i();
    	long s=1l*a*c;
    	s=max(s,1l*a*d);
    	s=max(s,1l*b*c);
    	s=max(s,1l*b*d);
    	pl(s);
    }

    static void s(String s){sb.append(s);}
    static void s(int s){sb.append(s);}
    static void s(long s){sb.append(s);}
    static void s(char s){sb.append(s);}
    static void s(double s){sb.append(s);}
    static void ss(){sb.append(' ');}
    static void sl(String s){sb.append(s);sb.append("\n");}
    static void sl(int s){sb.append(s);sb.append("\n");}
    static void sl(long s){sb.append(s);sb.append("\n");}
    static void sl(char s){sb.append(s);sb.append("\n");}
    static void sl(double s){sb.append(s);sb.append("\n");}
    static void sl(){sb.append("\n");}
    static int max(int a,int b){return a>b?a:b;}
    static int min(int a,int b){return a<b?a:b;}
    static int abs(int a){return Math.abs(a);}
    static long max(long a,long b){return a>b?a:b;}
    static long min(long a,long b){return a<b?a:b;}
    static long abs(long a){return Math.abs(a);}
    static int sq(int a){return (int)Math.sqrt(a);}
    static long sq(long a){return (long)Math.sqrt(a);}
    static int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
    static boolean pa(String s,int i,int j)
    {
    	while(i<j)if(s.charAt(i++)!=s.charAt(j--))return false;
    	return true;
    }
    static int ncr(int n,int c,long m)
    {
        long a=1l;
        for(int x=n-c+1;x<=n;x++)a=((a*x)%m);
        long b=1l;
        for(int x=2;x<=c;x++)b=((b*x)%m);
        return (int)((a*(mul((int)b,m-2,m)%m))%m);
    }
    static boolean[] sieve(int n)
    {
        boolean bo[]=new boolean[n+1];
        bo[0]=true;bo[1]=true;
        for(int x=4;x<=n;x+=2)bo[x]=true;
        for(int x=3;x*x<=n;x+=2)if(!bo[x])for(int y=x*x;y<=n;y+=x)bo[y]=true;
        return bo;
    }
    static int[] fac(int n)
    {
        int bo[]=new int[n+1];
        for(int x=1;x<=n;x++)for(int y=x;y<=n;y+=x)bo[y]++;
        return bo;
    }
    static long mul(long a,long b,long m)
    {
        long r=1l;
        a%=m;
        while(b>0)
        {
            if((b&1)==1)r=(r*a)%m;
            b>>=1;
            a=(a*a)%m;
        }
        return r;
    }
    static int i()throws IOException
    {
        if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
        return Integer.parseInt(st.nextToken());
    }
    static long l()throws IOException
    {
        if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
        return Long.parseLong(st.nextToken());
    }
    static String s()throws IOException
    {
        if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
        return st.nextToken();
    }
    static double d()throws IOException
    {
        if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
        return Double.parseDouble(st.nextToken());
    }
    static void p(Object p){System.out.print(p);}
    static void p(String p){System.out.print(p);}
    static void p(int p){System.out.print(p);}
    static void p(double p){System.out.print(p);}
    static void p(long p){System.out.print(p);}
    static void p(char p){System.out.print(p);}
    static void p(boolean p){System.out.print(p);}
    static void pl(Object p){System.out.println(p);}
    static void pl(String p){System.out.println(p);}
    static void pl(int p){System.out.println(p);}
    static void pl(char p){System.out.println(p);}
    static void pl(double p){System.out.println(p);}
    static void pl(long p){System.out.println(p);}
    static void pl(boolean p){System.out.println(p);}
    static void pl(){System.out.println();}
    static int[] ari(int n)throws IOException
    {
        int ar[]=new int[n];
        if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
        for(int x=0;x<n;x++)ar[x]=Integer.parseInt(st.nextToken());
        return ar;
    }
    static int[][] ari(int n,int m)throws IOException
    {
        int ar[][]=new int[n][m];
        for(int x=0;x<n;x++)
        {
        	if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
            for(int y=0;y<m;y++)ar[x][y]=Integer.parseInt(st.nextToken());
        }
        return ar;
    }
    static long[] arl(int n)throws IOException
    {
        long ar[]=new long[n];
        if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
        for(int x=0;x<n;x++) ar[x]=Long.parseLong(st.nextToken());
        return ar;
    }
    static long[][] arl(int n,int m)throws IOException
    {
        long ar[][]=new long[n][m];
        for(int x=0;x<n;x++)
        {
        	if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
            for(int y=0;y<m;y++)ar[x][y]=Long.parseLong(st.nextToken());
        }
        return ar;
    }
    static String[] ars(int n)throws IOException
    {
        String ar[]=new String[n];
        if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
        for(int x=0;x<n;x++) ar[x]=st.nextToken();
        return ar;
    }
    static double[] ard(int n)throws IOException
    {
        double ar[]=new double[n];
        if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
        for(int x=0;x<n;x++)ar[x]=Double.parseDouble(st.nextToken());
        return ar;
    }
    static double[][] ard(int n,int m)throws IOException
    {
        double ar[][]=new double[n][m];
        for(int x=0;x<n;x++)
        {
        	if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
            for(int y=0;y<m;y++)ar[x][y]=Double.parseDouble(st.nextToken());
        }
        return ar;
    }
    static char[] arc(int n)throws IOException
    {
        char ar[]=new char[n];
        if(!st.hasMoreTokens())st=new StringTokenizer(br.readLine());
        for(int x=0;x<n;x++)ar[x]=st.nextToken().charAt(0);
        return ar;
    }
    static char[][] arc(int n,int m)throws IOException
    {
        char ar[][]=new char[n][m];
        for(int x=0;x<n;x++)
        {
            String s=br.readLine();
            for(int y=0;y<m;y++)ar[x][y]=s.charAt(y);
        }
        return ar;
    }
    static void p(int ar[])
    {
        StringBuilder sb=new StringBuilder(2*ar.length);
        for(int a:ar)
        {
        	sb.append(a);
        	sb.append(' ');
        }
        System.out.println(sb);
    }
    static void p(int ar[][])
    {
    	StringBuilder sb=new StringBuilder(2*ar.length*ar[0].length);
        for(int a[]:ar)
        {
            for(int aa:a)
            {
            	sb.append(aa);
            	sb.append(' ');
            }
            sb.append("\n");
        }
        p(sb);
    }
    static void p(long ar[])
    {
        StringBuilder sb=new StringBuilder(2*ar.length);
        for(long a:ar)
        {
        	sb.append(a);
        	sb.append(' ');
        }
        System.out.println(sb);
    }
    static void p(long ar[][])
    {
    	StringBuilder sb=new StringBuilder(2*ar.length*ar[0].length);
        for(long a[]:ar)
        {
            for(long aa:a)
            {
            	sb.append(aa);
            	sb.append(' ');
            }
            sb.append("\n");
        }
        p(sb);
    }
    static void p(String ar[])
    {
    	int c=0;
    	for(String s:ar)c+=s.length()+1;
        StringBuilder sb=new StringBuilder(c);
        for(String a:ar)
        {
        	sb.append(a);
        	sb.append(' ');
        }
        System.out.println(sb);
    }
    static void p(double ar[])
    {
        StringBuilder sb=new StringBuilder(2*ar.length);
        for(double a:ar)
        {
        	sb.append(a);
        	sb.append(' ');
        }
        System.out.println(sb);
    }
    static void p(double ar[][])
    {
    	StringBuilder sb=new StringBuilder(2*ar.length*ar[0].length);
        for(double a[]:ar)
        {
            for(double aa:a)
            {
            	sb.append(aa);
            	sb.append(' ');
            }
            sb.append("\n");
        }
        p(sb);
    }
    static void p(char ar[])
    {
        StringBuilder sb=new StringBuilder(2*ar.length);
        for(char aa:ar)
        {
        	sb.append(aa);
        	sb.append(' ');
        }
        System.out.println(sb);
    }
    static void p(char ar[][])
    {
        StringBuilder sb=new StringBuilder(2*ar.length*ar[0].length);
        for(char a[]:ar)
        {
            for(char aa:a)
            {
            	sb.append(aa);
            	sb.append(' ');
            }
            sb.append("\n");
        }
        p(sb);
    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

class Main {
	public static void main(String args[]) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		Solver solver = new Solver();
		solver.init();
		solver.readHead(in.readLine());
		// for (; solver.hasNext();) {
		// solver.readBody(in.readLine());
		// }
		// solver.solve();
	}
}

class Solver {
	int N;
	int cnt;

	public void init() {
		N = 0;
		cnt = 0;
	}

	public void readHead(String str) {
		String[] strArr = str.split("\\s+");
		// N = Integer.parseInt(strArr[0]);
		// System.out.println(N);
		long a = Long.parseLong(strArr[0]);
		long b = Long.parseLong(strArr[1]);
		long c = Long.parseLong(strArr[2]);
		long d = Long.parseLong(strArr[3]);
		long max = a * c;
		if (max < a * d)
			max = a * d;
		if (max < b * c)
			max = b * c;
		if (max < b * d)
			max = b * d;
		System.out.println(max);
	}

	public boolean hasNext() {
		return cnt < N;
	}

	public void readBody(String str) {
		// System.out.println(str);
		cnt++;
	}

	public void solve() {

	}
}


import java.awt.desktop.AboutHandler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class template {

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static StringBuilder sb = new StringBuilder("");

    boolean[] sieveOfEratosthenes(int n)
    {
        boolean isPrime[] = new boolean[n+1];
        Arrays.fill(isPrime , true);
        isPrime[0] = false;
        isPrime[1] = false;
        for(int i = 2; i * i <= n ; i++)
        {
            for(int j = 2 * i ; j <= n; j += i)
                isPrime[i] = false;
        }
        return isPrime;
    }

    static long modExpo(long x, long y , int mod) {
        if(y == 0) {
            return 1;
        }
        if((y&1) == 0) {
            return modExpo(x * x , y >> 1 , mod);
        }
        long res = modExpo(x , y - 1 , mod) * x;
        return res > mod ? res - mod : res;
    }

    static int gcd(int a , int b) {
        if(a % b == 0) {
            return b;
        }
        return gcd(b , a % b);
    }

    static long[] inputArray(int n) throws IOException {
        long a[] = new long[n];
        st = new StringTokenizer(br.readLine());
        for(int i = 0 ; i < n ; i++) {
            a[i] = Long.parseLong(st.nextToken());
        }
        return a;
    }

    static int search(int numbers[] , int target) {
        int endIndex = -1;
        int low = 0;
        int high = numbers.length - 1;
        while (low <= high) {
            int mid = (high - low) / 2 + low;
            if (numbers[mid] > target) {
                high = mid - 1;
            } else if (numbers[mid] == target) {
                endIndex = mid;
                low = mid + 1;
            } else {
                low = mid + 1;
                endIndex = mid;
            }
        }
        return endIndex;
    }

    public static void main(String[] args) throws IOException {
        PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
        pq.add(1);
        pq.add(3);
        pq.add(5);pq.add(2);
        pq.add(2);
        pq.add(2);
        pq.add(3);
        System.out.println(pq);
        pq.remove(2);
        System.out.println(pq);
    }

    public int findLeastNumOfUniqueInts(int[] a, int k) {
        int n = a.length;
        HashMap<Integer , Integer> freq = new HashMap<>();
        for(int i = 0 ; i < n ; i++) {
            if(freq.containsKey(a[i])) {
                freq.replace(a[i] , freq.get(a[i]) + 1);
            }
            else {
                freq.put(a[i] , 1);
            }
        }

        ArrayList<Integer> list = new ArrayList<>();
        for(Map.Entry<Integer , Integer> map : freq.entrySet()) {
            list.add(map.getValue());
        }
        Collections.sort(list);
        int i = 0;
        while(k > 0) {
            k -= list.get(i);
            i++;
        }
        return n-i;
    }

}
/*
10 5
1 2 3 4 5
5 3 2 3 5 3 1 2 3 2
 */


import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.util.*;

public class Main {

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static StringBuilder sb = new StringBuilder("");

    static int[] inputArray(int n) throws IOException {
        int[] a = new int[n];
        st = new StringTokenizer(br.readLine());
        for(int i = 0 ; i < n ; i++) {
            a[i] = Integer.parseInt(st.nextToken());
        }
        return a;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        StringBuilder sb = new StringBuilder("");
        st = new StringTokenizer(br.readLine());
        long a = Long.parseLong(st.nextToken());
        long b = Long.parseLong(st.nextToken());
        long c = Long.parseLong(st.nextToken());
        long d = Long.parseLong(st.nextToken());
        if(b > 0 && d > 0) {
            System.out.println(b * c);
        }
        else if(b > 0 || d > 0) {
            if(b < 0) {
                if(c < 0) {
                    System.out.println(c*a);
                }
                else {
                    System.out.println(c*b);
                }
            }
            else {
                if(a < 0) {
                    System.out.println(a*c);
                }
                else {
                    System.out.println(a*d);
                }
            }
        }
        else {
            System.out.println(a*c);
        }
    }

    static int gcd(int a , int b) {
        if(a % b == 0) {
            return b;
        }
        return gcd(b , a % b);
    }

    static void longestGcdSeq(int a[] , int n) {
        int coprimes[] = new int[n];
        for(int i = 0 ; i < n ; i++) {
            if(a[i] < a[(i+1)%n]) {
                if(gcd(a[(i+1)%n] , a[i]) != 1) {
                    coprimes[i] = 1;
                }
            }
            else {
                if(gcd(a[i] , a[(i+1)%n]) != 1) {
                    coprimes[i] = 1;
                }
            }
        }
        //System.out.println(Arrays.toString(coprimes));
        int maxLen = 0 , startLen = 0 , endLen = 0;
        int i = 0;
        while(i < n && coprimes[i] == 1) {
            startLen++;
            i++;
        }
        i = n -1;
        while(i >= 0 && coprimes[i] == 1) {
            endLen++;
            i--;
        }
        int start = 0;
        for(i = 0 ; i < n ; i++) {
            if(coprimes[i] == 0) {
                maxLen = Math.max(maxLen , i - start);
                start = i + 1;
            }
        }
        maxLen = Math.max(maxLen , i - start);
        start = i + 1;
        //System.out.println(startLen + " " + maxLen + " " + endLen);
        int contMax = startLen == n ? n : Math.max(startLen + endLen , maxLen) + 1;
        //System.out.println(contMax);
        for(int k = 2 ; k <= n ; k++) {
            System.out.print((contMax-1)/(k-1) + " ");
        }
        System.out.println();
    }

}
/*

if(tree.size == 2) {

}

5 8
5 1 2 4 3
0 1
0 2
0 3
0 4
0 5
1 1000000000
1 1
1 500000000

 */


import java.util.Scanner;

public class Main {
  public static void main(String[] args){
    Scanner sc = new Scanner(System.in);
    int a=sc.nextInt();
    int b=sc.nextInt();
    int c=sc.nextInt();
    int d=sc.nextInt();

    int x=a*c;
    int y=a*d;
    int z=b*c;
    int w=b*d;

    if(x>=y&&x>=z&&x>=w)
    {
    	System.out.println(x);
    }else {
    	if(y>=z&&y>=w) {
    		System.out.println(y);
    	}else {
    		if(z>=w) {
    			System.out.println(z);
    		}else {
    			System.out.println(w);
    		}
    	}
    }
  }
}


#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

#define mid ((l+r)>>1)

using namespace std;

int main()
{
	long long a[5];
	for(int i=1;i<=4;i++)scanf("%lld",&a[i]);
	long long ans=a[2]*a[4];
	ans=max(ans,a[1]*a[3]);
	ans=max(ans,a[1]*a[4]);
	ans=max(ans,a[2]*a[3]);
	printf("%lld",ans);
	return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

int main(void){
    long long int i, j, n, x, d, t, s, a, b, c, ans=0, po=0;
    scanf("%lld %lld %lld %lld", &a, &b, &c, &d);
    ans = a*c;
    if(ans<a*d) ans = a*d;
    if(ans<b*c) ans = b*c;
    if(ans<b*d) ans = b*d;
    printf("%lld", ans);

}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
using namespace std;

int main(){
    long a,b,c,d;
    cin >> a >> b >> c >> d;

    long v = a*c;
    if(a*d>v) v = a*d;
    if(b*c>v) v = b*c;
    if(b*d>v) v = b*d;
    cout << v << endl;

    return 0;
}


#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
	long long a[4], ans = -10000000000;
	for (int i = 0; i < 4; i++) {
		cin >> a[i];
	}
	for (int i = 0; i < 2; i++) {
		for (int j = 2; j < 4; j++) {
			ans = max(ans, a[i] * a[j]);
		}
	}
	cout << ans << endl;
	return 0;
}


#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
	long long int a[4], ans = -1000000001;
	for (int i = 0; i < 4; i++) {
		cin >> a[i];
	}
	for (int i = 0; i < 2; i++) {
		for (int j = 2; j < 4; j++) {
			ans = max(ans, a[i] * a[j]);
		}
	}
	cout << max(ans, (long long int)0) << endl;
	return 0;
}


#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
	long long int a[4], ans = -1000000001;
	for (int i = 0; i < 4; i++) {
		cin >> a[i];
	}
	for (int i = 0; i < 2; i++) {
		for (int j = 2; j < 4; j++) {
			ans = max(ans, a[i] * a[j]);
		}
	}
	cout << ans << endl;
	return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define rep(i,l,r)for(int i=(l);i<(r);i++)

int main(void){
  long long int a,b,c,d;
  scanf("%lld %lld %lld %lld",&a,&b,&c,&d);
  long long int x,y,z,w;
  x = a*c;
  y = b*c;
  z = a*d;
  w = b*d;
  if(x<y) x=y;
  if(x<z) x=z;
  if(x<w) x=w;
  printf("%lld",x);
  return 0;
}


#include <limits.h>
#include <stdio.h>

int main(){
  int a, b, c, d, i;
  long long int x[4], max=LLONG_MIN;

  scanf("%d %d %d %d", &a, &b, &c, &d);
  x[0]=(long long int)a*c;
  x[1]=(long long int)a*d;
  x[2]=(long long int)b*c;
  x[3]=(long long int)b*d;
  for(i=0; i<4; i++)
    if(x[i]>max)
      max=x[i];
  printf("%lld\n", max);

return 0;}


#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include<math.h>
int main(){
    long long a,b,c,d, eq1=0, eq2=0, eq3=0, eq4=0;
    scanf("%lld %lld %lld %lld", &a,&b,&c,&d);
    eq1= a*c;
    eq2= a*d;
    eq3= b*c;
    eq4= b*d;
    if(eq1>= eq2 && eq1>= eq3 && eq1>= eq4)
        printf("%lld", eq1);
    else if(eq2>= eq1 && eq2>= eq3 && eq2>= eq4)
        printf("%lld", eq2);
    else if(eq3>= eq1 && eq3>= eq2 && eq3>= eq4)
        printf("%lld", eq3);
    else if(eq4>= eq1 && eq4>= eq3 && eq4>= eq2)
        printf("%lld", eq4);
    printf("\n");
    return 0;
}


#include<stdio.h>

int main(){
        long long a, b, c, d, ans;
        scanf("%lld %lld %lld %lld", &a, &b, &c, &d);
        ans=a*c;
        if(ans<a*d)ans=a*d;
        if(ans<b*c)ans=b*c;
        if(ans<b*d)ans=b*d;
        printf("%lld" ans);
        return 0;
}


#include<stdio.h>
int main()
{
  long int a,b,c,d,i;
  long long int e[4],n;
  scanf("%ld %ld %ld %ld",&a,&b,&c,&d);
  e[0]=a*c;e[1]=a*d;e[2]=b*c;e[3]=b*d;
  n=e[0];printf("%d\n",n);
  for(i=1;i<=3;i++)
  {
    if(n < e[i])
    {
      n=e[i];
    }
  }
  printf("%lld",n);
}


#include<stdio.h>
int main()
{
  int a,b,c,d,i;
  int e[4],n;
  scanf("%d %d %d %d",&a,&b,&c,&d);
  e[0]=a*c;e[1]=a*d;e[2]=b*c;e[3]=b*d;
  n=e[0];
  for(i=1;i<=3;i++)
  {
    if(n < e[i])
    {
      n=e[i];
    }
  }
  printf("%d",n);
}


'use script';

{
function Main(input) {
	//input = input.split("\n");
	tmp = input.split(" ");
	const a = BigInt(tmp[0], 10);
	const b = BigInt(tmp[1], 10);
	const c = BigInt(tmp[2], 10);
	const d = BigInt(tmp[3], 10);

  	let max = a*c;

	if(max < a*d){
      max = a*d;
    }
	if(max < b*c){
      max = b*c;
    }
  	if(max < b*d){
      max = b*d;
    }

  	console.log(max.toString());

	}

Main(require("fs").readFileSync("/dev/stdin", "utf8"));

}


function Main(input) {
	input = input.trim().split(" ");
	var a = BigInt(input[0], 10);
	var b = BigInt(input[1], 10);
    var c = BigInt(input[2], 10);
    var d = BigInt(input[3], 10);

  	var ans = a * c;
  	if(a * d > ans) ans = a * d;
  	if(b * c > ans) ans = b * c;
  	if(b * d > ans) ans = b * d;

    console.log(ans.toString());
}

Main(require("fs").readFileSync("/dev/stdin", "utf8"));


const main = arg => {
  const [a,b,c,d] = arg.trim().split(' ').map(x => BigInt(x));
  let max = a * c
  if (a * d > max) max = a * d
  if (b * c > max) max = b * c
  if (b * d > max) max = b * d
  console.log(max.toString())
}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));


const Main = (input) => {
  const[A,B,C,D] = input.split(' ').map(Number);
  const numbers = [A * C, A * D, B * C, C * D];

  console.log(Math.max.apply(null, numbers));
}

Main(require("fs").readFileSync("/dev/stdin", "utf8"));
// Main(`-1000000000 0 -1000000000 0`);


const Main = (input) => {
  const[A,B,C,D] = input.split(' ').map(Number);
  let numbers = [];
  for(let i = A; i <= B; i++) {
    for(let j = C; j <= D; j++) {
      numbers.push(i*j);
    }
  }
  console.log(Math.max.apply(null, numbers));
}

Main(require("fs").readFileSync("/dev/stdin", "utf8"));
// Main(`-1000000000 0 -1000000000 0`);


const main = arg => {
  const [a, b, c, d] = arg.split(' ').map(BigInt);
  const ary = [a * c, a * d, b * c, b * d];
  const max = ary.reduce((x, y) => x > y ? x : y);
  console.log(Number(max));
};
main(require('fs').readFileSync('/dev/stdin', 'utf8'));


package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
	"strings"

)

func main() {
	solve(os.Stdin, os.Stdout)
}

type ReaderEx struct {
	baseScanner *bufio.Scanner
	words       []string
	nextWordIdx func() int
	initWordIdx func(int)
}

func NewScannerEx(stdin io.Reader) *ReaderEx {
	var this ReaderEx
	var idx int
	var wordsCnt int
	this.baseScanner = bufio.NewScanner(stdin)
	this.baseScanner.Buffer(make([]byte, 0), 1E+11)
	this.nextWordIdx = func() int {
		cur := idx
		idx = (idx + 1) % wordsCnt
		return cur
	}
	this.initWordIdx = func(wc int) {
		idx = 0
		wordsCnt = wc
	}
	return &this
}

func (me *ReaderEx) Scan(doSplit bool) (isScanned bool) {
	isScanned = me.baseScanner.Scan()
	if doSplit {
		me.words = strings.Fields(me.baseScanner.Text())
	} else {
		me.words = []string{me.baseScanner.Text()}
	}
	me.initWordIdx(len(me.words))
	return
}

func (me *ReaderEx) nextBytes() []byte {
	return []byte(me.words[me.nextWordIdx()])
}
func (me *ReaderEx) nextString() string {
	return me.words[me.nextWordIdx()]
}

type StringArray []string

func (me *ReaderEx) nextStringArray() StringArray {
	return me.words[me.nextWordIdx():]
}

func (me StringArray) toStrings() []string {
	return me
}

func (me StringArray) toInts() []int {
	strValues := me.toStrings()
	values := make([]int, len(strValues))
	for i, v := range strValues {
		n, err := strconv.Atoi(v)
		if err != nil {
			panic(err)
		}
		values[i] = n
	}
	return values
}
func (me *ReaderEx) nextInt() int {
	n, err := strconv.Atoi(me.words[me.nextWordIdx()])

	defer func() {
		if err != nil {
			panic(fmt.Sprintf("getInt(%d)", n))
		}
	}()
	return n
}

func pow(x, y, mod int) (ans int) {

	ans = 1
	for bit := 1 << uint(math.Floor(math.Log2(float64(y)))); ; bit >>= 1 {
		if y&bit != 0 {
			ans *= x
			if mod > 0 {
				ans %= mod
			}
		}
		if bit <= 1 {
			return
		}
		ans *= ans
		if mod > 0 {
			ans %= mod
		}
	}
}

type factType struct {
	prime int
	count int
}

func fact(n int) (facts []*factType) {

	for i := 2; i*i <= n; i++ {
		if n%i == 0 {
			fa := factType{prime: i}
			for n%fa.prime == 0 {
				n /= fa.prime
				fa.count++
			}
			facts = append(facts, &fa)
		}
	}
	if n > 1 {
		facts = append(facts, &factType{prime: n, count: 1})
	}
	return facts
}
func dec2bin(n int) (ret []bool) {
	for bit := 1 << uint(math.Floor(math.Log2(float64(n)))); ; bit >>= 1 {
		ret = append(ret, n&bit != 0)

		if bit <= 1 {
			return
		}
	}

}

func abs(v int) int {
	if v < 0 {
		v = -v
	}
	return v
}

func b2i(b bool) (i int) {
	if b {
		i = 1
	} else {
		i = 0
	}
	return
}

func solve(stdin io.Reader, stdout io.Writer) {

	r := NewScannerEx(stdin)
	r.Scan(true)
	a, b, c, d := r.nextInt(), r.nextInt(), r.nextInt(), r.nextInt()

	maxInt := func(a int, vs ...int) int {
		for i := range vs {
			v := &vs[i]
			if a < *v {
				a = *v
			}
		}
		return a
	}
	fmt.Fprintln(stdout, maxInt(a*c, a*d, b*c, b*d))
}


package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"sort"
	"strconv"
)

func main() {
	fmt.Println(abc178b(os.Stdin))
}

func nextInt(sc *bufio.Scanner) int {
	sc.Scan()
	i, _ := strconv.Atoi(sc.Text())
	return i
}

func nextLine(sc *bufio.Scanner) string {
	sc.Scan()
	return sc.Text()
}

func abc178b(r io.Reader) int {
	sc := bufio.NewScanner(r)
	sc.Split(bufio.ScanWords)

	a, b, c, d := nextInt(sc), nextInt(sc), nextInt(sc), nextInt(sc)

	//最大値、最小値スライス作成
	s := []int{a * c, a * d, b * c, b * d}
	sort.Sort(sort.Reverse(sort.IntSlice(s)))

	return s[0]
}


package main

import (
  "os"
  "fmt"
  "bufio"
  "strconv"
)

var sc = bufio.NewScanner(os.Stdin)

func nextInt() int {
  sc.Scan()
  i, err := strconv.Atoi(sc.Text())
  if err != nil {
    panic(err)
  }
  return i
}

func main() {
  sc.Split(bufio.ScanWords)

  a := nextInt()
  b := nextInt()
  c := nextInt()
  d := nextInt()
  max := a * c
  if b * d > max {
    max = b * d
  }
  if a * d > max {
  	max = a * d
  }
  if b * c > max {
    max = b * c
  }
  fmt.Println(max)
}


package main

import (
	"fmt"
	"math"
)

func main() {
	var a, b, c, d int
	fmt.Scan(&a, &b, &c, &d)

	res := math.MinInt64
	for i := a; i <= b; i++ {
		for j := c; j <= d; j++ {
			product := i * j
			if product > res {
				res = product
			}
		}
	}

	fmt.Println(res)
}


package main

import (
	"fmt"
	"math"
)

func main() {
	var a, b, c, d int
	var ans1 int
	var ans2 int
	fmt.Scan(&a, &b, &c, &d)
	ans1 = max(a*c, a*d)
	ans2 = max(b*c, b*d)
	fmt.Println(max(ans1, ans2))

}

func min(nums ...int) int {
	if len(nums) == 0 {
		panic("funciton min() requires at least one argument.")
	}
	res := nums[0]
	for i := 0; i < len(nums); i++ {
		res = int(math.Min(float64(res), float64(nums[i])))
	}
	return res
}

func max(nums ...int) int {
	if len(nums) == 0 {
		panic("funciton max() requires at least one argument.")
	}
	res := nums[0]
	for i := 0; i < len(nums); i++ {
		res = int(math.Max(float64(res), float64(nums[i])))
	}
	return res
}


package main

import "fmt"

func main() {
	nums := make([]int, 4)
	for i:=0; i<len(nums); i++{
		fmt.Scan(&nums[i])
	}

	max := 0
	for i:=0; i<2; i++{
		if max < nums[i] * nums[2]{
			max = nums[i] * nums[2]
		}
		if max < nums[i] * nums[3]{
			max = nums[i] * nums[3]
		}
	}
	fmt.Println(max)
}


a,b,c,d = gets.chomp.split(' ').map(&:to_i)
ab = [a,b].sort
cd = [c,d].sort
ans = []
ans << ab[0]*cd[0]
ans << ab[0]*cd[1]
ans << ab[1]*cd[0]
ans << ab[1]*cd[1]
ans = ans.sort
p ans [-1]


a,b,c,d = gets.split.map(&:to_i)
puts [a*c, a*d, b*c, b*d].max


a,b,c,d=gets.split.map &:to_i
p [a*c,a*d,b*c,b*d].max


a,b,c,d = gets.split.map(&:to_i)
puts [a*c,a*d,b*c,d*d].max


a,b,c,d = gets.split(" ").map(&:to_i)
z = []
(a..b).each do |x|
  (c..d).each do |y|
    z << x * y
  end
end

puts z.max


line = gets.split(' ')
if line[0] > line[1] then
   x = line[0]
else
   x = line[1]
end

if line[2] > line[3] then
   y = line[2]
else
   y = line[3]
end
max = x.to_i * y.to_i
p max


use proconio::fastout;
use whiteread::parse_line;

#[fastout]
fn main() {
    let (a, b, c, d): (i64, i64, i64, i64) = parse_line().unwrap();

    println!(
        "{}",
        *[a*c, a*d, b*c, b*d].iter().max().unwrap()
    );
}


#[allow(unused_macros)]
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        let mut next = || { iter.next().unwrap() };
        input_inner!{next, $($r)*}
    };
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes
                .by_ref()
                .map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

#[allow(unused_macros)]
macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};

    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let mut $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

#[allow(unused_macros)]
macro_rules! read_value {
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };

    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };

    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };

    ($next:expr, bytes) => {
        read_value!($next, String).into_bytes()
    };

    ($next:expr, usize1) => {
        read_value!($next, usize) - 1
    };

    ($next:expr, $t:ty) => {
        $next().parse::<$t>().expect("Parse error")
    };
}

use std::cmp::Ordering;
use std::cmp;
use std::cmp::min;
use std::collections::BTreeMap;
use std::process;
use std::cmp::Ord;
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::collections::BTreeSet;
use std::mem;
use std::collections::BinaryHeap;
use std::hash::{Hash, Hasher};

// ---------- begin ModInt ----------

#[derive(Clone, Copy)]
struct ModInt(usize);
impl std::ops::Add for ModInt {
    type Output = ModInt;
    fn add(self, rhs: ModInt) -> Self::Output {
        let mut d = self.0 + rhs.0;
        if d >= MODu {
            d -= MODu;
        }
        ModInt(d)
    }
}

impl std::ops::AddAssign for ModInt {
    fn add_assign(&mut self, rhs: ModInt) {
        *self = *self + rhs;
    }
}

impl std::ops::Sub for ModInt {
    type Output = ModInt;
    fn sub(self, rhs: ModInt) -> Self::Output {
        let mut d = self.0 + MODu - rhs.0;
        if d >= MODu {
            d -= MODu;
        }
        ModInt(d)
    }
}

impl std::ops::SubAssign for ModInt {
    fn sub_assign(&mut self, rhs: ModInt) {
        *self = *self - rhs;
    }
}

impl std::ops::Mul for ModInt {
    type Output = ModInt;
    fn mul(self, rhs: ModInt) -> Self::Output {
        ModInt((self.0 as u64 * rhs.0 as u64 % MODu as u64) as usize)
    }
}

impl std::ops::MulAssign for ModInt {
    fn mul_assign(&mut self, rhs: ModInt) {
        *self = *self * rhs;
    }
}

impl std::ops::Neg for ModInt {
    type Output = ModInt;
    fn neg(self) -> Self::Output {
        ModInt(if self.0 == 0 {0} else {MODu - self.0})
    }
}

impl std::fmt::Display for ModInt {
    fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl std::str::FromStr for ModInt {
    type Err = std::num::ParseIntError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let val = s.parse::<usize>()?;
        Ok(ModInt::new(val))
    }
}
impl PartialEq for ModInt {
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0
    }
}
impl Hash for ModInt {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
        self.0.hash(state);
    }
}
impl Eq for ModInt {}
#[allow(dead_code)]
impl ModInt {
    pub fn new(n: usize) -> ModInt {
        ModInt(n % MODu)
    }
    pub fn zero() -> ModInt {
        ModInt(0)
    }
    pub fn one() -> ModInt {
        ModInt(1)
    }
    pub fn pow(self, mut n: usize) -> ModInt {
        let mut t = ModInt::one();
        let mut s = self;
        while n > 0 {
            if n & 1 == 1 {
                t *= s;
            }
            s *= s;
            n >>= 1;
        }
        t
    }
    pub fn inv(self) -> ModInt {
        self.pow(MODu - 2)
    }
}
// ---------- end ModInt ----------

/// Equivalent to std::lowerbound and std::upperbound in c++
pub trait BinarySearch<T> {
    fn lower_bound(&self, x:&T) -> usize;
    fn upper_bound(&self, x:&T) -> usize;
}

impl<T: Ord> BinarySearch<T> for VecDeque<T>{
    fn lower_bound(&self, x: &T) -> usize {
        let mut low = 0;
        let mut high = self.len();

        while low != high {
            let mid = (low + high) / 2;
            match self[mid].cmp(x) {
                Ordering::Less => {
                    low = mid + 1;
                }
                Ordering::Equal | Ordering::Greater => {
                    high = mid;
                }
            }
        }
        low
    }

    fn upper_bound(&self, x: &T) -> usize {
        let mut low = 0;
        let mut high = self.len();

        while low != high {
            let mid = (low + high) / 2;
            match self[mid].cmp(x) {
                Ordering::Less | Ordering::Equal => {
                    low = mid + 1;
                }
                Ordering::Greater => {
                    high = mid;
                }
            }
        }
        low
    }
}
impl<T: Ord> BinarySearch<T> for [T]{
    fn lower_bound(&self, x: &T) -> usize {
        let mut low = 0;
        let mut high = self.len();

        while low != high {
            let mid = (low + high) / 2;
            match self[mid].cmp(x) {
                Ordering::Less => {
                    low = mid + 1;
                }
                Ordering::Equal | Ordering::Greater => {
                    high = mid;
                }
            }
        }
        low
    }

    fn upper_bound(&self, x: &T) -> usize {
        let mut low = 0;
        let mut high = self.len();

        while low != high {
            let mid = (low + high) / 2;
            match self[mid].cmp(x) {
                Ordering::Less | Ordering::Equal => {
                    low = mid + 1;
                }
                Ordering::Greater => {
                    high = mid;
                }
            }
        }
        low
    }
}

fn matmul(A:&Vec<Vec<i64>>, B:&Vec<Vec<i64>>) -> Vec<Vec<i64>>{
    let mut C = vec![vec![0;B[0].len()];A.len()];
    for i in 0..A.len(){
        for k in 0..B.len(){
            for j in 0..B[0].len(){
                C[i][j] += A[i][k]*B[k][j];
                C[i][j] %= MOD;
            }
        }
    }
    return C;
}
fn matpow(A:&mut Vec<Vec<i64>>, n:usize) -> Vec<Vec<i64>>{
    let mut B = vec![vec![0;A.len()];A.len()];
    for i in 0..A.len(){
        B[i][i] = 1;
    }
    let mut n = n;
    let mut tmp = A.clone();
    while(n>0){
        if n&1 == 1{B = matmul(&B, &tmp);}
        tmp = matmul(&tmp, &tmp);
        n>>=1;
    }
    return B;
}
fn matmul2(A:&Vec<Vec<ModInt>>, B:&Vec<Vec<ModInt>>) -> Vec<Vec<ModInt>>{
    let mut C = vec![vec![ModInt(0);B[0].len()];A.len()];
    for i in 0..A.len(){
        for k in 0..B.len(){
            for j in 0..B[0].len(){
                C[i][j] += A[i][k]*B[k][j];
            }
        }
    }
    return C;
}
fn matpow2(A:&mut Vec<Vec<ModInt>>, n:usize) -> Vec<Vec<ModInt>>{
    let mut B = vec![vec![ModInt(0);A.len()];A.len()];
    for i in 0..A.len(){
        B[i][i] = ModInt(1);
    }
    let mut n = n;
    let mut tmp = A.clone();
    while(n>0){
        if n&1 == 1{B = matmul2(&B, &tmp);}
        tmp = matmul2(&tmp, &tmp);
        n>>=1;
    }
    return B;
}

fn divisor(n:usize) -> Vec<usize>{
    let mut res:Vec<usize> = Vec::new();
    for i in 1..n+1{
        if i*i>n{break;}
        if n%i == 0{
            res.push(i);
            if i != n/i{
                res.push(n/i);
            }
        }
    }
    res
}
struct UnionFind{
    par:Vec<usize>,
    rank:Vec<usize>,
    size:Vec<usize>,
    size_edge:Vec<usize>,
}
impl UnionFind{
    fn init(n:usize) -> UnionFind{
        let mut par = vec![0;n];
        for i in 0..n{
            par[i] = i;
        }
        UnionFind{
            par:par,
            rank:vec![0;n],
            size:vec![1;n],
            size_edge:vec![0;n],
        }
    }
    fn find(&mut self, x:usize) ->usize{
        if(self.par[x] == x){
            x
        }
        else{
            let p = self.par[x];
            let res = self.find(p);
            self.par[x] = res;
            res
        }
    }
    fn same(&mut self, a:usize, b:usize)->bool{
        self.find(a) == self.find(b)
    }
    fn unite(&mut self, a:usize, b:usize){
        let x = self.find(a);
        let y = self.find(b);
        if x != y{
            if (self.rank[x] < self.rank[y]){
                self.par[x] = y;
                self.size[y] += self.size[x];
                self.size_edge[y] += self.size_edge[x];
                self.size_edge[y] += 1;
            }
            else{
                self.par[y] = x;
                self.size[x] += self.size[y];
                self.size_edge[x] += self.size_edge[y];
                self.size_edge[x] += 1;
                if(self.rank[x] == self.rank[y]){ self.rank[x]+=1;}
            }

        }
        else{
            self.size_edge[x] += 1;
        }
    }
    fn check_size(&mut self, a:usize) -> usize{
        let x = self.find(a);
        let s = self.size[x];
        s
    }
}
pub struct Scanner<R> {
    stdin: R,
}

impl<R: std::io::Read> Scanner<R> {
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        use std::io::Read;
        let buf = self
            .stdin
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n' || b == b'\r')
            .take_while(|&b| b != b' ' && b != b'\n' && b != b'\r')
            .collect::<Vec<_>>();
        std::str::from_utf8(&buf).unwrap()
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }
    pub fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}
struct LazySegTree<BiOp> {
    n: usize,
    val: Vec<i64>,
    ma:Vec<i64>,
    op: BiOp,
    e: i64,
    upe:i64,
    inf:i64,
}

impl<BiOp> LazySegTree<BiOp>
    where BiOp: Fn(i64, i64) -> i64{
    pub fn new(n_: usize, op: BiOp, e: i64, upe:i64, inf:i64) -> Self {
        let mut n = 1;
        while n < n_ { n *= 2; } // n is a power of 2

        LazySegTree {n: n, val: vec![e; 2 * n ], ma:vec![upe;2*n], op: op, e: e, upe:upe, inf:inf}
    }
    pub fn query(&self, x:usize, y:usize, l:usize, r:usize, k:usize) -> i64 {
        if (r<=x || y<=l) {return self.inf;}
        if (x<=l && r<=y) {return self.ma[k];}
        let mut L = self.query(x,y,l,(l+r)/2, k*2);
        let mut R = self.query(x,y,(l+r)/2,r, k*2+1);
        return self.val[k] + (self.op)(L, R);

    }

    pub fn update(&mut self, x:usize, y:usize, v:i64, l:usize,r:usize, k:usize) {
        if (l>=r) {return;}
        if (x<=l && r<=y){
            self.val[k]+=v;
            self.ma[k]+=v;
        }
        else if(l<y && x<r){
            self.update(x, y, v, l, (l+r)/2, k*2);
            self.update(x,y,v,(l+r)/2,r, k*2+1);
            self.ma[k] = self.val[k] + (self.op)(self.ma[k*2], self.ma[k*2+1]);
        }
    }
}
fn modinv(a:ModInt)->ModInt{
    let mut a = a.0 as usize;
    let mut b = MODu as i64;
    let mut u = 1 as i64;
    let mut v = 0 as i64;
    let mut a = a as i64;
    let mut m = MODu as i64;
    while(b>0){
        let mut t = a/b;
        a -= t*b;
        mem::swap(&mut a, &mut b);
        u-=t*v;
        mem::swap(&mut u, &mut v);
    }
    u%=m;
    if u<0{u+=m;}
    return ModInt(u as usize);

}
fn modinv2(a:usize)->usize{
    let mut a = a as usize;
    let mut b = MODu as i64;
    let mut u = 1 as i64;
    let mut v = 0 as i64;
    let mut a = a as i64;
    let mut m = MODu as i64;
    while(b>0){
        let mut t = a/b;
        a -= t*b;
        mem::swap(&mut a, &mut b);
        u-=t*v;
        mem::swap(&mut u, &mut v);
    }
    u%=m;
    if u<0{u+=m;}
    return u as usize;

}
fn modpow(x:ModInt, n:ModInt) -> ModInt{
        let mut ans = ModInt(1);
        let mut n = n.0 as usize;
        let mut x = x;
        while(n != 0){
            if (n&1 == 1){ans = ans*x;}
            x = x*x;
            n = n>>1;
        }
        ans
}
fn comb(a:usize, b:usize,  fac:&Vec<ModInt>, ifac:&Vec<ModInt>)->ModInt{
        let mut a = a;
        let mut b = b;
        if a == 0 && b == 0{return ModInt(1);}
        if a<b || a<0{return ModInt(0);}
        let mut tmp = ifac[a-b]*ifac[b];
        return tmp * fac[a];
}

fn invs()->(Vec<ModInt>, Vec<ModInt>){
    let mut fac = vec![ModInt(0);600001];
    let mut ifac = vec![ModInt(0);600001];
    fac[0] = ModInt(1);
    ifac[0] = ModInt(1);
    for i in 0..600000{

        fac[i+1] = fac[i] * ModInt(i+1);
        ifac[i+1] = ifac[i] * modpow(ModInt(i+1), ModInt(MODu - 2));
    }
    (fac, ifac)
}

struct ConvexHallTrick {
    Q: Vec<(i64, i64)>,
}

impl ConvexHallTrick{
    pub fn new() -> Self {

        ConvexHallTrick {Q: Vec::new()}
    }
    pub fn calc(&self, p:(i64, i64), x:i64)->i64{
        return p.0 * x + p.1;
    }
    pub fn dodo(& self, A:(i64, i64), B:(i64, i64), C:(i64, i64)) -> bool{
        //max or min
        (A.1 - C.1) * (B.0 - A.0) <= (A.1 - B.1)*(C.0 - A.0)
    }
    pub fn add(&mut self, a:i64, b:i64){
        self.Q.push((a, b));
        let mut v = self.Q.len();
        while(v >=3 && self.dodo(self.Q[v-3], self.Q[v-2], self.Q[v-1])){
            self.Q[v-2] = self.Q[v-1];
            self.Q.pop();
            v = self.Q.len();
        }
    }
    pub fn query(& self, x:i64) -> i64{
        let mut L = -1;
        let mut R = (self.Q.len() - 1) as i64;
        while(R-L>1){
            let mut m = (L+R)/2;
            if self.calc(self.Q[m as usize], x)>=self.calc(self.Q[m as usize+1], x){
                L=m;
            }
            else{
                R=m;
            }

        }
        return self.calc(self.Q[R as usize], x);
    }
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Rev<T>(pub T);
impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}
impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
}
fn sieve(n:usize) -> (Vec<bool>, Vec<usize>){
    let mut p:usize = 0;
    let mut is_prime = vec![false; n+1];
    let mut prime = Vec::new();
    for i in 0..n+1{
        is_prime[i] = true;
    }
    is_prime[0] = false;
    is_prime[1] = false;
    for i in 2..n+1{
        if is_prime[i]{
            prime.push(i as usize);
            let mut j = 2*i;
            while(j<=n){
                is_prime[j] = false;
                j+=i;
            }
        }
    }
    (is_prime, prime)

}
fn nHr(n:usize, r:usize, fac:&Vec<ModInt>, ifac:&Vec<ModInt>) -> ModInt{
    if n+r == 0{
        return ModInt(1);
    }
    comb(n + r - 1, r, fac, ifac)
}
fn gcd(a:usize, b:usize)->usize{
    if b==0{return a;}
    return gcd(b, a%b);
}
fn lcm(a:usize, b:usize)->usize{
    return (b/gcd(a, b))*a;
}
struct SegTree_MOD<BiOp> {
    n: usize,
    dat: Vec<i64>,
    op: BiOp,
    e: i64,
    mod_:i64,
}
impl<BiOp> SegTree_MOD<BiOp>
    where BiOp: Fn(i64, i64) -> i64
          {
    pub fn new(n_: usize, op: BiOp, e: i64, mod_:i64) -> Self {
        let mut n = 1;
        while n < n_ { n *= 2; } // n is a power of 2
        SegTree_MOD {n: n, dat: vec![e; 2 * n - 1], op: op, e: e, mod_:mod_}
    }
    /* ary[k] <- v */
    pub fn update(&mut self, idx: usize, v: i64) {
        let mut k = idx + self.n - 1;
        self.dat[k] = v;
        while k > 0 {
            k = (k - 1) / 2;
            self.dat[k] = (self.op)(self.dat[2 * k + 1], self.dat[2 * k + 2]);
            self.dat[k] %= self.mod_;
        }
    }
    /* [a, b) (note: half-inclusive)
     * http://proc-cpuinfo.fixstars.com/2017/07/optimize-segment-tree/ */
    pub fn query(&self, mut a: usize, mut b: usize) -> i64 {
        let mut left = self.e;
        let mut right = self.e;
        a += self.n - 1;
        b += self.n - 1;
        while a < b {
            if (a & 1) == 0 {
                left = (self.op)(left, self.dat[a]);
                left %= self.mod_;
            }
            if (b & 1) == 0 {
                right = (self.op)(self.dat[b - 1], right);
                right %= self.mod_;
            }
            a = a / 2;
            b = (b - 1) / 2;
        }
        let mut res = (self.op)(left, right);
        res %= self.mod_;
        res

    }
}
fn modpow2(x:usize, n:usize) -> usize{
        let mut ans = 1;
        let mut n = n;
        let mut x = x;
        while(n != 0){
            if (n&1 == 1){ans = ans*x%MODu;}
            x = x*x%MODu;
            n = n>>1;
        }
        ans
}
#[derive(Clone)]
struct PPUnionFind{
    par:Vec<usize>,
    rank:Vec<usize>,
    time:Vec<usize>,
    now:usize,
    history:Vec<(usize, usize)>,
}
impl PPUnionFind{
    fn init(n:usize) -> PPUnionFind{
        let mut par = vec![0;n];
        for i in 0..n{
            par[i] = i;
        }
        PPUnionFind{
            par:par,
            rank:vec![0;n],
            time:vec![INF as usize;n],
            now:0,
            history:vec![],
        }
    }
    fn find(&mut self, t:usize, x:usize) ->usize{
        if self.time[x] > t{return x;}
        else { let tt = self.par[x]; return self.find(t, tt);}
    }
    fn unite(&mut self, x:usize, y:usize) -> usize{
        self.now+=1;
        let mut x = x;
        let mut y = y;
        let nc = self.now;
        x = self.find(nc, x);
        y = self.find(nc, y);
        if x == y{return self.now;}
        if self.par[x] < self.par[y] {mem::swap(&mut x, &mut y);}
        self.par[x] += self.par[y];
        self.history.push((self.now, self.par[x]));
        self.par[y] = x;
        self.time[y] = self.now;
        return self.now;
    }
}

fn prim(cost:&Vec<Vec<(usize, i64)>>, vs:usize)->i64{
    let mut used = vec![false; vs];
    let mut bh = BinaryHeap::new();
    for j in 0..cost[0].len(){
            bh.push((cost[0][j].1 * -1, cost[0][j].0));
    }
    used[0] = true;
    let mut res = 0;
    while(bh.len()!=0){
        let mut m = bh.pop().unwrap();
        if used[m.1]{continue;}
        used[m.1] = true;
        for e in 0..cost[m.1].len(){
            if used[cost[m.1][e].0] == false{
                bh.push((cost[m.1][e].1 * -1, cost[m.1][e].0));
            }
        }
        res += m.0*-1;
    }
    return res;
}
fn kruscal(cost:&mut Vec<(i64, usize, usize)>, vs:usize)->i64{
    cost.sort();
    let mut uf = UnionFind::init(vs);
    let mut res = 0;

    for i in 0..cost.len(){
        let e = cost[i].clone();
        if uf.find(e.1) != uf.find(e.2){
            uf.unite(e.1, e.2);
            res += e.0;
        }
    }
    return res;
}
fn kruscal3(cost:&mut Vec<(f64, usize, usize, usize)>, vs:usize)->(UnionFind, Vec<usize>) {
    cost.sort_by(|a, b| (&a.0).partial_cmp(&b.0).unwrap());
    let mut uf = UnionFind::init(vs);
    let mut res = 0.0;
    let mut rv = Vec::new();
    let mut c = 0.0;
    let mut t = 0.0;
    for i in 0..cost.len(){
        let e = cost[i].clone();
        if uf.find(e.1) != uf.find(e.2){
            uf.unite(e.1, e.2);
            rv.push(e.3);
        }
    }
    return (uf,rv);
}
fn kruscal2(cost:&mut Vec<(f64, usize, usize)>, vs:usize)->f64{
    cost.sort_by(|a, b| (&a.0).partial_cmp(&b.0).unwrap());
    let mut uf = UnionFind::init(vs);
    let mut res = 0.0;
    for i in 0..cost.len(){
        let e = cost[i].clone();
        if uf.find(e.1) != uf.find(e.2){
            uf.unite(e.1, e.2);
            res+= e.0;
        }
    }
    return res;
}

struct segtree<I, Op>{
    n: usize,
    dat: Vec<I>,
    op:Op,
    e:I,
}
impl<I, Op> segtree<I, Op>

    where Op: Fn(I, I) -> I, I:Copy{

        pub fn new(n_:usize, op: Op, e:I)->Self{
            let mut n = 1;
            while(n<n_){n*=2;}
            segtree{n: n, dat:vec![e; 2*n-1], op:op, e:e}
        }
        pub fn update(&mut self, k:usize, a:I){
            let mut k = k;
            k += self.n-1;
            self.dat[k] = a;
            while(k>0){
                k = (k-1)/2;
                self.dat[k] = (self.op)(self.dat[k*2 + 1], self.dat[k*2+2]);
            }
        }
        pub fn query(&self, a:usize, b:usize, k:usize, l:usize, r:usize) -> I{
            if r<=a || b<=l{return self.e;}
            if a<=l && r<=b{return self.dat[k];}
            else{
                let mut vl = self.query(a, b, k*2+1, l, (l+r)/2);
                let mut vr = self.query(a, b, k*2+2, (l+r)/2, r);
                return (self.op)(vl, vr);
            }
        }
    }
struct BIT<I, Op>{
    n:usize,
    bit:Vec<I>,
    op:Op,
    e:I,
    ini:I,
}
impl <I, Op>  BIT<I, Op>
    /* 1-index*/
    where Op: Fn(I, I) -> I, I:Copy{
        pub fn new(n_:usize, op:Op, e:I, ini:I)->Self{
            BIT{n:n_, bit:vec![e;n_+1], op:op, e:e, ini:ini}
        }
        pub fn sum(&self, i:usize)->I{
            let mut s = self.ini;
            let mut i = i as i64;
            while(i>0){
                s = (self.op)(s, self.bit[i as usize]);
                i -= i & -i;
            }
            return s;
        }
        pub fn add(&mut self, i:usize, x:I){
            let mut i = i as i64;
            while(i<=self.n as i64){
                self.bit[i as usize] = (self.op)(self.bit[i as usize], x);
                i += i & -i;
            }
        }
    }
struct Dsegtree{
    n: usize,
    datA: Vec<i64>,
    datB:Vec<i64>,
    e:i64,
}
impl Dsegtree{
        pub fn new(n_:usize, e:i64)->Self{

            Dsegtree{n:n_, datA:vec![e; 1<<22 - 1], datB:vec![e;1<<22 - 1], e:e}
        }
        pub fn update(&mut self,a:usize, b:usize, x:i64,  k:usize, l:usize, r:usize){
            //println!("{} {} {} {} {} {}", a, b, x, k , l, r);
            if a<=l && r<=b{
                self.datA[k] += x;
            }
            else if (l<b && a<r){
                self.datB[k] += (cmp::min(b, r) as i64 - cmp::max(a, l) as i64) * x;
                self.update(a, b, x, k*2+1, l, (l+r)/2);
                self.update(a, b, x, k*2+2, (l+r)/2, r);
            }
        }
        pub fn query(&self, a:usize, b:usize, k:usize, l:usize, r:usize) -> i64{
            if (b<=l || r<=a){
                return 0;
            }
            else if (a<=l && r<=b){
                return self.datA[k] * ((r as i64-l as i64)) + self.datB[k];
            }
            else{
                let mut res = (cmp::min(b, r) as i64 - cmp::max(a, l) as i64)* self.datA[k];
                res += self.query(a, b, k*2+1, l, (l+r)/2);
                res += self.query(a, b, k*2+2, (l+r)/2, r);
                return res;
            }
        }
    }
/*
unwrap_or_else
*/
fn prime_factor(n:usize)->HashMap<usize, usize>{
    let mut res = HashMap::new();
    let mut n = n;
    for i in 2..n{
        if i*i>n{break;}
        while(n%i==0){
            *res.entry(i).or_insert(0)+=1;
            n/=i;
        }
    }
    if n != 1{
        res.insert(n, 1);
    }
    res
}
struct rollinghash{
    base:Vec<i64>,
    Mod:Vec<i64>,
    hash:Vec<Vec<i64>>,
    power:Vec<Vec<i64>>,
}
impl rollinghash{
    pub fn new(s:&Vec<usize>)->Self{
        let mut n = s.len();
        let mut base = vec![1007, 2009];
        let mut hash = vec![vec![0;n+1];2];
        let mut power = vec![vec![1;n+1];2];
        let mut Mod = vec![1000000007, 1000000009];
        for iter in 0..2{
            let mut ht = vec![0;n+1];
            let mut pt = vec![1;n+1];
            for i in 0..n{
                hash[iter][i+1] = (hash[iter][i] * base[iter] + s[i] as i64) % Mod[iter];
                power[iter][i+1] = power[iter][i] * base[iter] % Mod[iter];
            }
        }
        return rollinghash{base:base, Mod:Mod, hash:hash, power:power}

    }
    pub fn get(&self, l:usize, r:usize)->(i64, i64){
        let mut res = self.hash[0][r] - self.hash[0][l] * self.power[0][r-l] % self.Mod[0];
        if res<0{
            res += self.Mod[0];
        }
        let mut res2 = self.hash[1][r] - self.hash[1][l] * self.power[1][r-l] % self.Mod[1];
        if res2<0{
            res2 += self.Mod[1];
        }
        return (res, res2);
    }

}
struct LCA{
    G:Vec<Vec<(usize, i64)>>,
    depth:Vec<i64>,
    len:Vec<i64>,
    parent:Vec<Vec<usize>>,
    V:usize,
    logV:usize,
}
impl LCA{
    pub fn new(V:usize, G:&Vec<Vec<(usize, i64)>>)->Self{
        let mut logV = 0;
        while(V>(1<<logV)){logV+=1;}
        return LCA{G:G.clone(), logV:logV, V:V, depth:vec![0;V], len:vec![0;V], parent:vec![vec![INFu;V];logV]}
    }
    pub fn init(&mut self, v:usize, par:usize, d:i64, l:i64){
        self.depth[v] = d;
        self.parent[0][v] = par;
        self.len[v] = l;
        for i in 0..self.G[v].len(){
            let mut w = self.G[v][i].0;
            let mut lc = self.G[v][i].1;
            if w == par{continue;}
            self.init(w, v, d+1, lc+l);
        }
    }
    pub fn build(&mut self, root:usize){
        self.init(root, INFu, 0, 0);
        for k in 0..(self.logV-1){
            for v in 0..self.V{
                if self.parent[k][v] == INFu{
                    self.parent[k+1][v] = INFu;
                }
                else{
                    self.parent[k+1][v] = self.parent[k][self.parent[k][v]];
                }
            }
        }
    }
    pub fn lca(&self, u:usize, v:usize)->usize{
        let mut u = u;
        let mut v = v;
        if self.depth[u]>self.depth[v]{
            mem::swap(&mut u, &mut v);
        }
        for k in 0..self.logV{
            if ((self.depth[v]-self.depth[u]) >> k) & 1 == 1{
                v = self.parent[k][v];
            }
        }
        if u == v{
            return u;
        }
        for k in (0..self.logV).rev(){
            if self.parent[k][u] != self.parent[k][v]{
                u = self.parent[k][u];
                v = self.parent[k][v];
            }
        }
        return self.parent[0][u];
    }
    pub fn dist(&self, u:usize, v:usize)->i64{
        let z = self.lca(u, v);
        return self.len[u]+self.len[v]-2*self.len[z];
    }
}

fn fast_prime_factor_table(ma:usize)->Vec<usize>{
    let mut p = sieve(1001);
    let mut minf = vec![0;ma];
    for j in 0..p.1.len(){
        let P = p.1[j];
        let mut now = P;
        for i in 2..ma{
            if minf[now] ==0{
                minf[now] = P;
            }
            now+=P;
            if now>=ma{
                break;
            }
        }
    }
    return minf;
}
fn area_rectanble(x1:f64, x2:f64, x3:f64, y1:f64, y2:f64, y3:f64)->f64{
    let tmp = x1*y2 + x2*y3 + x3*y1 - y1*x2 - y2*x3 - y3*x1;
    tmp.abs()/2.0
}
#[derive(PartialEq, Clone)]
struct FW(f64);

impl Eq for FW {}

impl PartialOrd for FW {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl Ord for FW {
    fn cmp(&self, other: &FW) -> Ordering {
        other.partial_cmp(self).unwrap()

    }
}
/* parsing
    fn expr(s:&Vec<char>, i:&mut usize) -> Vec<usize>{
        let mut val = term(s, i);
        while(*i<s.len() && (s[*i] == '+' || s[*i] == '-')){
            let mut op = encode(s[*i]);
            *i+=1;
            let mut val2 = term(s, i);
            val = cal(val, val2, op);
        }
        return val;
    }
    fn term(s:&Vec<char>, i:&mut usize) -> Vec<usize>{
        let mut val = factor(s, i);
        while(*i<s.len() && s[*i] == '*'){
            let mut op = encode(s[*i]);
            *i+=1;
            let mut val2 = factor(s, i);
            val = cal(val, val2, op);
        }
        return val;
    }
    fn factor(s:&Vec<char>, i:&mut usize)->Vec<usize>{
        if s[*i] == 'R' || s[*i] == 'S' || s[*i] == 'P' || s[*i] == '?'{
            let mut res = encode(s[*i]);
            *i+=1;
            return res;
        }
        *i+=1;
        let mut ret = expr(s, i);
        *i+=1;
        return ret;
    }
*/
fn matmulf64(A:&Vec<Vec<f64>>, B:&Vec<Vec<f64>>) -> Vec<Vec<f64>>{
    let mut C = vec![vec![0.0;B[0].len()];A.len()];
    for i in 0..A.len(){
        for k in 0..B.len(){
            for j in 0..B[0].len(){
                C[i][j] += A[i][k]*B[k][j];
            }
        }
    }
    return C;
}
//sort_by_key(|a| vec![a[0], -a[1]]);
//v.sort_by(|a, b| a.partial_cmp(b).unwrap());

fn fact_mod(n:usize)->usize {
    let mut  f = 1;
    for i in 2..n+1{
        f = f * (i % MODu) % MODu;
    }
    return f;
}

fn mod_pow(x:usize, n:usize) ->usize{
    if(n == 0){ return 1;}
    let mut res = mod_pow((x * x) % MODu, n / 2 );
    if(n & 1 == 1){ res = (res * x) % MODu;}
    return res;
}

fn comb2(n:usize, r:usize)->usize {
    let mut n = n;
    let mut r = r;
    if(r > n-r) {r = n-r;}
    if(r == 0) {return 1;}
    let mut a = 1;
    for i in 0..r{
        a = a * ((n-i) % MODu) % MODu;
    }
    let mut b = mod_pow(fact_mod(r), MODu-2);
    return (a % MODu) * (b % MODu) % MODu;
}

struct scc{
    G:Vec<Vec<usize>>,
    rG:Vec<Vec<usize>>,
    vs:Vec<usize>,
    used:Vec<bool>,
    cmp:Vec<usize>,
}
impl scc{
    pub fn new(N:usize, G:&Vec<Vec<usize>>, rG:&Vec<Vec<usize>>)->Self{
        scc{G:G.clone(), rG:rG.clone(), vs:vec![], used:vec![false;N], cmp:vec![0;N]}
    }
    pub fn add_edge(&mut self, from:usize, to:usize){
        self.G[from].push(to);
        self.rG[to].push(from);
    }
    pub fn dfs(&mut self, v:usize){
        self.used[v] = true;
        for i in 0..self.G[v].len(){
            let t = self.G[v][i];
            if !self.used[t]{
                self.dfs(t);
            }
        }
        self.vs.push(v);
    }
    pub fn rdfs(&mut self, v:usize, k:usize){
        self.used[v] = true;
        self.cmp[v] = k;
        for i in 0..self.rG[v].len(){
            let t = self.rG[v][i];
            if !self.used[t]{
                self.rdfs(t, k);
            }
        }
    }
    pub fn scc(&mut self)->usize{
        for v in 0..self.G.len(){
            if !self.used[v]{
                self.dfs(v);
            }
        }
        self.used = vec![false;self.used.len()];
        let mut k = 0;
        for i in (0..self.vs.len()).rev(){
            if !self.used[self.vs[i]]{
                let t = self.vs[i];
                self.rdfs(t, k);
                k+=1;
            }
        }
        k
    }
}

#[macro_use]
fn modpow3(x:usize, n:usize,m:usize) -> usize{
        let mut ans = 1;
        let mut n = n;
        let mut x = x;
        x%=m;
        while(n != 0){
            if (n&1 == 1){ans = ans*x%m;}
            x = x*x%m;
            n = n>>1;
        }
        ans%m
}
fn cal1(x:usize, n:usize, m:usize, h:&mut HashMap<usize, usize>)->usize{
    if h.contains_key(&n){
        return h[&n];
    }
    if n == 1{
        return x;
    }
    if n == 0{
        return 0;
    }
    let mut res = 0;
    let mut a = n/2;
    let mut b = n-a;
    res = cal1(x, b, m, h)%m;
    res = ((res*modpow3((10)%m, a*x.to_string().len(), m)%m)%m + cal1(x, a, m, h)%m)%m;
    h.insert(n, res);
    return res;
}
fn cal2(x:usize, n:usize, m:usize, h:&mut HashMap<usize, usize>, l:usize)->usize{
    if h.contains_key(&n){
        return h[&n];
    }
    if n == 1{
        return x;
    }
    if n == 0{
        return 0;
    }
    let mut res = 0;
    let mut a = n/2;
    let mut b = n-a;
    res = cal2(x, b, m, h, l)%m;
    res = ((res*modpow3((10)%m, a*l, m)%m)%m + cal2(x, a, m, h, l)%m)%m;
    h.insert(n, res);
    return res;
}
fn modinv3(a:usize, m:usize)->usize{
    let mut a = a as usize;
    let mut b = m as i64;
    let mut u = 1 as i64;
    let mut v = 0 as i64;
    let mut a = a as i64;
    let mut m = m as i64;
    while(b>0){
        let mut t = a/b;
        a -= t*b;
        mem::swap(&mut a, &mut b);
        u-=t*v;
        mem::swap(&mut u, &mut v);
    }
    u%=m;
    if u<0{u+=m;}
    return u as usize;

}

fn dijkstra(s:usize, g:&Vec<Vec<(usize, i64)>>)->Vec<i64>{
    let mut dist = vec![INF;g.len()];
    dist[s] = 0;
    let mut h = BinaryHeap::new();
    h.push((0, s));
    while(h.len() != 0){
        let mut t = h.pop().unwrap();
        let mut d = t.0 * -1;
        let mut v = t.1;
        if dist[v]<d{
            continue;
        }
        for i in 0..g[v].len(){
            let n = g[v][i].0;
            let dd = g[v][i].1;
            if dist[n]>d+dd{
                dist[n] = d+dd;
                h.push((dist[n]*-1, n));
            }
        }
    }
    return dist;
}
fn dijkstra2(s:usize, g:&Vec<Vec<(i64, usize, usize)>>)->Vec<i64>{
    let mut dist = vec![INF;g.len()];
    dist[s] = 0;
    let mut h = BinaryHeap::new();
    h.push((0, s));
    while(h.len() != 0){
        let mut t = h.pop().unwrap();
        let mut d = t.0 * -1;
        let mut v = t.1;
        if dist[v]<d{
            continue;
        }
        for i in 0..g[v].len(){
            let n = g[v][i].1;
            let dd = g[v][i].0;
            if dist[n]>d+dd{
                dist[n] = d+dd;
                h.push((dist[n]*-1, n));
            }
        }
    }
    return dist;
}
struct BIT2{
    n:usize,
    bit:Vec<i64>,
    e:i64,
    ini:i64,
}
impl BIT2{
    /* 1-index*/
        pub fn new(n_:usize, e:i64, ini:i64)->Self{
            BIT2{n:n_, bit:vec![e;n_+1], e:e, ini:ini}
        }
        pub fn sum(&self, i:usize)->i64{
            let mut s = self.ini;
            let mut i = i as i64;
            while(i>0){
                s = s+self.bit[i as usize];
                i -= i & -i;
            }
            return s;
        }
        pub fn add(&mut self, i:usize, x:i64){
            let mut i = i as i64;
            while(i<=self.n as i64){
                self.bit[i as usize] = self.bit[i as usize] + x;
                i += i & -i;
            }
        }
}
struct StarrySkyTree_min{
    n:usize,
    segMin:Vec<i64>,
    segAdd:Vec<i64>,
}
impl StarrySkyTree_min{
    pub fn new(n_:usize)->Self{
        let mut n = 1;
        while(n<n_){n*=2;}
        StarrySkyTree_min{n: n, segMin:vec![0; 2*n-1], segAdd:vec![0;2*n-1]}
    }
    pub fn add(&mut self, a:usize, b:usize, x:i64, k:usize, l:usize, r:usize){
        if (r <= a || b <= l) {return;}
        if (a <= l && r <= b){
            self.segAdd[k] += x;
            return;
        }
        self.add(a, b, x, k * 2 + 1, l, (l + r) / 2);
        self.add(a, b, x, k * 2 + 2, (l + r) / 2, r);
        self.segMin[k] = cmp::min(self.segMin[k * 2 + 1] + self.segAdd[k * 2 + 1], self.segMin[k * 2 + 2] + self.segAdd[k * 2 + 2]);
    }
    pub fn getMin(&self, a:usize, b:usize, k:usize, l:usize, r:usize)->i64{
        if (r <= a || b <= l){ return (INF);}
        if (a <= l && r <= b){ return(self.segMin[k] + self.segAdd[k])};
        let mut left = self.getMin(a, b, k * 2 + 1, l, (l + r) / 2);
        let mut right = self.getMin(a, b, k * 2 + 2, (l + r) / 2, r);
        return (cmp::min(left, right) + self.segAdd[k]);
    }
}

struct StarrySkyTree_max{
    n:usize,
    segMin:Vec<i64>,
    segAdd:Vec<i64>,
}
impl StarrySkyTree_max{
    pub fn new(n_:usize)->Self{
        let mut n = 1;
        while(n<n_){n*=2;}
        StarrySkyTree_max{n: n, segMin:vec![0; 2*n-1], segAdd:vec![0;2*n-1]}
    }
    pub fn add(&mut self, a:usize, b:usize, x:i64, k:usize, l:usize, r:usize){
        if (r <= a || b <= l) {return;}
        if (a <= l && r <= b){
            self.segAdd[k] += x;
            return;
        }
        self.add(a, b, x, k * 2 + 1, l, (l + r) / 2);
        self.add(a, b, x, k * 2 + 2, (l + r) / 2, r);
        self.segMin[k] = cmp::max(self.segMin[k * 2 + 1] + self.segAdd[k * 2 + 1], self.segMin[k * 2 + 2] + self.segAdd[k * 2 + 2]);
    }
    pub fn getMax(&self, a:usize, b:usize, k:usize, l:usize, r:usize)->i64{
        if (r <= a || b <= l){ return (-INF);}
        if (a <= l && r <= b){ return(self.segMin[k] + self.segAdd[k])};
        let mut left = self.getMax(a, b, k * 2 + 1, l, (l + r) / 2);
        let mut right = self.getMax(a, b, k * 2 + 2, (l + r) / 2, r);
        return (cmp::max(left, right) + self.segAdd[k]);
    }
}
fn compress(N:usize, x1:&Vec<i64>,x2:&Vec<i64>, W:i64)->Vec<i64>{
    // [0,W]
    let mut xs = HashSet::new();
    for i in 0..N{
        for d in -1..2{
            let mut tx1 = x1[i]+d;
            let mut tx2 = x2[i]+d;
            if (0<=tx1 && tx1<=W){
                xs.insert(tx1);
            }
            if (0<=tx2 && tx2<=W){
                xs.insert(tx2);
            }
        }
    }
    let mut xs:Vec<i64> = xs.into_iter().collect();
    xs.sort();

    return xs;
}
//２次元和 [ (x, y), (x, y) )
//sum[i+1][j+1] = ((sum[i+1][j]+sum[i][j+1]+MODu-sum[i][j])%MODu+dp[i+1][j+1])%MODu;
/*for (int i = 0; i < H; i++) {

             for (int j = 0; j < W; j++) {
                 imos[i][j + 1] += imos[i][j];
             }
         }

         for (int j = 0; j < W; j++) {
             for (int i = 0; i < H; i++) {
                 imos[i + 1][j] += imos[i][j];
             }
         }

        sums[yy1][xx1]+=1;
        sums[yy2][xx2]+=1;
        sums[yy1][xx2]-=1;
        sums[yy2][xx1]-=1;
    }
    for i in 0..ys.len() {
        for j in 0..xs.len(){
            sums[i][j + 1] += sums[i][j];
            }
        }

    for j in 0..xs.len(){
        for i in 0..ys.len(){
            sums[i + 1][j] += sums[i][j];
        }
    }
*/
//3次元和 [ (x, y, z), (x, y, z) )
/*
//let mut v = vec![X1, Y1, Z1, X2, Y2, Z2];
        let mut si = vec![1i64, -1i64];
        for i in 0..2{
            for j in 0..2{
                for k in 0..2{
                    let mut X = v[0+i*3];
                    let mut Y = v[1+j*3];
                    let mut Z = v[2+k*3];
                    sum[X][Y][Z]+=si[i]*si[j]*si[k];
                }
            }
        }
    }
    for i in 0..xs.len()-1{
        for j in 0..ys.len(){
            for k in 0..zs.len(){
                sum[i+1][j][k] += sum[i][j][k];
            }
        }
    }

    for i in 0..xs.len(){
        for j in 0..ys.len()-1{
            for k in 0..zs.len(){
                sum[i][j+1][k] += sum[i][j][k];
            }
        }
    }

    for i in 0..xs.len(){
        for j in 0..ys.len(){
            for k in 0..zs.len()-1{
                sum[i][j][k+1] += sum[i][j][k];
            }
        }
    }
*/

fn solve(){
    let sssss = std::io::stdin();
    let mut sc = Scanner { stdin: sssss.lock() };
    let mut res = -INF;
    let mut x = vec![0i64;2];
    let mut y = vec![0i64;2];
    for i in 0..2{
        x[i] = sc.read();
    }
    for i in 0..2{
        y[i] = sc.read();
    }
    for i in 0..2{
        for j in 0..2{
            if i == 0 && j == 0{
                res = x[i]*y[j];
            }
            else{
                res = cmp::max(res, x[i]*y[j]);
            }
        }
    }
    if x[0]<=0 && 0<=x[1] && y[0]<=0 && 0<=y[1]{
        res = cmp::max(res, 0);
    }
    println!("{}", res);

}

fn main(){
    solve();
}
const PI:f64 = std::f64::consts::PI;
pub static MOD:i64 = 1000000007;
pub static MODu:usize = 1000000007;
pub static MODi32:i32 = 1000000007;
pub static eps:f64 = 1e-6;
const INF: i64 = 1 << 60;
const INFu:usize = 1<<62;


use proconio::input;
use proconio::marker::Chars;
#[allow(unused_imports)]
use std::cmp::{max, min};
#[allow(unused)]
const ALPHA_SMALL: [char; 26] = [
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
    't', 'u', 'v', 'w', 'x', 'y', 'z',
];
#[allow(unused)]
const ALPHA: [char; 26] = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
    'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
];
macro_rules! maxs {
    ($x:expr, $($y:expr), *) => {{
        let mut ret = $x;
        $(
            ret = max(ret, $y);
        )*
        ret
    }};
}
fn main() {
    input!(a: i64, b: i64, c: i64, d: i64);
    let ans = maxs!(a * c, b * d, a * d, b * c);
    println!("{}", ans);
}


use proconio::input;
use std::cmp;

fn main() {
    input! {
        a: i64,
        b: i64,
        c: i64,
        d: i64,
    }

    if (a > 0 && d < 0) || (b < 0 && c > 0) {
        // 負の数しか作れない
        let x = cmp::min(a.abs(), b.abs());
        let y = cmp::min(c.abs(), d.abs());
        println!("{}", - x * y);
    } else {
        let x = cmp::max(a.abs(), b.abs());
        let y = cmp::max(c.abs(), d.abs());
        println!("{}", x * y);
    }
}


fn read<T: std::str::FromStr>() -> T {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>()
.split_whitespace()
        .map(|e| e.parse().ok().unwrap())
        .collect()
}

fn read_vec2<T: std::str::FromStr>(n: u32) -> Vec<Vec<T>> {
    (0..n).map(|_| read_vec()).collect()
}

fn main() {
    // solver code...
    let tmp_vec = read_vec::<i64>();

    let mut ans = -1 * (10^20);
    for x in 0..2 {
        for y in 2..4 {
                let tmp_ans = tmp_vec[x] * tmp_vec[y];
                ans = std::cmp::max(ans, tmp_ans);
        }
    }
    println!("{}", ans);
}


fn read<T: std::str::FromStr>() -> T {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>()
.split_whitespace()
        .map(|e| e.parse().ok().unwrap())
        .collect()
}

fn read_vec2<T: std::str::FromStr>(n: u32) -> Vec<Vec<T>> {
    (0..n).map(|_| read_vec()).collect()
}

fn main() {
    // solver code...
    let tmp_vec = read_vec::<i64>();

    let mut ans = -1 * (10^18);
    for x in 0..2 {
        for y in 2..4 {
                let tmp_ans = tmp_vec[x] * tmp_vec[y];
                ans = std::cmp::max(ans, tmp_ans);
        }
    }
    println!("{}", ans);
}


func readInts() -> [Int] {
    return readLine()!.split(separator: " ").map { Int($0)! }
}

func main1() {
    let param = readInts()

    var ans = param[1] * param[3]

    for i in 0...1 {
        for j in 2...3 {
            if (param[i] * param[j] > ans){
                ans = param[i] * param[j]
            }
        }
    }

    print(ans)
}

main1()


let x = readLine()!.split(separator: " ").map {Int($0)!}
var resultArray: [Int] = []
for i in 0..<2 {
    for j in 2..<4 {
        resultArray.append(x[i]*x[j])
    }
}
print(resultArray.max()!)


let abcd = readLine()!.split(separator: " ").compactMap { Int($0) }
let a = abcd[0]
let b = abcd[1]
let c = abcd[2]
let d = abcd[3]

print(max(a * c, a * d, b * c, b * d))


func readInts() -> [Int] {
    return readLine()!.split(separator: " ").map { Int($0)! }
}

func main1() {
    let param = readInts()

    var ans = param[1] * param[3]

    for x in param[0]...param[1] {
        for y in param[2]...param[3] {
            if (x * y) > ans {
                ans = x * y
            }
        }
    }

    print(ans)
}

main1()


import Foundation

let line = readLine()!.components(separatedBy: " ")
let a = Double(line[0])!
let b = Double(line[1])!
let c = Double(line[2])!
let d = Double(line[3])!

var m: Double = a * c
m = max(m, a * d)
m = max(m, b * c)
m = max(m, b * d)
print(Int(m))


import * as fs from 'fs';

function bigMax(...a: bigint[]): bigint {
  return a.reduce((prev, current) => prev > current ? prev : current);
}
function main(input) {
  input = input.split('\n');
  const [a, b, c, d]: bigint[] = input[0].split(' ').map(i => BigInt(parseInt(i)));
  console.log('%s', bigMax(a * c, a * d, b * c, b * d).toString());
}

main(fs.readFileSync('/dev/stdin', 'utf8'));


"use strict"
let fs = require('fs');
let input = fs.readFileSync("/dev/stdin", "utf8").split(/\s/);

const a = BigInt(input[0]);
const b = BigInt(input[1]);
const c = BigInt(input[2]);
const d = BigInt(input[3]);

const ac = a * c;
const ad = a * d;
const bc = b * c;
const bd = b * d;

let ans = ac;
ans = ans < ad ? ad : ans;
ans = ans < bc ? bc : ans;
ans = ans < bd ? bd : ans;

console.log(String(ans).replace('n', ''));


import { readFileSync } from "fs";

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const range = (n: number | bigint) => [...Array(Number(n))].map((_, i) => i);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const tuple = <T extends unknown[]>(...ts: T) => ts;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [cin, nCin, bCin] = (() => {
  const inputs = readFileSync("/dev/stdin", "utf-8").split(/[\n|\s]+/);
  let count = 0;
  const cin = () => inputs[count++];
  return tuple(
    cin,
    () => Number(cin()),
    () => BigInt(cin())
  );
})();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const isNumber = (x: unknown): x is number => typeof x === "number";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const isBigint = (x: unknown): x is bigint => typeof x === "bigint";
type NumberOrBigintOrElse<T> = number | bigint extends T
  ? undefined
  : T extends number
  ? number
  : T extends bigint
  ? bigint
  : undefined;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const max = <T extends number | bigint>(...ts: T[]) =>
  (ts.length === 0
    ? undefined
    : isNumber(ts[0])
    ? Math.max(...(ts as number[]))
    : (ts as bigint[]).reduce((acc, t) =>
        acc >= t ? acc : t
      )) as NumberOrBigintOrElse<T>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const min = <T extends number | bigint>(...ts: T[]) =>
  (ts.length === 0
    ? undefined
    : isNumber(ts[0])
    ? Math.min(...(ts as number[]))
    : (ts as bigint[]).reduce((acc, t) =>
        acc <= t ? acc : t
      )) as NumberOrBigintOrElse<T>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const abs = <T extends number | bigint>(t: T) =>
  (isNumber(t)
    ? Math.abs(t)
    : isBigint(t)
    ? t >= 0n
      ? t
      : -t
    : undefined) as NumberOrBigintOrElse<T>;

/**
 * Program
 */
const getAns = (a: bigint, b: bigint, c: bigint, d: bigint): string =>
  max(a * c, a * d, b * c, b * d).toString();

{
  const [a, b, c, d] = [bCin(), bCin(), bCin(), bCin()];
  const ans = getAns(a, b, c, d);
  console.log(ans);
}


import * as fs from "fs";

const input = fs.readFileSync("/dev/stdin", "utf8");
const a = +input.split(" ")[0];
const b = +input.split(" ")[1];
const c = +input.split(" ")[2];
const d = +input.split(" ")[3];

const ac = a * c;
const ad = a * d;
const bc = b * c;
const bd = b * d;

let max = ac;

if (ac >= ad && ac >= bc && ac >= bd) {
  max = ac;
} else if (ad >= ac && ad >= bc && ad >= bd) {
  max = ad;
} else if (bc >= ac && bc >= ad && bc >= bd) {
  max = bc;
} else if (bd >= ac && bd >= ad && bd >= bc) {
  max = bd;
}

console.log(max);


import * as fs from "fs";

const input = fs.readFileSync("/dev/stdin", "utf8");
const a = +input.split(" ")[0];
const b = +input.split(" ")[1];
const c = +input.split(" ")[2];
const d = +input.split(" ")[3];

const ac = a * c;
const ad = a * d;
const bc = b * c;
const bd = b * d;

let max = ac;

if (ac >= ad && ac >= bc && ac >= bd) {
  max = ac;
} else if (ad >= ac && ad >= bc && ad >= bd) {
  max = ad;
} else if (bc >= ac && bc >= ad && bc >= bd) {
  max = bc;
} else {
  max = bd;
}

console.log(max);


import sys
import numpy as np

n = int(input())
a, b = np.fromstring(sys.stdin.read(), dtype=np.uint32, sep=' ').reshape((n, 2)).T
i = b.argsort()
print('Yes' if (np.add.accumulate(a[i]) <= b[i]).all() else 'No')


import sys
import numpy as np

N = int(sys.stdin.readline())
ind = np.fromstring(sys.stdin.read(), dtype='i8', sep=' ').reshape((N, 2))
a = ind[:, 0]
b = ind[:, 1]
arg = np.argsort(b)
a = a[arg]
b = b[arg]
ac = np.add.accumulate(a)
if np.all(b - ac >= 0):
    print('Yes')
else:
    print('No')


import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

# 締切の近いものから詰め込む

import numpy as np

N = int(readline())
AB = np.array(read().split(),np.int64)

A = AB[::2]; B = AB[1::2]

ind = B.argsort(); A = A[ind]; B = B[ind]

answer = 'Yes' if np.all(A.cumsum() <= B) else 'No'
print(answer)


def main():
    n = int(input())
    ab_lst = [list(map(int, input().split())) for _ in range(n)]

    ba_lst = [0] * n
    for i in range(n):
        a = ab_lst[i][0]
        b = ab_lst[i][1]
        ba = [b, a]
        ba_lst[i] = ba
    ba_lst.sort()

    lst = []
    b = ba_lst[0][0]
    a = ba_lst[0][1]
    for i in range(n):
        b_tmp = ba_lst[i][0]
        a_tmp = ba_lst[i][1]

        if b == b_tmp:
            if i != 0:
                a += a_tmp
            if i == n - 1:
                lst.append([b, a])

        else:
            lst.append([b, a])
            b = b_tmp
            a = a_tmp

    if ba_lst[-1][0] != ba_lst[-2][0]:
        lst.append([ba_lst[-1][0], ba_lst[-1][1]])

    print(lst)

    accumulate = 0
    flag = True
    for i in range(len(lst)):
        accumulate += lst[i][1]
        if accumulate > lst[i][0]:
            flag = False
            break

    if flag:
        print('Yes')
    else:
        print('No')

if __name__ == '__main__':
    main()


n = int(input())
work = [list(map(int,input().split())) for _ in range(n)]
work = sorted(work,key = lambda x:x[1])
a = [0] * n
a[0] = work[0][0]
for i in range(1,N):
    a[i] = a[i-1] + work[i][0]
ans = 'Yes'
for j in range(N):
    if a[j] > work[j][1]:
        ans = 'No'
        break
print(ans)


import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.*;

public class Main {
    int N;
    int[] A,B;
    private class Task implements Comparable<Task> {
        int take, end;
        public Task(int take, int end) {
            this.take = take;
            this.end = end;
        }

        public int compareTo(Task task) {
            if (this.end == task.end) {
                return this.take - task.take;
            }
            return this.end - task.end;
        }
    }
    private void solve() {
        N = nextInt();
        A = new int[N];
        B = new int[N];
        for(int i = 0;i < N;i++) {
            A[i] = nextInt();
            B[i] = nextInt();
        }

        PriorityQueue<Task> pq = new PriorityQueue<>();
        for(int i = 0;i < N;i++) {
            pq.add(new Task(A[i], B[i]));
        }

        int now = 0;
        while(!pq.isEmpty()) {
            Task task = pq.poll();

            if (now + task.take > task.end) {
                out.println("No");
                return;
            }
            now = now + task.take;
        }

        out.println("Yes");
    }

    public static void main(String[] args) {
        out.flush();
        new Main().solve();
        out.close();
    }

    /* Input */
    private static final InputStream in = System.in;
    private static final PrintWriter out = new PrintWriter(System.out);
    private final byte[] buffer = new byte[4096];
    private int p = 0;
    private int buflen = 0;

    private boolean hasNextByte() {
        if (p < buflen)
            return true;
        p = 0;
        try {
            buflen = in.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (buflen <= 0)
            return false;
        return true;
    }

    public boolean hasNext() {
        while (hasNextByte() && !isPrint(buffer[p])) {
            p++;
        }
        return hasNextByte();
    }

    private boolean isPrint(int ch) {
        if (ch >= '!' && ch <= '~')
            return true;
        return false;
    }

    private int nextByte() {
        if (!hasNextByte())
            return -1;
        return buffer[p++];
    }

    public String next() {
        if (!hasNext())
            throw new NoSuchElementException();
        StringBuilder sb = new StringBuilder();
        int b = -1;
        while (isPrint((b = nextByte()))) {
            sb.appendCodePoint(b);
        }
        return sb.toString();
    }

    public int nextInt() {
        return Integer.parseInt(next());
    }

    public long nextLong() {
        return Long.parseLong(next());
    }

    public double nextDouble() {
        return Double.parseDouble(next());
    }
}


import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) {
        FastScanner sc = new FastScanner();
        int n = sc.nextInt();
        long max = 0;
        List<Pair> p = new ArrayList<Pair>();
        for (int i = 0; i < n; i++) {
            long a = sc.nextLong();
            long b = sc.nextLong();
            max = Math.max(max, b);
            p.add(new Pair(a, b));
        }
        Collections.sort(p, new PairComparator());
        if (solve(max, p)) {
            System.out.println("Yes");
            return;
        }
        System.out.println("No");
    }

    public static boolean solve(long x, List<Pair> p) {
        long res = 0;
        for (int i = 0; i < p.size(); i++) {
            res += p.get(i).a;
            if (res > p.get(i).b) {
                return false;
            }
        }
        return true;
    }
}

class Pair {
    long a;
    long b;

    public Pair(long a, long b) {
        this.a = a;
        this.b = b;
    }

    public long compareTo(Pair p) {
        return this.b - p.b;
    }

    public String toString() {
        return String.format("a: %d b: %d %n", this.a, this.b);
    }
}

class PairComparator implements Comparator<Pair> {
    public int compare(Pair p1, Pair p2) {
        return (int) p1.b - (int) p2.b;
    }
}

class FastScanner {
    private final InputStream in = System.in;
    private final byte[] buffer = new byte[1024];
    private int ptr = 0;
    private int buflen = 0;

    private boolean hasNextByte() {
        if (ptr < buflen) {
            return true;
        } else {
            ptr = 0;
            try {
                buflen = in.read(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (buflen <= 0) {
                return false;
            }
        }
        return true;
    }

    private int readByte() {
        if (hasNextByte())
            return buffer[ptr++];
        else
            return -1;
    }

    private static boolean isPrintableChar(int c) {
        return 33 <= c && c <= 126;
    }

    public boolean hasNext() {
        while (hasNextByte() && !isPrintableChar(buffer[ptr]))
            ptr++;
        return hasNextByte();
    }

    public String next() {
        if (!hasNext())
            throw new NoSuchElementException();
        StringBuilder sb = new StringBuilder();
        int b = readByte();
        while (isPrintableChar(b)) {
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }

    public long nextLong() {
        if (!hasNext())
            throw new NoSuchElementException();
        long n = 0;
        boolean minus = false;
        int b = readByte();
        if (b == '-') {
            minus = true;
            b = readByte();
        }
        if (b < '0' || '9' < b) {
            throw new NumberFormatException();
        }
        while (true) {
            if ('0' <= b && b <= '9') {
                n *= 10;
                n += b - '0';
            } else if (b == -1 || !isPrintableChar(b)) {
                return minus ? -n : n;
            } else {
                throw new NumberFormatException();
            }
            b = readByte();
        }
    }

    public int nextInt() {
        long nl = nextLong();
        if (nl < Integer.MIN_VALUE || nl > Integer.MAX_VALUE)
            throw new NumberFormatException();
        return (int) nl;
    }

    public double nextDouble() {
        return Double.parseDouble(next());
    }
}


import java.util.*;
import java.io.*;

class Main{
    public static void main(String[] args){
        FastScanner fs = new FastScanner();
        int n = fs.nextInt();
        int[][] ab = new int[n][2];
        for(int i=0;i<n;i++){
            ab[i][0] = fs.nextInt();
            ab[i][1] = fs.nextInt();
        }
        Arrays.sort(ab,new Comparator<int[]>(){
			@Override
			public int compare(int[] o1, int[] o2) {
				return o1[1]-o2[1];
			}
        });
        int now = 0;
        for(int i=0;i<n;i++){
            now+=ab[i][0];
            if(now > ab[i][1]){
                System.out.println("No");
                return;
            }
        }
        System.out.println("Yes");
    }
    static class FastScanner{
        private final InputStream in = System.in;
        private final byte[] buffer = new byte[1024];
        private int ptr = 0;
        private int buflen = 0;

        private boolean hasNextByte(){
            if(ptr < buflen){
                return true;
            }else{
                ptr = 0;
                try{
                    buflen = in.read(buffer);
                }catch(IOException e){
                    e.printStackTrace();
                }
                if(buflen <= 0){
                    return false;
                }
            }
            return true;
        }

        private int readByte(){
            if(hasNextByte())return buffer[ptr++];
            else return -1;
        }

        private boolean isPrintableChar(int c){
            return 33<=c && c<=126;
        }

        public boolean hasNext(){
            while(hasNextByte() && !isPrintableChar(buffer[ptr]))ptr++;
            return hasNextByte();
        }

        public String next(){
            if(!hasNext()) throw new NoSuchElementException();
            StringBuilder sb = new StringBuilder();
            int b = readByte();
            while(isPrintableChar(b)){
                sb.appendCodePoint(b);
                b = readByte();
            }
            return sb.toString();
        }

        public long nextLong(){
            if(!hasNext()) throw new NoSuchElementException();
            long n = 0;
            boolean minus = false;
            int b = readByte();
            if(b == '-'){
                minus = true;
                b = readByte();
            }
            if(b < '0' || '9' < b){
                throw new NumberFormatException();
            }
            while(true){
                if('0' <= b && b<='9'){
                    n*=10;
                    n+=b-'0';
                }else if(b==-1 || !isPrintableChar(b)){
                    return minus ? -n : n;
                }else{
                    throw new NumberFormatException();
                }
                b = readByte();
            }
        }
        public int nextInt(){
            long nl = nextLong();
            if(nl < Integer.MIN_VALUE || nl > Integer.MAX_VALUE)throw new NumberFormatException();
            return (int)nl;
        }
        public double nextDouble(){return Double.parseDouble(next());}
    }
}


import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.Set;

import atCoder.abc177.f.Main.Pair;

public class Main {

	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();

		PriorityQueue<Pair> q = new PriorityQueue<Pair>();
		Pair[] a = new Pair[n];

		for( int i=0 ; i<n ; i++ ) {
			a[i] = new Pair(sc.nextInt(), sc.nextInt() );
			q.add(a[i]);
		}

		Arrays.sort(a);

		boolean canFinish = true;
		int time =0;
		for( int i = 0 ; i< n ; i++ ) {
			time+= a[i].weight;
			if( a[i].limit < time ) {
				canFinish = false;
				break;
			}
		}

		if( canFinish ) {
			System.out.println("Yes");
		}else {
			System.out.println("No");
		}

	}

	public static class Pair implements Comparable<Pair>{
		int weight = 0;
		int limit = 0;

		public Pair(int weight, int limit) {
			super();
			this.weight = weight;
			this.limit = limit;
		}

		@Override
		public int compareTo(Pair o) {
			return limit - o.limit;
		}

	}
}