//! # Bundled libraries
//!
//! ## `kyopro_lib` (private)
//!
//! ### Modules
//!
//! - `::__kyopro_lib::modint` → `$crate::modint`

#[allow(unused_imports)]
use itertools::Itertools;
use proconio::input;
#[allow(unused_imports)]
use proconio::marker::*;

/*#[cfg_attr(cargo_equip, cargo_equip::equip)]
use ::__kyopro_lib::modint;*/

type Mint = modint::Mint1_000_000_007;

fn main() {
    input! {
        n: u64,
    }
    let mut res = Mint::new(10).pow(n);
    res -= Mint::new(9).pow(n);
    res -= Mint::new(9).pow(n);
    res += Mint::new(8).pow(n);
    println!("{}", res);
}

// The following code was expanded by `cargo-equip`.

pub mod modint {
    /// aaa
    pub trait Modulation {
        const MOD: u64;
    }
    //b
    #[derive(PartialEq)]
    pub struct ModInt<M: Modulation> {
        x: u64,
        phantom: std::marker::PhantomData<M>,
    }

    impl<M: Modulation> Clone for ModInt<M> {
        fn clone(&self) -> Self {
            Self::new_uncheck(self.x)
        }
    }
    impl<M: Modulation> Copy for ModInt<M> {}

    impl<M: Modulation> std::fmt::Display for ModInt<M> {
        fn fmt(&self, dest: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
            write!(dest, "{}", self.x)
        }
    }

    impl<M: Modulation> ModInt<M> {
        #[inline]
        pub fn new(x: u64) -> Self {
            Self {
                x: x % M::MOD,
                phantom: std::marker::PhantomData,
            }
        }
        #[inline]
        pub fn from_signed(x: i64) -> Self {
            let x = if x >= 0 {
                x as u64 % M::MOD
            } else {
                (M::MOD as i64 + x % M::MOD as i64) as u64
            };
            Self {
                x: x,
                phantom: std::marker::PhantomData,
            }
        }
        #[inline]
        pub fn new_uncheck(x: u64) -> Self {
            Self {
                x: x,
                phantom: std::marker::PhantomData,
            }
        }
        #[inline]
        pub fn val(&self) -> u64 {
            self.x
        }
    }

    macro_rules! def_from_trait {
        (u, $t:ty) => {
            impl<M: Modulation> std::convert::From<$t> for ModInt<M> {
                #[inline]
                fn from(x: $t) -> Self {
                    Self::new(x as u64)
                }
            }
        };
        (i, $t:ty) => {
            impl<M: Modulation> std::convert::From<$t> for ModInt<M> {
                #[inline]
                fn from(x: $t) -> Self {
                    Self::from_signed(x as i64)
                }
            }
        };
    }

    def_from_trait!(u, u8);
    def_from_trait!(u, u16);
    def_from_trait!(u, u32);
    def_from_trait!(u, u64);
    def_from_trait!(u, usize);
    def_from_trait!(i, i8);
    def_from_trait!(i, i16);
    def_from_trait!(i, i32);
    def_from_trait!(i, i64);
    def_from_trait!(i, isize);

    impl<M: Modulation> std::ops::Neg for ModInt<M> {
        type Output = Self;
        #[inline]
        fn neg(self) -> Self {
            Self {
                x: if self.x == 0 { 0 } else { M::MOD - self.x },
                phantom: std::marker::PhantomData,
            }
        }
    }

