#![allow(unused_macros)]
#![allow(dead_code)]
#![allow(unused_imports)]

use itertools::Itertools;
use proconio::*;
use std::collections::VecDeque;
use std::io::stdin;
use std::str::FromStr;
use text_io::*;

const U_INF: usize = 1 << 60;
const I_INF: isize = 1 << 60;

fn main() {
    let mut sc = Scanner::new();
    let n = sc.next_usize();

    if n == 1 {
        println!("{}", 0);
        return;
    }

    let mut ans = ModInt::new(1);
    for i in 0..n {
        ans *= ModInt::new(10);
    }

    let mut a = ModInt::new(1);
    for i in 0..n {
        a *= ModInt::new(9);
    }

    let mut min = ModInt::new(1);
    for i in 0..n {
        min *= ModInt::new(8);
    }

    println!("{}", ans + min - ModInt::new(2) * a);
}

use std::fmt::{Display, Formatter};
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};

pub const MOD: isize = 1000000007;
// pub const MOD: isize = 998244353;

/// 常に設定したModを取り続ける正整数型
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct ModInt {
    /// 保持する値
    value: isize,
}

impl ModInt {
    /// isizeを受け取り、ModIntに変換する
    pub fn new(n: isize) -> Self {
        let mut value = n % MOD;
        if value < 0 {
            value += MOD;
        }
        Self { value }
    }

    /// べき乗計算関数
    /// 二分累乗法を用いるため、計算量はO(log n)
    pub fn pow(self, n: usize) -> Self {
        if n == 0 {
            1.into()
        } else if n == 1 {
            self
        } else if n % 2 == 0 {
            (self * 2.into()).pow(n / 2)
        } else {
            self * self.pow(n - 1)
        }
    }

    /// 逆元を返す
    /// フェルマーの少定理より、べき乗を用いて計算するため、計算量はO8log MOD)
    pub fn inv(self) -> Self {
        self.pow((MOD - 2) as usize)
    }
}

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

impl From<usize> for ModInt {
    fn from(n: usize) -> Self {
        Self::new(n as isize)
    }
}

impl From<u64> for ModInt {
    fn from(n: u64) -> Self {
        Self::new(n as isize)
    }
}

impl From<u32> for ModInt {
    fn from(n: u32) -> Self {
        Self::new(n as isize)
    }
}

impl From<u16> for ModInt {
    fn from(n: u16) -> Self {
        Self::new(n as isize)
    }
}

impl From<u8> for ModInt {
    fn from(n: u8) -> Self {
        Self::new(n as isize)
    }
}

impl From<isize> for ModInt {
    fn from(n: isize) -> Self {
        Self::new(n)
    }
}

impl From<i64> for ModInt {
    fn from(n: i64) -> Self {
        Self::new(n as isize)
    }
}

impl From<i32> for ModInt {
    fn from(n: i32) -> Self {
        Self::new(n as isize)
    }
}

impl From<i16> for ModInt {
    fn from(n: i16) -> Self {
        Self::new(n as isize)
    }
}

impl From<i8> for ModInt {
    fn from(n: i8) -> Self {
        Self::new(n as isize)
    }
}

impl Add for ModInt {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        let mut tmp = self.value + rhs.value;
        if tmp >= MOD {
            tmp %= MOD;
        }

        Self { value: tmp }
    }
}

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

impl Sub for ModInt {
    type Output = ModInt;

    fn sub(self, rhs: Self) -> Self::Output {
        let mut tmp = self.value;
        if tmp < rhs.value {
            tmp += MOD;
        }
        tmp -= rhs.value;
        if tmp >= MOD {
            tmp %= MOD;
        }

        Self { value: tmp }
    }
}

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

impl Mul for ModInt {
    type Output = ModInt;

    fn mul(self, rhs: Self) -> Self::Output {
        let mut tmp = self.value * rhs.value;
        if tmp >= MOD {
            tmp %= MOD;
        }

        Self { value: tmp }
    }
}

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

impl Div for ModInt {
    type Output = ModInt;

    fn div(self, rhs: Self) -> Self::Output {
        self * rhs.inv()
    }
}

impl DivAssign for ModInt {
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs;
    }
}

/// 高速に二項係数を求める構造体
pub struct Combination {
    /// `0..=n`分の階乗値を保持
    factorial: Vec<ModInt>,
    /// `0..=n`分の階乗値の逆元を保持
    factorial_inv: Vec<ModInt>,
}

impl Combination {
    /// 初期化処理
    /// 計算量はO(n)
    pub fn new(n: usize) -> Self {
        let mut factorial = Vec::with_capacity(n + 1);
        let mut factorial_inv = Vec::with_capacity(n + 1);

        factorial.push(ModInt::new(1));

        for i in 1..=n {
            factorial.push(factorial[i - 1] * (i as i32).into());
        }

        factorial_inv.push(factorial[n].inv());

        for i in (0..n).rev() {
            factorial_inv[i] = factorial_inv[i + 1] * ((i + 1) as i32).into();
        }

        let factorial_inv = factorial_inv.into_iter().rev().collect_vec();

        Self {
            factorial_inv,
            factorial,
        }
    }

    /// 実際のCombinationの計算
    /// 計算量はO(1)
    pub fn combination(&self, n: usize, r: usize) -> ModInt {
        if n < r {
            0.into()
        } else {
            self.factorial[n] * (self.factorial_inv[r] * self.factorial_inv[n - r])
        }
    }
}

pub struct Scanner {
    buf: VecDeque<String>,
}

impl Scanner {
    pub fn new() -> Self {
        Self {
            buf: VecDeque::new(),
        }
    }

    fn scan_line(&mut self) {
        let mut flag = 0;
        while self.buf.is_empty() {
            let mut s = String::new();
            stdin().read_line(&mut s).unwrap();
            let mut iter = s.split_whitespace().peekable();
            if iter.peek().is_none() {
                if flag >= 5 {
                    panic!("There is no input!");
                }
                flag += 1;
                continue;
            }

            for si in iter {
                self.buf.push_back(si.to_string());
            }
        }
    }

    pub fn next<T: FromStr>(&mut self) -> T {
        self.scan_line();
        self.buf
            .pop_front()
            .unwrap()
            .parse()
            .unwrap_or_else(|_| panic!("Couldn't parse!"))
    }

    pub fn next_usize(&mut self) -> usize {
        self.next()
    }

    pub fn next_isize(&mut self) -> isize {
        self.next()
    }

    pub fn next_chars(&mut self) -> Vec<char> {
        self.next::<String>().chars().collect_vec()
    }

    pub fn next_string(&mut self) -> String {
        self.next()
    }

    pub fn fill_vec_line<T: FromStr>(&mut self, v: &mut Vec<T>) {
        for vi in v {
            *vi = self.next();
        }
    }

    pub fn fill_vec<T: FromStr>(&mut self, v: &mut Vec<Vec<T>>) {
        for vi in v {
            for vii in vi {
                *vii = self.next();
            }
        }
    }

    pub fn make_vec_line<T: FromStr + Default + Clone>(&mut self, i: usize) -> Vec<T> {
        let mut v = vec![Default::default(); i];
        self.fill_vec_line(&mut v);
        v
    }

    pub fn make_vec<T: FromStr + Default + Clone>(&mut self, i: usize, j: usize) -> Vec<Vec<T>> {
        let mut v = vec![vec![Default::default(); j]; i];
        self.fill_vec(&mut v);
        v
    }
}


Measured memory_bytes: 2152