#include <iostream>
#include <cstdio>
#include <vector>
#include <complex>
#include <cmath>
#include <algorithm>
using namespace std;

const double EPS = 1e-8;
const double INF = 1e12;
const double PI = acos(-1.0);

// 2つのスカラーが等しいかどうか
bool equal(double a, double b) {
	return fabs(a - b) < EPS;
}
// 点クラス
struct P {
	double x, y;
	P(double x_, double y_) { x = x_; y = y_; }
	P(){}
	// 加算, 減算, スカラー倍
	P operator+(const P& a) const {
		return P(x + a.x, y + a.y);
	}
	P operator-(const P& a) const {
		return P(x - a.x, y - a.y);
	}
	P operator*(const P& a) const {
		return P(x * a.x - y * a.y, x * a.y + y * a.y);
	}
	P operator*(double c) const {
		return P(x * c, y * c);
	}
	P operator/(const P& a) const {
		double norm = a.x * a.x + a.y * a.y;
		double x_ = (x * a.x + y * a.y) / norm;
		double y_ = (y * a.x - x * a.y) / norm;
		return P(x_, y_);
	}
	P operator/(double c) const {
		return P(x / c, y / c);
	}
	P& operator+=(const P& a) {
		x += a.x; y += a.y;
	}
	P& operator-=(const P& a) {
		x -= a.x; y -= a.y;
	}
	P& operator*=(const P& a) {
		*this = P(x * a.x - y * a.y, x * a.y + y * a.y);
	}
	P& operator*=(double c) {
		*this = P(x * c, y * c);
	}
	P& operator/=(const P& a) {
		double norm = a.x * a.x + a.y * a.y;
		double x_ = (x * a.x + y * a.y) / norm;
		double y_ = (y * a.x - x * a.y) / norm;
		*this = P(x_, y_);
	}
	P& operator/=(double c) {
		*this = P(x / c, y / c);
	}
	// デバッグ出力
	void print() { printf("(%f,%f)", x, y); }
};
P operator*(double c, P a){
	return P(a.x * c, a.y * c);
}
// 比較演算子
bool operator==(const P& a, const P& b) {
	return equal(a.x, b.x) && equal(a.y, b.y);
}
bool operator!=(const P& a, const P& b) {
	return !(a == b);
}
bool operator<(const P& a, const P& b) {
	return (a.x != b.x)? a.x < b.x : a.y < b.y;
}

const P INF_P = P(INF, INF);

// 原点からの距離(絶対値)
double abs(P a) {
	return sqrt(a.x * a.x + a.y * a.y);
}
// 2点間の距離
double dist(P a, P b) {
	return abs(a - b);
}
// ノルム
double norm(const P& z){
	return z.x * z.x + z.y * z.y;
}
// 偏角
double arg(const P& z) {
	return atan2(z.y, z.x);
}
// ベクトル a の単位ベクトルを求める
P unit(P a) {
	return a / abs(a);
}
// ベクトル a の法線ベクトルを求める
vector<P> normal(P a) {
	vector<P> vp;
	vp.push_back( a * P(0, +1) );
	vp.push_back( a * P(0, -1) );
	return vp;
}
// 内積 (dot product) : a・b = |a||b|cosΘ
double dot(P a, P b) {
	return a.x * b.x + a.y * b.y;
}
// 外積 (cross product) : a×b = |a||b|sinΘ
double cross(P a, P b) {
	return a.x * b.y - a.y * b.x;
}

// CCW : 反時計回り (Counter Clock Wise)
// CW : 時計回り (Clock Wise)
enum {CCW=1, CW=-1, ON=0};
// * 3点がどちら回りであるか返す, 3点が1直線に乗っているときは ON を返す
int ccw(const P &a, P b, P c) {
	b -= a, c -= a;
	if( cross(b,c) >  EPS ) return CCW; // CCW : 反時計回り
	if( cross(b,c) < -EPS ) return CW;  // CW : 時計回り
	if( dot(b, c)  < -EPS ) return +2;  // c--a--b on line
	if( dot(b, b)  + EPS < dot(c, c) ) return -2; // a--b--c on line 
	return ON;
}

// ラジアンから度数へ変換して返す
double to_deg(double rad) {
	return rad * 180.0 / PI;
}
// 度数からラジアンに変換して返す
double to_rad(double deg) {
	return deg * PI / 180.0;
}