    impl<M: Modulation> std::ops::AddAssign for ModInt<M> {
        #[inline]
        fn add_assign(&mut self, rhs: Self) {
            self.x += rhs.x;
            if M::MOD <= self.x {
                self.x -= M::MOD;
            }
        }
    }
    impl<M: Modulation> std::ops::Add for ModInt<M> {
        type Output = Self;
        #[inline]
        fn add(self, rhs: Self) -> Self {
            let mut res = self;
            res += rhs;
            res
        }
    }
    impl<M: Modulation> std::ops::SubAssign for ModInt<M> {
        #[inline]
        fn sub_assign(&mut self, rhs: Self) {
            if self.x >= rhs.x {
                self.x -= rhs.x;
            } else {
                self.x += M::MOD - rhs.x;
            }
        }
    }
    impl<M: Modulation> std::ops::Sub for ModInt<M> {
        type Output = Self;
        #[inline]
        fn sub(self, rhs: Self) -> Self {
            let mut res = self;
            res -= rhs;
            res
        }
    }
    impl<M: Modulation> std::ops::MulAssign for ModInt<M> {
        #[inline]
        fn mul_assign(&mut self, rhs: Self) {
            self.x *= rhs.x;
            self.x %= M::MOD;
        }
    }
    impl<M: Modulation> std::ops::Mul for ModInt<M> {
        type Output = Self;
        #[inline]
        fn mul(self, rhs: Self) -> Self {
            let mut res = self;
            res *= rhs;
            res
        }
    }

    /// ax + by = gcd(a,b) を満たす最小のx,yの組 + gcd
    /// ```
    /// // assert_eq!(ext_gcd(4,6),(-1,1,2));
    /// ```
    fn ext_gcd(a: u64, b: u64) -> (i64, i64, u64) {
        if b == 0 {
            (1, 0, a)
        } else {
            let (mut y, x, d) = ext_gcd(b, a % b);
            y -= (a / b) as i64 * x;
            (x, y, d)
        }
    }

    impl<M: Modulation> ModInt<M> {
        pub fn pow(&self, mut n: u64) -> Self {
            let mut res = Self::new_uncheck(1);
            let mut d = *self;
            while n != 0 {
                if n & 1 != 0 {
                    res *= d;
                }
                d *= d;
                n >>= 1;
            }
            res
        }

        pub fn inv(&self) -> Self {
            let (mut x, _, _) = ext_gcd(self.x, M::MOD);
            if x < 0 {
                x %= M::MOD as i64;
                x += M::MOD as i64;
            }
            Self::new(x as u64)
        }

        pub fn gen_factorial(n: u64) -> Factorial<M> {
            let n = n as usize;
            let mut pos = vec![Self::new_uncheck(1); n + 1];
            let mut neg = vec![Self::new_uncheck(1); n + 1];
            for i in 1..n {
                pos[i + 1] = pos[i] * Self::new(i as u64 + 1);
            }
            neg[n] = pos[n].inv();
            for i in (1..n).rev() {
                neg[i] = neg[i + 1] * Self::new(i as u64 + 1);
            }

            Factorial { pos: pos, neg: neg }
        }
        pub fn gen_inv(n: u64) -> Vec<Self> {
            let mut res = vec![Self::new_uncheck(1); (n + 1) as usize];
            for i in 2..=n {
                res[i as usize] =
                    Self::new_uncheck(M::MOD - M::MOD / i) * res[(M::MOD % i) as usize];
            }
            res
        }
    }

    pub struct Factorial<M: Modulation> {
        pos: Vec<ModInt<M>>,
        neg: Vec<ModInt<M>>,
    }
    impl<M: Modulation> Factorial<M> {
        pub fn permutation(&self, n: u64, r: u64) -> ModInt<M> {
            if r > n {
                ModInt::new(0)
            } else {
                self.pos[n as usize] * self.neg[(n - r) as usize]
            }
        }

        pub fn binomial(&self, n: u64, r: u64) -> ModInt<M> {
            if r > n {
                ModInt::new(0)
            } else {
                self.pos[n as usize] * self.neg[r as usize] * self.neg[(n - r) as usize]
            }
        }
        pub fn cmb_with_rep(&self, n: u64, r: u64) -> ModInt<M> {
            self.binomial(n + r - 1, r)
        }
    }

    pub struct F1_000_000_007;
    impl Modulation for F1_000_000_007 {
        const MOD: u64 = 1_000_000_007;
    }
    pub type Mint1_000_000_007 = ModInt<F1_000_000_007>;

    pub struct F998_244_353;
    impl Modulation for F998_244_353 {
        const MOD: u64 = 998_244_353;
    }
    pub type Mint998_244_353 = ModInt<F998_244_353>;
}


Measured memory_bytes: 2136