use proconio::input;

fn main() {
    input! {
        n: u64,
    }

    type Mi = ModInt<Mod1e9p7>;

    let res =
        Mi::new(10).pow(n) - Mi::new(2) * Mi::new(9).pow(n) + Mi::new(8).pow(n);

    println!("{}", res);
}

// /////////////////////////////////////////////////////////////
use std::fmt;
use std::marker::PhantomData;
use std::ops::*;

#[derive(Clone, Copy, Eq, PartialEq, fmt::Debug)]
struct ModInt<M: Mod> {
    n: i64,
    _p: PhantomData<M>,
}

impl<M: Mod> Add<ModInt<M>> for ModInt<M> {
    type Output = Self;
    fn add(self, other: Self) -> Self::Output {
        let mut n = self.n + other.n;
        if n < 0 {
            n += M::get();
        } else if n >= M::get() {
            n -= M::get();
        }
        Self { n, _p: PhantomData }
    }
}

impl<M: Mod> AddAssign<ModInt<M>> for ModInt<M> {
    fn add_assign(&mut self, other: Self) {
        self.n += other.n;
        if self.n < 0 {
            self.n += M::get();
        } else if self.n >= M::get() {
            self.n -= M::get();
        }
    }
}

impl<M: Mod> Sub<ModInt<M>> for ModInt<M> {
    type Output = Self;
    fn sub(self, other: Self) -> Self::Output {
        let mut n = self.n - other.n;
        if n < 0 {
            n += M::get();
        } else if n >= M::get() {
            n -= M::get();
        }
        Self { n, _p: PhantomData }
    }
}

impl<M: Mod> SubAssign<ModInt<M>> for ModInt<M> {
    fn sub_assign(&mut self, other: Self) {
        self.n -= other.n;
        if self.n < 0 {
            self.n += M::get();
        } else if self.n >= M::get() {
            self.n -= M::get();
        }
    }
}

impl<M: Mod> Mul<ModInt<M>> for ModInt<M> {
    type Output = Self;
    fn mul(self, other: Self) -> Self::Output {
        let n = (self.n * other.n).rem_euclid(M::get());
        Self { n, _p: PhantomData }
    }
}

impl<M: Mod> MulAssign<ModInt<M>> for ModInt<M> {
    fn mul_assign(&mut self, other: Self) {
        self.n = (self.n * other.n).rem_euclid(M::get());
    }
}

impl<M: Mod> Div<ModInt<M>> for ModInt<M> {
    type Output = Self;
    fn div(self, other: Self) -> Self::Output {
        let n = (self.n * other.recip().unwrap().n).rem_euclid(M::get());
        Self { n, _p: PhantomData }
    }
}

impl<M: Mod> DivAssign<ModInt<M>> for ModInt<M> {
    fn div_assign(&mut self, other: Self) {
        self.n = (self.n * other.recip().unwrap().n).rem_euclid(M::get());
    }
}

impl<M: Mod> Neg for ModInt<M> {
    type Output = Self;
    fn neg(self) -> Self::Output {
        if self.n == 0 {
            Self {
                n: 0,
                _p: PhantomData,
            }
        } else {
            Self {
                n: M::get() - self.n,
                _p: PhantomData,
            }
        }
    }
}

impl<M: Mod> fmt::Display for ModInt<M> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.n)
    }
}

impl<M: Mod> ModInt<M> {
    fn new(n: i64) -> Self {
        let n = n.rem_euclid(M::get());
        Self { n, _p: PhantomData }
    }

    fn get(self) -> i64 {
        self.n
    }

    fn recip(self) -> Option<Self> {
        let mut x = 0i64;
        let mut y = 1i64;
        let mut a = self.n;
        let mut b = M::get();
        let mut u = y;
        let mut v = x;
        while a != 0 {
            let q = b / a;
            let tmp = x - q * u;
            x = u;
            u = tmp;
            let tmp = y - q * v;
            y = v;
            v = tmp;
            let tmp = b - q * a;
            b = a;
            a = tmp;
        }
        if b == 1 {
            Some(Self::new(x))
        } else {
            None
        }
    }

    fn pow(self, mut n: u64) -> Self {
        let mut res = ModInt::<M>::new(1);
        let mut dbl = self.clone();
        while n > 0 {
            if n & 1 == 1 {
                res *= dbl;
            }
            dbl *= dbl;
            n >>= 1;
        }
        res
    }
}

trait Mod: Copy + Clone + fmt::Debug {
    fn get() -> i64;
}

#[derive(Copy, Clone, fmt::Debug)]
struct Mod1e9p7 {}

impl Mod for Mod1e9p7 {
    fn get() -> i64 {
        1_000_000_007
    }
}

#[derive(fmt::Debug)]
struct ModValTable<M> {
    fact: Vec<M>,
    fact_inv: Vec<M>,
    inv: Vec<M>,
}

impl<M: Mod> ModValTable<ModInt<M>> {
    fn new(n: usize) -> Self {
        let mut fact = vec![ModInt::<M>::new(1); n + 1];
        let mut fact_inv = vec![ModInt::<M>::new(1); n + 1];
        let mut inv = vec![ModInt::<M>::new(1); n + 1];
        for i in 2..=n {
            fact[i] = fact[i - 1] * ModInt::<M>::new(i as i64);
            inv[i] = -ModInt::<M>::new(M::get() / i as i64)
                * inv[M::get() as usize % i];
            fact_inv[i] = fact_inv[i - 1] * inv[i];
        }

        Self {
            fact,
            fact_inv,
            inv,
        }
    }

    fn perm(&self, n: usize, r: usize) -> ModInt<M> {
        if n < r {
            ModInt::<M>::new(0)
        } else {
            self.fact[n] * self.fact_inv[n - r]
        }
    }

    fn binom(&self, n: usize, r: usize) -> ModInt<M> {
        if n < r {
            ModInt::<M>::new(0)
        } else {
            self.fact[n] * self.fact_inv[r] * self.fact_inv[n - r]
        }
    }

    fn mulnom(&self, n: usize, r: usize) -> ModInt<M> {
        self.binom(n + r - 1, r)
    }

    fn fact(&self, n: usize) -> ModInt<M> {
        self.fact[n]
    }

    fn fact_recip(&self, n: usize) -> ModInt<M> {
        self.fact_inv[n]
    }

    fn recip(&self, n: usize) -> ModInt<M> {
        self.inv[n]
    }
}
// /////////////////////////////////////////////////////////////


Measured memory_bytes: 2124