// 原点を軸に点 p を角度 a (ラジアン)だけ回転させた点を返す
P rot(P p, double a){
	return P(p.x * cos(a) - p.y * sin(a), p.x * sin(a) + p.y * cos(a));
}
// 点 a を軸に点 b を角度 angle (ラジアン)だけ回転させた点を返す
P rot(P a, P b, double angle){
	return rot(b - a, angle) + a;
}

// 点 c を点 a, b を通る直線の線対称に移動させる
P symmetry(P a, P b, P c) {
	P res;
	if( b.x == a.x ) {
		res.x = -c.x; res.y = c.y;
	}else{
		double m = (b.y - a.y) / (b.x - a.x);
		double z = b.y - m * b.x;
		res.x = (2 * m * c.y - c.x * (m * m - 1) - 2 * m * z) / (m * m + 1);
		res.y = (2 * m * c.x + c.y * (m * m - 1) + 2 * z) / (m * m + 1);
	}
	return res;
}

// 直線クラス
struct Line : public vector<P> {
	Line(){}
	Line(const P& a, const P& b) {
		push_back(a); push_back(b);
	}
	Line(const vector<P>& vp){
		(*this) = vp;
	}
	// デバッグ出力 (線分を出力)
	void print_s() const {
		printf("line(%f,%f,%f,%f); \n", (*this)[0].x, (*this)[0].y, (*this)[1].x, (*this)[1].y);
	}
	// デバッグ出力 (直線を出力, 途中で直線が途切れているときは適当にlenの値を大きくする)
	void print_l() const {
		const double len = 100;
		P p1 = (*this)[0], p2 = (*this)[1];
		double dx = p1.x - p2.x, dy = p1.y - p2.y;
		p1.print();
		p2.print();
		p1.x += len * dx;
		p1.y += len * dy;
		p2.x -= len * dx;
		p2.y -= len * dy;
		Line l( p1 , p2 );
		l.print_s();
	}
};

// 2つの直線の直交判定
bool is_orthogonal(const Line& a, const Line& b) {
	return equal( dot( a[0] - a[1] , b[0] - b[1] ) , 0.0 );
}
// 2つの直線の平行判定
bool is_parallel(const Line& a, const Line& b) {
	return equal( cross( a[0] - a[1] , b[0] - b[1] ), 0.0 );
}

