// Copyright 2013-2014 The Algebra Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(clippy::suspicious_arithmetic_impl)]
pub mod mylib {

// use num_traits::PrimInt;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
use std::cmp::PartialEq;
use std::marker::PhantomData;
use alga::general::{Operator, Identity, AbstractMagma, AbstractSemigroup, AbstractMonoid, Additive};
use num::integer;

pub trait ToModInt<MOD: ModNumber> {
	fn to_modint(self) -> ModInt<MOD>;
}

pub trait ModNumber : Clone + Copy {
	type ModType: Clone + Copy;
	fn modv() -> u32;
	fn from_bi(x: i64) -> ModInt<Self>;
	fn from_bu(x: u64) -> ModInt<Self>;
	fn from_si(x: i32) -> ModInt<Self>;
	fn from_su(x: u32) -> ModInt<Self>;
}
macro_rules! from_bu_prim_to_modint {
	($($im:ty),*) => ($(
		#[inline]
		fn from_bu(x: u64) -> ModInt<$im> {
			let m = <$im>::modv() as u64;
			ModInt::<$im>((x % m) as u32)
		}
	)*)
}
macro_rules! from_bi_prim_to_modint {
	($($im:ty),*) => ($(
		#[inline]
		fn from_bi(i: i64) -> ModInt<$im> {
			let m = <$im>::modv() as i64;
			let mut i = i % m;
			if i < 0 {i += m;}
			ModInt::<$im>((i % m) as u32)
		}
	)*)
}
macro_rules! from_su_prim_to_modint {
	($($im:ty),*) => ($(
		#[inline]
		fn from_su(x: u32) -> ModInt<$im> {
			ModInt::<$im>(x % <$im>::modv())
		}
	)*)
}
macro_rules! from_si_prim_to_modint {
	($($im:ty),*) => ($(
		#[inline]
		fn from_si(x: i32) -> ModInt<$im> {
			let m = <$im>::modv() as i32;
			let mut x = x % m;
			if x < 0 {x += m;}
			ModInt::<$im>(x as u32)
		}
	)*)
}
macro_rules! impl_modint {
	($($im:ty,$fm:block);*) => ($(
		impl ModNumber for $im {
 			type ModType = u32;
			#[inline]
			fn modv() -> u32 $fm
			from_si_prim_to_modint!($im);
			from_su_prim_to_modint!($im);
			from_bi_prim_to_modint!($im);
			from_bu_prim_to_modint!($im);
		}
	)*)
}
impl_modint!(RuntimeMod,{unsafe {RUNTIME_MOD}}; Mod107, {1_000_000_007}; Mod998, {998_244_353});


#[derive(Clone, Copy)]
pub struct RuntimeMod {}
impl RuntimeMod {
	pub fn set(x: u32) {
		unsafe {
			RUNTIME_MOD = x;
		}
	}
}
#[derive(Clone, Copy)]
pub struct Mod107 {}
#[derive(Clone, Copy)]
pub struct Mod998 {}
// impl ModNumber for RuntimeMod {
// 	type ModType = u32;
// 	#[inline]
// 	fn modv() -> u32 {
// 		unsafe {
// 			RUNTIME_MOD
// 		}
// 	}
// }


// impl RuntimeMod {
// 	fn from_u8() -> <RuntimeMod as ModNumber>::ModType {
// 		let x: <RuntimeMod as ModNumber>::ModType = 1;
// 		x
// 	}
// }

// from_bu_prim_to_modint!(RuntimeMod, from_u64, u128);
#[derive(Clone, Copy)]
pub struct ModInt<MOD: ModNumber> (pub MOD::ModType);

macro_rules! impl_to_modint_bi {
	($($t:ty)*) => ($(
		impl <MOD: ModNumber> ToModInt<MOD> for $t {
			#[inline]
			fn to_modint(self) -> ModInt<MOD> {
				<MOD>::from_bi(self as i64)
			}
		}
	)*)
}
macro_rules! impl_to_modint_si {
	($($t:ty)*) => ($(
		impl <MOD: ModNumber> ToModInt<MOD> for $t {
			#[inline]
			fn to_modint(self) -> ModInt<MOD> {
				<MOD>::from_si(self as i32)
			}
		}
	)*)
}
macro_rules! impl_to_modint_bu {
	($($t:ty)*) => ($(
		impl <MOD: ModNumber> ToModInt<MOD> for $t {
			#[inline]
			fn to_modint(self) -> ModInt<MOD> {
				<MOD>::from_bu(self as u64)
			}
		}
	)*)
}
macro_rules! impl_to_modint_su {
	($($t:ty)*) => ($(
		impl <MOD: ModNumber> ToModInt<MOD> for $t {
			#[inline]
			fn to_modint(self) -> ModInt<MOD> {
				<MOD>::from_su(self as u32)
			}
		}
	)*)
}

impl_to_modint_si!(i8 i16);
impl_to_modint_bu!(u32 u64);
impl_to_modint_su!(u8 u16);
impl_to_modint_bi!(i32 i64);

static mut RUNTIME_MOD: u32 = 0;
impl<MOD: ModNumber> ModInt<MOD> {}
impl<MOD: ModNumber> ModInt<MOD> 
where 
	ModInt<MOD>: MulAssign
{
	pub fn pow(self, mut p: u64) -> Self {
		let mut res = self;
		let mut m = self;
		while p != 0 {
			if p & 1 == 1 {
				res *= m;
			}
			p >>= 1;
			m *= m;
		}
		res
	}
}
macro_rules! impl_modints {
	($($m:ty)*) => ($(
		impl Add<ModInt<$m>> for ModInt<$m> {
			type Output = ModInt<$m>;
			fn add(self, rhs: ModInt<$m>) -> ModInt<$m> {
				ModInt::<$m>((self.0 + rhs.0) % <$m>::modv())
			}
		}
		impl AddAssign<ModInt<$m>> for ModInt<$m> {
			fn add_assign(&mut self, rhs: ModInt<$m>) {
				*self = *self + rhs;
			}
		}
		impl Sub<ModInt<$m>> for ModInt<$m> {
			type Output = ModInt<$m>;
			fn sub(self, rhs: ModInt<$m>) -> ModInt<$m> {
				let mut x = self.0 as i32 - rhs.0 as i32;
				if x < 0 {x += <$m>::modv() as i32}
				ModInt::<$m>(x as u32 % <$m>::modv())
			}
		}
		impl SubAssign<ModInt<$m>> for ModInt<$m> {
			fn sub_assign(&mut self, rhs: ModInt<$m>) {
				*self = *self - rhs;
			}
		}
		impl Mul<ModInt<$m>> for ModInt<$m> {
			type Output = ModInt<$m>;
			fn mul(self, rhs: ModInt<$m>) -> ModInt<$m> {
				let x = self.0 as u64 * rhs.0 as u64;
				ModInt::<$m>((x % <$m>::modv() as u64) as u32)
			}
		}
		impl MulAssign<ModInt<$m>> for ModInt<$m> {
			fn mul_assign(&mut self, rhs: ModInt<$m>) {
				*self = *self * rhs;
			}
		}
		impl Div<ModInt<$m>> for ModInt<$m> {
			type Output = ModInt<$m>;
			fn div(self, rhs: ModInt<$m>) -> ModInt<$m> {
				self * rhs.pow((<$m>::modv() - 2) as u64)
			}
		}
		impl DivAssign<ModInt<$m>> for ModInt<$m> {
			fn div_assign(&mut self, rhs: ModInt<$m>) {
				*self = *self / rhs;
			}
		}
		impl PartialEq<ModInt<$m>> for ModInt<$m> {
			fn eq(&self, rhs: &ModInt<$m>) -> bool {
				self.0 == rhs.0
			}
		}
	)*)
}
impl_modints!(Mod107 Mod998 RuntimeMod);
macro_rules! impl_modint_primint {
	($m:ty, $($t:ty)*) => ($(
		impl Add<$t> for ModInt<$m> {
			type Output = ModInt<$m>;
			fn add(self, rhs: $t) -> ModInt<$m> {
				self + rhs.to_modint()
			}
		}
		impl AddAssign<$t> for ModInt<$m> {
			fn add_assign(&mut self, rhs: $t) {
				*self = *self + rhs;
			}
		}
		impl Sub<$t> for ModInt<$m> {
			type Output = ModInt<$m>;
			fn sub(self, rhs: $t) -> ModInt<$m> {
				self - rhs.to_modint()
			}
		}
		impl SubAssign<$t> for ModInt<$m> {
			fn sub_assign(&mut self, rhs: $t) {
				*self = *self - rhs;
			}
		}
		impl Mul<$t> for ModInt<$m> {
			type Output = ModInt<$m>;
			fn mul(self, rhs: $t) -> ModInt<$m> {
				self * rhs.to_modint()
			}
		}
		impl MulAssign<$t> for ModInt<$m> {
			fn mul_assign(&mut self, rhs: $t) {
				*self = *self * rhs;
			}
		}
		impl Div<$t> for ModInt<$m> {
			type Output = ModInt<$m>;
			fn div(self, rhs: $t) -> ModInt<$m> {
				self / rhs.to_modint()
			}
		}
		impl DivAssign<$t> for ModInt<$m> {
			fn div_assign(&mut self, rhs: $t) {
				*self = *self / rhs;
			}
		}
	)*)
}
impl_modint_primint!(    Mod107, u8 u16 u32 u64 i8 i16 i32 i64);
impl_modint_primint!(    Mod998, u8 u16 u32 u64 i8 i16 i32 i64);
impl_modint_primint!(RuntimeMod, u8 u16 u32 u64 i8 i16 i32 i64);


macro_rules! impl_marker(
	// Finds the generic parameters of the type and implements the trait for it
	(@para_rec
		[$tra1t:ty, ($($clause:tt)+), ($($type_constr:tt)*)]
		(< $($params:tt)*)
	) => {
		impl< $($params)* $tra1t for $($type_constr)*< $($params)*
			where $($clause)+
		{}
	};
	// Munches some token trees for searching generic parameters of the type
	(@para_rec
		[$tra1t:ty, ($($clause:tt)+), ($($prev:tt)*)]
		($cur:tt $($rest:tt)*)
	) => {
		impl_marker!(@para_rec
			[$tra1t, ($($clause)+), ($($prev)* $cur)]
			($($rest)*)
		);
	};
	// Handles the trailing separator after where clause
	(@where_rec
		[$tra1t:ty, ($($typ3:tt)+), ($($clause:tt)+)]
		($(;)*)
	) => {
		impl_marker!(@para_rec
			[$tra1t, ($($clause)+), ()]
			($($typ3)+)
		);
	};
	// Implements the trait for the generic type and continues searching other types
	(@where_rec
		[$tra1t:ty, ($($typ3:tt)+), ($($clause:tt)+)]
		(; $($rest:tt)+)
	) => {
		impl_marker!(@para_rec
			[$tra1t, ($($clause)+), ()]
			($($typ3)+)
		);
		impl_marker!(@rec
			[$tra1t, ()]
			($($rest)+)
		);
	};
	// Munches some token trees for searching the end of the where clause
	(@where_rec
		[$tra1t:ty, ($($typ3:tt)+), ($($prev:tt)*)]
		($cur:tt $($rest:tt)*)
	) => {
		impl_marker!(@where_rec
			[$tra1t, ($($typ3)+), ($($prev)* $cur)]
			($($rest)*)
		);
	};
	// Handles the trailing separator for non-generic type and implements the trait
	(@rec
		[$tra1t:ty, ($($typ3:tt)*)]
		($(;)*)
	) => {
		impl $tra1t for $($typ3)* { }
	};
	// Implements the trait for the non-generic type and continues searching other types
	(@rec
		[$tra1t:ty, ($($typ3:tt)*)]
		(; $($rest:tt)+)
	) => {
		impl $tra1t for $($typ3)* { }
		impl_marker!(@rec
			[$tra1t, ()]
			($($rest)+)
		);
	};
	// Detects that there is indeed a where clause for the type and tries to find where it ends.
	(@rec
		[$tra1t:ty, ($($prev:tt)+)]
		(where $($rest:tt)+)
	) => {
		impl_marker!(@where_rec
			[$tra1t, ($($prev)+), ()]
			($($rest)+)
		);
	};
	// Munches some token trees for detecting if we have where clause or not
	(@rec
		[$tra1t:ty, ($($prev:tt)*)]
		($cur:tt $($rest:tt)*)
	) => {
		impl_marker!(@rec
			[$tra1t, ($($prev)* $cur)]
			($($rest)*)
		);
	};
	// Entry point to the macro
	($tra1t:ty; $($rest:tt)+) => {
		impl_marker!(@rec
			[$tra1t, ()]
			($($rest)+)
		);
	};
);
macro_rules! impl_magma(
	($M:ty; $op: ident; $($T:ty),* $(,)*) => {
		$(impl AbstractMagma<$M> for $T {
			#[inline]
			fn operate(&self, lhs: &Self) -> Self {
				self.$op(*lhs)
			}
		})*
	}
);
macro_rules! impl_semigroup(
	(<$M:ty> for $($T:tt)+) => {
		impl_marker!(AbstractSemigroup<$M>; $($T)+);
	}
);
macro_rules! impl_monoid(
	(<$M:ty> for $($T:tt)+) => {
		impl_semigroup!(<$M> for $($T)+);
		impl_marker!(AbstractMonoid<$M>; $($T)+);
	}
);
macro_rules! impl_ident {
	($M:ty; $V:expr; $($T:ty),* $(,)*) => {
		$(impl Identity<$M> for $T { #[inline] fn identity() -> $T {$V} })+
	}
}


pub struct SegmentTree<T, O> 
where
	T: AbstractMonoid<O> + Copy,
	O: Operator,
{
	size: usize,
	monoid: Vec<T>,
	_phantom: PhantomData<fn() -> O>,
}
impl<T, O> SegmentTree<T, O>
where
	T: AbstractMonoid<O> + Copy,
	O: Operator
{
	pub fn new(sz: usize) -> Self {
		let mut n = 1usize;
		while n < sz {
			n <<= 1;
		}
		SegmentTree{size: n, monoid: vec![T::identity(); n*2-1], _phantom: PhantomData}
	}
	pub fn build(v: &[T]) -> Self {
		let mut seg = Self::new(v.len());
		for (i, e) in v.iter().enumerate() {
			seg.monoid[i+seg.size-1] = *e;
		}
		for i in (0..seg.size-1).rev() {
			seg.monoid[i] = seg.monoid[i*2+1].operate(&seg.monoid[i*2+2]);
		}
		seg
	}
	pub fn set(&mut self, i: usize, v: T) {
		let mut i = i + self.size - 1;
		self.monoid[i] = v;
		while i != 0 {
			i = (i-1) / 2;
			self.monoid[i] = self.monoid[i*2+1].operate(&self.monoid[i*2+2]);
		}
	}
	pub fn get(&self, l: usize, r: usize) -> T {
		let mut lm = T::identity();
		let mut rm = T::identity();
		let mut l = l + self.size - 1;
		let mut r = r + self.size - 1;
		while l < r {
			if l & 1 == 0 {lm = lm.operate(&self.monoid[l]);}
			if r & 1 == 0 {rm = self.monoid[r-1].operate(&rm);}
			l /= 2;
			r = (r - 1) / 2;
		}
		lm.operate(&rm)
	}
	pub fn at(&self, p: usize) -> T {
		self.monoid[p + self.size-1]
	}
}

#[derive(Clone, Copy)]
pub struct Affine;

impl Operator for Affine {
	fn operator_token() -> Self {
		Affine
	}
}

trait AffineTrait<T> {
	fn affine(self, lhs: Self) -> Self;
}
macro_rules! impl_affine(
	($($T:ty),* $(,)*) => {
		$(impl AffineTrait<($T, $T)> for ($T, $T) {
			#[inline]
			fn affine(self, lhs: Self) -> Self {
				(self.0 * lhs.0, self.1 * lhs.0 + lhs.1)
			}
		})*
	}
);
impl_affine!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64, ModInt<Mod107>, ModInt<Mod998>, ModInt<RuntimeMod>);
impl_ident!(Affine; (1, 0); (u8, u8), (u16, u16), (u32, u32), (u64, u64), (usize, usize), (i8, i8), (i16, i16), (i32, i32), (i64, i64), (isize, isize));
impl_ident!(Affine; (1.0, 0.0); (f32, f32), (f64, f64));
impl_ident!(Affine; (ModInt::<Mod107>(1), ModInt::<Mod107>(0)); (ModInt<Mod107>, ModInt<Mod107>));
impl_ident!(Affine; (ModInt::<Mod998>(1), ModInt::<Mod998>(0)); (ModInt<Mod998>, ModInt<Mod998>));
impl_ident!(Affine; (ModInt::<RuntimeMod>(1), ModInt::<RuntimeMod>(0)); (ModInt<RuntimeMod>, ModInt<RuntimeMod>));
impl_magma!(Affine; affine; (u8, u8), (u16, u16), (u32, u32), (u64, u64), (usize, usize), (i8, i8), (i16, i16), (i32, i32), (i64, i64), (isize, isize), (f32, f32), (f64, f64),
           (ModInt<Mod107>, ModInt<Mod107>), (ModInt<Mod998>, ModInt<Mod998>), (ModInt<RuntimeMod>, ModInt<RuntimeMod>));
impl_monoid!(<Affine> for (u8, u8); (u16, u16); (u32, u32); (u64, u64); (usize, usize); (i8, i8); (i16, i16); (i32, i32); (i64, i64); (isize, isize); (f32, f32); (f64, f64);
						  (ModInt<Mod107>, ModInt<Mod107>); (ModInt<Mod998>, ModInt<Mod998>); (ModInt<RuntimeMod>, ModInt<RuntimeMod>));

#[derive(Clone, Copy)]
pub struct GCD;

impl Operator for GCD {
	fn operator_token() -> Self {
		GCD
	}
}

trait GCDTrait<T> {
	fn gcd(self, lhs: Self) -> Self;
}
macro_rules! impl_gcd(
	($($T:ty),* $(,)*) => {
		$(impl GCDTrait<$T> for $T {
			#[inline]
			fn gcd(self, lhs: Self) -> Self {
				integer::gcd(self, lhs)
			}
		})*
	}
);
impl_gcd!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
impl_ident!(GCD; 0; u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
impl_magma!(GCD; gcd; u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
impl_monoid!(<GCD> for u8; u16; u32; u64; usize; i8; i16; i32; i64; isize);

impl_ident!(Additive; ModInt::<Mod107>(0); ModInt<Mod107>);
impl_ident!(Additive; ModInt::<Mod998>(0); ModInt<Mod998>);
impl_ident!(Additive; ModInt::<RuntimeMod>(0); ModInt<RuntimeMod>);
impl_magma!(Additive; add; ModInt<Mod107>, ModInt<Mod998>, ModInt<RuntimeMod>);
impl_monoid!(<Additive> for ModInt<Mod107>; ModInt<Mod998>; ModInt<RuntimeMod>);

pub type RangeSum<T> = SegmentTree<T, Additive>;
pub type RangeGCD<T> = SegmentTree<T, GCD>;
pub type RangeAffine<T> = SegmentTree<(T, T), Affine>;


} // mod mylib

use proconio::input;
// type ModType = mylib::RuntimeMod;
// type ModType = mylib::Mod107;
// type ModType = mylib::Mod998;
// type ModInt = mylib::ModInt<ModType>;

// #[inline]
// fn modint<T: mylib::ToModInt<ModType>>(x: T) -> ModInt {
// 	x.to_modint()
// }

// use std::time::Instant;


fn main() {
	input! {
		n: usize,
		a: [i32; n],
	}
	let seg = mylib::RangeGCD::build(&a);
	let mut res = 1;
	for i in 0..n {
		res = std::cmp::max(res, num::integer::gcd(seg.get(0, i), seg.get(i+1, n)));
	}
	println!("{}", res);
}

// fn main() {
// 	input! {
// 		n: usize,
// 		q: usize,
// 		a: [i64; n],
// 		querys: [(i32, i64, i64); q]
// 	}
// 	let start = Instant::now();
// 	let mut seg = mylib::RangeSum::<i64>::build(&a);
// 	for query in querys {
// 		if query.0 == 0 {
// 			let p = query.1 as usize;
// 			let x = query.2;
// 			seg.set(p, seg.at(p) + x);
// 		} else {
// 			let l = query.1 as usize;
// 			let r = query.2 as usize;
// 			println!("{}", seg.get(l, r));
// 		}
// 	}
// 	let end = start.elapsed();
// 	println!("{}.{:03}", end.as_secs(), end.subsec_millis());
// }

// fn main() {
// 	input! {
// 		n: usize,
// 		q: usize,
// 		ab: [(i64, i64); n],
// 		querys: [(i32, i64, i64, i64); q]
// 	}
// 	let start = Instant::now();
// 	let mut seg = mylib::RangeAffine::<ModInt>::new(n);
// 	for (i, e) in ab.iter().enumerate() {
// 		seg.set(i, (modint(e.0), modint(e.1)));
// 	}
// 	for query in querys {
// 		if query.0 == 0 {
// 			let p = query.1 as usize;
// 			let c = modint(query.2);
// 			let d = modint(query.3);
// 			seg.set(p, (c, d));
// 		} else {
// 			let l = query.1 as usize;
// 			let r = query.2 as usize;
// 			let x = modint(query.3);
// 			let res = seg.get(l, r);
// 			println!("{}", (x * res.0 + res.1).0);
// 		}
// 	}
// 	let end = start.elapsed();
// 	println!("{}.{:03}", end.as_secs(), end.subsec_millis());
// }

// fn main() {
// 	let start = Instant::now();
// 	let mut sc = Scanner::new();
// 	let n: usize = sc.cin();
// 	let q: usize = sc.cin();
// 	let aa = modint(1);
// 	let bb = aa + modint(1);
// 	println!("{}", bb.0);
// 	// mylib::RuntimeMod::set(n as u32 / 10000000 + 998244353);
// 	let mut seg = mylib::RangeAffine::<ModInt>::new(n);
// 	for i in 0..n {
// 		let a: u32 = sc.cin();
// 		let b: u32 = sc.cin();
// 		seg.set(i, (modint(a), modint(b)));
// 	}
// 	for _ in 0..q {
// 		let c: i32 = sc.cin();
// 		if c == 0 {
// 			let p: usize = sc.cin();
// 			let c: u32 = sc.cin();
// 			let d: u32 = sc.cin();
// 			let c = modint(c);
// 			let d = modint(d);
// 			seg.set(p, (c, d));
// 		} else {
// 			let l: usize = sc.cin();
// 			let r: usize = sc.cin();
// 			let x: u32 = sc.cin();
// 			let x = modint(x);
// 			let res = seg.get(l, r);
// 			println!("{}", (x * res.0 + res.1).0);
// 		}
// 	}
// 	let end = start.elapsed();
// 	println!("{}.{:03}", end.as_secs(), end.subsec_nanos() / 1_000_000);
// }


// use std::io::{self, Write};
// use std::str::FromStr;
// use std::collections::VecDeque;

// struct Scanner { stdin: io::Stdin, buffer: VecDeque<String>, }
// impl Scanner {
//     fn new() -> Self { Scanner { stdin: io::stdin(), buffer: VecDeque::new() } }
//     fn cin<T: FromStr>(&mut self) -> T {
//         while self.buffer.len() == 0 {
//             let mut line = String::new();
//             let _ = self.stdin.read_line(&mut line);
//             for w in line.split_whitespace() {
//                 self.buffer.push_back(String::from(w));
//             }
//         }
//         self.buffer.pop_front().unwrap().parse::<T>().ok().unwrap()
//     }
//     fn chars(&mut self) -> Vec<char> { self.cin::<String>().chars().collect() }
//     fn vec<T: FromStr>(&mut self, n: usize) -> Vec<T> { (0..n).map(|_| self.cin()).collect() }
// }


Measured memory_bytes: 4380