// 直線 a と直線 b の交差判定
bool intersectLL(const Line& a, const Line& b) {
	return abs(cross(a[1] - a[0], b[1] - b[0])) > EPS || abs(cross(a[1] - a[0], b[0] - a[0])) < EPS;
}
// 直線 l と 線分 s の交差判定
bool intersectLS(const Line& l, const Line& s) {
	return cross(l[1] - l[0], s[0] - l[0]) * cross(l[1] - l[0], s[1] - l[0]) < EPS;
}
// 直線 l 上に点 p があるかどうか
bool intersectLP(const Line& l, const P& p) {
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
// 線分 s と 線分 t の交差判定
bool intersectSS(const Line& s, const Line& t) {
	return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 &&
		   ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}
// 線分 s 上に点 p があるかどうか
bool intersectSP(const Line& s, const P& p) {
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;
}

P projection(const Line& l, const P& p) {
	double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
	return l[0] + (l[0] - l[1]) * t;
}
P reflection(const Line& l, const P& p) {
	return p + 2 * (projection(l, p) - p);
}
// 直線と点の距離
double distanceLP(const Line& l, const P& p) {
	return abs(p - projection(l, p));
}
// 直線と直線の距離
double distanceLL(const Line& l, const Line& m) {
	return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}
// 直線と線分の距離
double distanceLS(const Line& l, const Line& s) {
	if (intersectLS(l, s)) return 0;
	return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
// 線分と点の距離
double distanceSP(const Line& s, const P& p) {
	const P r = projection(s, p);
	if (intersectSP(s, r)) return abs(r - p);
	return min(abs(s[0] - p), abs(s[1] - p));
}
// 線分と線分の距離
double distanceSS(const Line& s, const Line& t) {
	if (intersectSS(s, t)) return 0;
	double a = min(distanceSP(s, t[0]), distanceSP(s, t[1]));
	double b = min(distanceSP(t, s[0]), distanceSP(t, s[1]));
	return min(a, b);
}
// 交点計算
P crosspoint(const Line& l, const Line& m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS && abs(B) < EPS) return m[0]; // same line
	// if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
	return m[0] + B / A * (m[1] - m[0]);
}

// 円クラス
struct Circle{
	P p;
	double r;
	// コンストラクタで初期化
	Circle(P p_, double r_) { p = p_; r = r_; }
	// 点 a が円の内部にあるかどうか
	bool is_inside(P a) const {
		return dist(p, a) <= r;
	}
	// 点 a が円周上にあるかどうか
	bool on_boundary(P a) const {
		return equal( dist(p, a) , r );
	}// 等しいかどうか
	bool operator==(const Circle& c) const {
		return p == c.p && r == c.r;
	}// デバッグ出力
	void print() { printf("circle(%f,%f,%f); \n", p.x, p.y, r ); }
};

struct Triangle{
private:
	// 余弦定理から 3 つの角の角度を求める (内部の関数で使用)
	double law_of_cos(double a, double b, double c) {
		return acos( (b*b + c*c - a*a) / (2.0 * b * c) );
	}
	// 点 a , b を端点とする線分に点 c が含まれているかどうか
	bool contain(P a, P b, P c) {
		return abs(a - c) + abs(b - c) - abs(b - a) < EPS;
	}
public:
	// 3 つの頂点
	P a, b, c;
	// 3 つの辺の長さ
	double edgeA, edgeB, edgeC;
	// 3 つの角の角度 (ラジアン)
	double angleA,angleB,angleC;
	// コンストラクタで初期化
	Triangle(P p1, P p2, P p3) {
		a = p1; b = p2; c = p3;
		edgeB = abs(c-a);
		edgeA = abs(b-c);
		edgeC = abs(a-b);
		angleA = law_of_cos( edgeA, edgeB, edgeC );
		angleB = law_of_cos( edgeB, edgeC, edgeA );
		angleC = law_of_cos( edgeC, edgeA, edgeB );
	}
	// 三角形の面積を返す (ヘロンの公式)
	double get_area() {
		double s = 0.5 * (edgeA + edgeB + edgeC);
		return sqrt( s * (s - edgeA) * (s - edgeB) * (s - edgeC) );
	}
	// 点 p が三角形の辺上にあるかどうか
	bool on_boundary(P p) {
		return contain(a, b, p) || contain(b, c, p) || contain(c, a, p);
	}
	// 三角形の重心を返す
	P gravity() {
		return P( (a.x + b.x + c.x) / 3.0 , (a.y + b.y + c.y) / 3.0 );
	}
	// 三角形の外接円を返す (AOJ 0010 で検証済み)
	Circle circumscribed_circle() {
		double r = ( edgeA / sin(angleA) / 2.0 );
		double A = sin( 2.0 * angleA );
		double B = sin( 2.0 * angleB );
		double C = sin( 2.0 * angleC );
		double cx = ( (a.x * A + b.x * B + c.x * C) / (A + B + C) );
		double cy = ( (a.y * A + b.y * B + c.y * C) / (A + B + C) );
		return Circle( P(cx,cy) , r );
	}
	// 三角形の内接円を返す
	Circle inscribed_circle() {
		// 三角形の外周の長さ
		double ABC = edgeA + edgeB + edgeC;
		
		double cx = (a.x * edgeA + b.x * edgeB + c.x * edgeC) / ABC;
		double cy = (a.y * edgeA + b.y * edgeB + c.y * edgeC) / ABC;
		double r  = (2.0 * get_area()) / ABC ;
		return Circle( P(cx,cy) , r );
	}
	// 点 p が三角形の内部にあるかどうか ( AOJ 0012 で検証済み )
	bool is_inside(P p) {
		// 辺上にあるとき
		if( this->on_boundary(p) ) return true;
		
		Triangle t1( a , b , p );
		Triangle t2( b , c , p );
		Triangle t3( c , a , p );
		// 角APB + 角BPB + 角CPA が 360度なら 点 p は三角形の内部にある
		return equal( t1.angleC + t2.angleC + t3.angleC , 2.0*PI );
	}
	// デバッグ出力
	void print() {
		Line AB(a,b), BC(b,c), CA(c,a);
		AB.print_s();
		BC.print_s();
		CA.print_s();
	}
};

typedef vector<P> Polygon;

// 点 p が単純多角形の内部・外部・境界のどこにあるか判定する.
enum { OUT, IN };
int contains(const Polygon& g, const P& p) {
	int n = g.size();
	bool in = false;
	for(int i = 0 ; i < n ; i++ ){
		P a = g[i] - p;
		P b = g[(i+1)%n] - p;
		if( a.y > b.y ){
			swap(a, b);
		}
		if( a.y <= 0 && 0 < b.y ){
			if( cross(a, b) < 0 ){
				in = !in;
			}
		}
		if( cross(a, b) == 0 && dot(a, b) <= 0 ){
			return ON;
		}
  }
  return in? IN : OUT;
}
// (凸とは限らない) 多角形の面積を返す.
double get_area(const Polygon& g) {
	int n = g.size();
	double s = 0;
	for(int i = 0 ; i < n ; i++ )
		s += cross(g[i], g[(i+1) % n]);
	return fabs(s);
}

// 凸多角形かどうか
bool is_convex(const Polygon& g) {
	int n = g.size();
	for(int i = 0 ; i < n ; i++ ){
		if( ccw(g[(i+n-1) % n], g[i % n], g[(i+1) % n]) > 0 )
			return false;
	}
	return true;
}

// 凸包を求める. (ps.size() >= 3 と仮定する)
vector<P> convex_hull(vector<P> ps) {
	int n = ps.size(), k = 0;
	sort(ps.begin(), ps.end());
	vector<P> ch(2*n);
	for(int i = 0 ; i < n ; ch[k++] = ps[i++] ){ // lower-hull
		while( k >= 2 && ccw(ch[k-2], ch[k-1], ps[i]) <= 0 ) --k;
	}
	for(int i = n-2, t = k+1 ; i >= 0 ; ch[k++] = ps[i--] ){ // upper-hull
		while (k >= t && ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
		ch.resize(k-1);
	}
	return ch;
}

// 凸多角形をある直線で切断し，その左側だけ残す．
Polygon convex_cut(const Polygon& g, const Line& l) {
	Polygon Q;
	int n = g.size();
	for(int i = 0 ; i < n ; i++ ){
		P A = g[i], B = g[(i+1) % n];
		if( ccw(l[0], l[1], A) != -1 ){
			Q.push_back(A);
		}
		if( ccw(l[0], l[1], A) * ccw(l[0], l[1], B) < 0 ){
			Q.push_back(crosspoint(Line(A, B), l));
		}
	}
	return Q;
}
// 凸多角形の重心を返す
P gravity(const Polygon& g) {
	P sg(0,0);
	double s = 0.0;
	for(int i=2 ; i < g.size() ; i++ ) {
		Triangle t( g[0] , g[i-1] , g[i] );
		s += t.get_area();
		sg += t.get_area() * t.gravity();
	};
	return sg / s;
}

// 点 p が凸多角形の内部・外部・境界のどれにあるか判定する.
int convex_contains(const Polygon& g, const P& p) {
	const int n = g.size();
	P pp = (g[0] + g[n/3] + g[2*n/3]) / 3.0;
	int a = 0, b = n;
	while( a + 1 < b ){
		int c = (a + b) / 2;
		if( cross(g[a] - pp, g[c] - pp) > 0 ){
			if( cross(g[a] - pp, p - pp) > 0 && cross(g[c] - pp, p - pp) < 0 ){
				b = c;
			}else{
				a = c;
			}
		}else{
			if( cross(g[a] - pp, p - pp) < 0 && cross(g[c] - pp, p - pp) > 0 ){
				a = c;
			}else{
				b = c;
			}
		}
	}
	b %= n;
	if( cross(g[a] - p, g[b] - p) < 0 ) return OUT;
	if( cross(g[a] - p, g[b] - p) > 0 ) return IN;
	return ON;
}

// 2つの凸多角形の共通部分の凸多角形を返す
bool intersect_1pt(const P& a, const P& b, const P& c, const P& d, P &r) {
	double D =  cross(b - a, d - c);
	if( equal(D,0) ) return false;
	double t =  cross(c - a, d - c) / D;
	double s = -cross(a - c, b - a) / D;
	r = a + t * (b - a);
	return ( t >= 0 && t <= 1 && s >= 0 && s <= 1 );
}
Polygon convex_intersect(Polygon p, Polygon q) {
	const int n = p.size();
	const int m = q.size();
	int a = 0, b = 0, aa = 0, ba = 0;
	enum { Pin, Qin, Unknown } in = Unknown;
	Polygon R;
	do {
		int a1 = (a+n-1) % n;
		int b1 = (b+m-1) % m;
		double C = cross( p[a] - p[a1] , q[b] - q[b1] );
		double A = cross( p[a1] - q[b], p[a] - q[b] );
		double B = cross( q[b1] - p[a], q[b] - p[a] );
		P r;
		if( intersect_1pt( p[a1], p[a], q[b1], q[b], r ) ) {
			if( in == Unknown ) aa = ba = 0;
			R.push_back( r );
			in = (B > 0) ? Pin : (A > 0)? Qin : in ;
		}
		if( C == 0 && B == 0 && A == 0 ) {
			if( in == Pin ) {
				b = (b + 1) % m;
				++ba;
			}else {
				a = (a + 1) % m;
				++aa;
			}
		}else if( C >= 0 ) {
			if( A > 0 ) {
				if( in == Pin ) R.push_back( p[a] );
				a = (a+1) % n;
				++aa;
			}else {
				if( in == Qin ) R.push_back( q[b] );
				b = (b+1) % m;
				++ba;
			}
		}else {
			if( B > 0 ) { 
				if( in == Qin ) R.push_back( q[b] );
				b = (b+1) % m;
				++ba;
			}else {
				if( in == Pin ) R.push_back( p[a] );
				a = (a+1) % n;
				++aa;
			}
		}
	}while( (aa < n || ba < m) && aa < 2*n && ba < 2*m );
	if( in == Unknown ) {
		if( convex_contains(q, p[0]) ) return p;
		if( convex_contains(p, q[0]) ) return q;
	}
	return R;
}

// 凸多角形の直径を求める. (最遠頂点対は pp に入る)
P diff(const Polygon& g, int i){
	return g[(i+1) % g.size()] - g[i];
}
double convex_diameter(const Polygon& pt, pair<P,P>& pp) {
	const int n = pt.size();
	int is = 0, js = 0;
	for(int i = 1 ; i < n ; i++ ){
		if( pt[i].y > pt[is].y ) is = i;
		if( pt[i].y < pt[js].y ) js = i;
	}
	double maxd = norm(pt[is] - pt[js]);
	int i, maxi, j, maxj;
	i = maxi = is;
	j = maxj = js;
	do{
		if( cross(diff(pt,i), diff(pt,j)) >= 0){
			j = (j+1) % n;
		}else{
			i = (i+1) % n;
		}
		
		if( norm(pt[i] - pt[j]) > maxd ){
			maxd = norm(pt[i] - pt[j]);
			maxi = i;
			maxj = j;
		}
	}while( i != is || j != js );
	pp = pair<P,P>(pt[maxi], pt[maxj]);
	return maxd;
}

// 直線 l の方向( l[0] から l[1] へのベクトル ) と 最も遠い点を返す
double d(int k, const Polygon& g, const Line& l) {
	return dot(g[k], l[1] - l[0]);
}
P convex_extreme(const Polygon& g, const Line& l) {
	int a = 0, b = g.size(), n = g.size();
	if( d(0,g,l) >= d(n-1,g,l) && d(0,g,l) >= d(1,g,l) ){
		return g[0];
	}
	while( a < b ) {
		int c = (a + b) / 2;
		if( d(c,g,l) >= d(c-1,g,l) && d(c,g,l) >= d(c+1,g,l) ){
			return g[c];
		}
		if( d(a+1,g,l) > d(a,g,l) ){
			if( d(c+1,g,l) <= d(c,g,l) || d(a,g,l) > d(c,g,l) ){
				b = c;
			}else{
				a = c;
			}
		}else{
			if( d(c+1,g,l) > d(c,g,l) || d(a,g,l) >= d(c,g,l) ){
				a = c;
			}else{
				b = c;
			}
		}
	}
}
int main(){
	double x1, y1, x2, y2, x3, y3, x4, y4;
	while( cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4 ){
		P p1(x1, y1), p2(x2, y2), p3(x3, y3), p4(x4, y4);
		Line l1(p1, p2), l2(p3, p4);
		cout << (is_orthogonal(l1, l2)? "YES" : "NO") << endl;
	}
}

Measured memory_bytes: 1228