#[allow(unused_imports)]
use std::cmp::{max, min, Ordering};
#[allow(unused_imports)]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
#[allow(unused_imports)]
use std::io::{stdin, stdout, BufWriter, StdoutLock, Write};
#[allow(unused_imports)]
use std::iter::FromIterator;
#[allow(unused_macros)]
macro_rules ! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut iter = $ s . split_whitespace ( ) ; let mut next = || { iter . next ( ) . unwrap ( ) } ; input_inner ! { next , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { let stdin = std :: io :: stdin ( ) ; let mut bytes = std :: io :: Read :: bytes ( std :: io :: BufReader :: new ( stdin . lock ( ) ) ) ; let mut next = move || -> String { bytes . by_ref ( ) . map ( | r | r . unwrap ( ) as char ) . skip_while ( | c | c . is_whitespace ( ) ) . take_while ( | c |! c . is_whitespace ( ) ) . collect ( ) } ; input_inner ! { next , $ ( $ r ) * } } ; }
#[allow(unused_macros)]
macro_rules ! input_inner { ( $ next : expr ) => { } ; ( $ next : expr , ) => { } ; ( $ next : expr , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ next , $ t ) ; input_inner ! { $ next $ ( $ r ) * } } ; }
#[allow(unused_macros)]
macro_rules ! read_value { ( $ next : expr , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ next , $ t ) ) ,* ) } ; ( $ next : expr , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ next , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ next : expr , chars ) => { read_value ! ( $ next , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ next : expr , bytes ) => { read_value ! ( $ next , String ) . into_bytes ( ) } ; ( $ next : expr , usize1 ) => { read_value ! ( $ next , usize ) - 1 } ; ( $ next : expr , $ t : ty ) => { $ next ( ) . parse ::<$ t > ( ) . expect ( "Parse error" ) } ; }
#[allow(dead_code)]
pub fn with_bufwriter<F: FnOnce(BufWriter<StdoutLock>) -> ()>(f: F) {
    let out = stdout();
    let writer = BufWriter::new(out.lock());
    f(writer)
}
#[allow(unused_macros)]
macro_rules ! debug { ( $ ( $ a : expr ) ,* ) => { eprintln ! ( concat ! ( $ ( stringify ! ( $ a ) , " = {:?}, " ) ,* ) , $ ( $ a ) ,* ) } ; }
#[allow(dead_code)]
fn main() {
    input!{
        n: usize,
        a: [i64; n],
    }
    let mut can = false;
    for bit in 0..1<<n {
        let mut sum = 0;
        for i in 0..n {
            if bit & (1<<i) != 0 {
                sum += a[i];
            } else {
                sum -= a[i];
            }
        }
        if sum % 360 == 0 {
            can = true;
            break;
        }
    }
    if can {
        println!("YES");
    } else {
        println!("NO");
    }
}


use std::io;
#[allow(unused_imports)]
use std::io::prelude::*;

fn main() {
    let mut n = String::new();
    io::stdin().read_line(&mut n).expect("failed to read input.");
    let n: u8 = n.trim().parse().expect("invalid input");

	let mut angles: Vec<u8> = Vec::new();
	let mut status: bool = false;

    for _i in 0..n {
    	let mut value = String::new();
    	io::stdin().read_line(&mut value).expect("failed to read input.");
		angles.push(value.trim().parse().expect("invalid input"));
	}

    for t in 0..(1 << n) {
        let mut s: i32 = 0;

    	for k in 0..n {
    		let angle = angles[k as usize] as i32;
			if (t & (1 << k)) != 0 {
				s = s + angle ;
			} else {
				s = s - angle;
			}
    	}
        if s % 360 == 0 {
            status = true;
        }
    }

	if status {
		println!("{}", "YES");
	} else {
		println!("{}", "NO");
	}
}


use std::io::stdin;

fn read_line() -> String {
    let mut buf = String::new();
    stdin().read_line(&mut buf).expect("Failed to read a line");
    buf
}

pub fn main() {
    let line = read_line();
    let mut iter = line.trim().split_whitespace().map(|x| x.parse::<i64>().unwrap());
    let w = iter.next().unwrap();
    let h = iter.next().unwrap();
    let mut result: u64 = 1;
    for _ in 0..w + h {
        result *= 2;
        result %= 998244353;
    }
    println!("{}", result);
}


// Try Codeforces
// author: Leonardone @ NEETSDKASU

fn main() {
    let mut stdin = String::new();
    std::io::Read::read_to_string(
        &mut std::io::stdin(),
        &mut stdin).unwrap();
    let mut stdin = stdin.split_whitespace();
    let mut get = || stdin.next().unwrap();
    macro_rules! get {
        ($t:ty) => (get().parse::<$t>().unwrap());
        () => (get!(i64));
    }

    let h = get!(usize);
    let w = get!(usize);
    let p = 998244353;
    let mut ans = 4;
    for i in 1 .. w {
        ans = (ans * 2) % p;
    }
    for j in 1 .. h {
        ans = (ans * 2) % p;
    }
    println!("{}", ans);
}


use std::io;

fn pow_mod(base : u64, mut exp : u64, md : u64) -> u64 {
    if exp == 0 {
        return 1;
    }

    let mut bin : Vec<bool> = Vec::with_capacity(64);
    while exp != 0 {
        bin.push(exp & 1u64 == 1);
        exp >>= 1;
    }
    bin.pop();

    bin.iter().rev().fold(base, |acc, &x| if x { (((acc * acc) % md) * base) % md } else { (acc * acc) % md })
}

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).expect("failed to read input");
    let mut buffer_iter = buffer.split_whitespace();
    let w: u64 = buffer_iter.next().unwrap().parse().unwrap();
    let h: u64 = buffer_iter.next().unwrap().parse().unwrap();

    println!("{}", pow_mod(2, w + h, 998244353));
}


#[allow(unused_macros)]
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        let mut next = || { iter.next().unwrap() };
        input_inner!{next, $($r)*}
    };
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes
                .by_ref()
                .map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

#[allow(unused_macros)]
macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};

    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };

    ($next:expr, mut $var:ident : $t:tt $($r:tt)*) => {
        let mut $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

#[allow(unused_macros)]
macro_rules! read_value {
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };

    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };

    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };

    ($next:expr, usize1) => {
        read_value!($next, usize) - 1
    };

    ($next:expr, $t:ty) => {
        $next().parse::<$t>().expect("Parse error")
    };
}

#[allow(unused_macros)]
macro_rules! debug {
    ($($a:expr),*) => {
        #[cfg(debug_assertions)]
        writeln!(&mut std::io::stderr(), concat!("[DEBUG] ", $(stringify!($a), "={:?} "),*), $($a),*);
    }
}

#[allow(unused_imports)]
use std::cmp::{min, max};
#[allow(unused_imports)]
use std::io::{stdout, stdin, BufWriter, Write};

fn main() {
    let out = std::io::stdout();
    let mut out = BufWriter::new(out.lock());
    macro_rules! puts {
        ($($format:tt)*) => (write!(out,$($format)*).unwrap());
    }

    const MOD: u64 = 998244353;

    input!{
      w: usize,
      h: usize,
    }

    let mut ans = 4;
    for _ in 0..w-1 {
        ans *= 2;
        ans %= MOD;
    }
    for _ in 0..h-1 {
        ans *= 2;
        ans %= MOD;
    }
    puts!("{}\n", ans);
}


//spnauti-rusT
use std::io::*;
use std::str::{self,*};
use std::fmt::Debug;
#[allow(unused_imports)] use std::cmp::Ordering::{self,*};
#[allow(unused_imports)] use std::ops::{self,*};
#[allow(unused_imports)] use std::iter::{self,*};
#[allow(unused_imports)] use std::collections::*;
#[allow(unused_macros)]
macro_rules! m {
    ($c:tt, $x:expr, $y:expr) => {{
        let b = $y; let a = &mut $x;
        if b $c *a { *a = b; true } else { false }
    }};
}
#[allow(unused_macros)]
macro_rules! l {
    ($($v:ident),* = $i:ident.$f:ident $a:tt) => {
        $( let $v = $i.$f$a; )*
    };
    ($($v:ident),*:$t:ty = $i:ident.$f:ident $a:tt) => {
        $( let $v:$t = $i.$f$a; )*
    };
}
struct WordReader<'a> { it : SplitAsciiWhitespace<'a> }
#[allow(dead_code)]
impl<'a> WordReader<'a> {
    fn new<T: Read>(b: &mut String, mut r: T) -> WordReader {
        b.clear();
        r.read_to_string(b).ok();
        WordReader { it: b.split_ascii_whitespace() }
    }
    fn from_stdin(b: &mut String) -> WordReader {
        WordReader::new(b, stdin())
    }
    fn sl(&mut self) ->  &str { self.it.next().unwrap() }
    fn bs(&mut self) -> &[u8] { self.sl().as_bytes()    }
    fn s(&mut self) -> String { String::from(self.sl()) }
    fn i(&mut self) ->    i32 { self.p()                }
    fn f(&mut self) ->    f64 { self.p()                }
    fn u(&mut self) ->  usize { self.p()                }
    fn sk(&mut self, n: usize) { self.it.nth(n - 1); }
    fn ii(&mut self, n: usize) -> impl Iterator<Item=i32> {
        self.ip(n).into_iter()
    }
    fn vi(&mut self, n: usize) -> Vec<i32> {
        self.vp::<i32>(n)
    }
    fn p<T: FromStr>(&mut self) -> T where T::Err: Debug {
        self.sl().parse::<T>().unwrap()
    }
    fn ip<T: FromStr>(&mut self, n: usize) -> impl Iterator<Item=T> where T::Err: Debug {
        self.vp(n).into_iter()
    }
    fn vp<T: FromStr>(&mut self, n: usize) -> Vec<T> where T::Err: Debug {
        (0..n).map(|_| self.p()).collect()
    }
}
//------------------- End rusT

//------------------- Start Field
const P5: i32 = 998244353;
const P6: i64 = P5 as i64;
#[derive(Debug,Clone,Copy)]
struct Field(i32);
#[allow(dead_code)]
impl Field {
    fn new<T: Into<i64>>(a: T) -> Self { Self(Self::cv(a)) }
    fn new_unchecked(a: i32) -> Self { Self(a) }
    fn hi(mut a: i32) -> i32 { if a >= P5 { a -= P5; } a }
    fn lo(mut a: i32) -> i32 { if a < 0 { a += P5; } a }
    fn cv<T: Into<i64>>(a: T) -> i32 { Self::lo((a.into() % P6) as i32) }
}
impl Add for Field { type Output = Self; fn add(self, a: Self) -> Self::Output { Self(Self::hi(self.0 + a.0)) }}
impl Sub for Field { type Output = Self; fn sub(self, a: Self) -> Self::Output { Self(Self::lo(self.0 - a.0)) }}
impl Mul for Field { type Output = Self; fn mul(self, a: Self) -> Self::Output { Self(Self::cv(self.0 as i64 * a.0 as i64)) }}
impl Neg for Field { type Output = Self; fn neg(self) -> Self::Output { Self(Self::lo(-self.0)) }}
impl AddAssign for Field { fn add_assign(&mut self, a: Self) { *self = *self + a; } }
impl SubAssign for Field { fn sub_assign(&mut self, a: Self) { *self = *self - a; } }
impl MulAssign for Field { fn mul_assign(&mut self, a: Self) { *self = *self * a; } }
use std::fmt::{Display, Formatter, Result};
impl Display for Field { fn fmt(&self, f: &mut Formatter) -> Result { write!(f, "{}", self.0) } }
// impl Default for Field { fn default() -> Self { Field(0) }}
impl Default for &Field { fn default() -> Self { &Field(0) }}
impl PartialEq for Field { fn eq(&self, a: &Self) -> bool { self.0 == a.0 } }
impl PartialOrd for Field { fn partial_cmp(&self, a: &Self) -> Option<Ordering> { Some(self.0.cmp(&a.0)) } }
impl Eq for Field {}
impl Ord for Field { fn cmp(&self, a: &Self) -> Ordering { self.0.cmp(&a.0) } }
impl Sum<Self> for Field {
    fn sum<I>(i: I) -> Self where I: Iterator<Item = Self> {
        i.fold(Field(0), |a,b| a + b) } }
impl<'a> Sum<&'a Self> for Field {
    fn sum<I>(i: I) -> Self where I: Iterator<Item = &'a Self> {
        i.fold(Field(0), |a,&b| a + b) } }
impl Product<Self> for Field {
    fn product<I>(i: I) -> Self where I: Iterator<Item = Self> {
        i.fold(Field(1), |a,b| a * b) } }
impl<'a> Product<&'a Self> for Field {
    fn product<I>(i: I) -> Self where I: Iterator<Item = &'a Self> {
        i.fold(Field(1), |a,&b| a * b) }
}
//------------------- End Field

fn main() {
    let mut bin = String::new();
    let mut input = WordReader::from_stdin(&mut bin);

    l!(a,b = input.i());
    let mut sol = Field(1);
    for _ in 0..a+b {
        sol *= Field(2);
    }
    println!("{}", sol);
}


#![allow(unused_imports)]
use std::collections::{HashSet, HashMap};
use std::cmp::{min,max};
use std::io::{self, Write};
use std::str;

struct Scanner<R> {
    reader: R,
    buf_str: Vec<u8>,
    buf_iter: str::SplitAsciiWhitespace<'static>,
}
impl<R: io::BufRead> Scanner<R> {
    fn new(reader: R) -> Self {
        Self { reader, buf_str: Vec::new(), buf_iter: "".split_ascii_whitespace() }
    }
    fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buf_iter.next() {
                return token.parse().ok().expect("Failed parse");
            }
            self.buf_str.clear();
            self.reader.read_until(b'\n', &mut self.buf_str).expect("Failed read");
            self.buf_iter = unsafe {
                let slice = str::from_utf8_unchecked(&self.buf_str);
                std::mem::transmute(slice.split_ascii_whitespace())
            }
        }
    }
}

#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
pub struct Field {
    pub val: i64,
}
impl Field {
    pub const MOD: i64 = 998_244_353; // 2^23 * 7 * 17 + 1

    /// Computes self^exp in O(log(exp)) time
    pub fn pow(mut self, mut exp: u64) -> Self {
        let mut result = Self::from_small(1);
        while exp > 0 {
            if exp % 2 == 1 {
                result = result * self;
            }
            self = self * self;
            exp /= 2;
        }
        result
    }
    /// Computes inverses of 1 to n in O(n) time
    pub fn vec_of_recips(n: i64) -> Vec<Self> {
        let mut recips = vec![Self::from(0), Self::from(1)];
        for i in 2..=n {
            let (md, dv) = (Self::MOD % i, Self::MOD / i);
            recips.push(recips[md as usize] * Self::from_small(-dv));
        }
        recips
    }
    /// Computes self^-1 in O(log(Self::MOD)) time
    pub fn recip(self) -> Self {
        self.pow(Self::MOD as u64 - 2)
    }
    /// Avoids the % operation but requires -Self::MOD <= x < Self::MOD
    fn from_small(s: i64) -> Self {
        let val = if s < 0 { s + Self::MOD } else { s };
        Self { val }
    }
}
impl From<i64> for Field {
    fn from(val: i64) -> Self {
        // Self { val: val.rem_euclid(Self::MOD) }
        Self::from_small(val % Self::MOD)
    }
}
impl std::ops::Mul for Field {
    type Output = Self;
    fn mul(self, other: Self) -> Self {
        Self::from(self.val * other.val)
    }
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    let mut out = io::BufWriter::new(stdout.lock());

    let w = scan.token::<u64>();
    let h = scan.token::<u64>();
    let ans = Field::from(2).pow(w + h);
    writeln!(out, "{}", ans.val).ok();
}


struct Scanner<'a, T: std::io::Read> {
    reader: &'a mut T,
    buffer: [u8; 4096],
    position: usize,
    size: usize
}

impl<'a, T: std::io::Read> Scanner<'a, T> {
    const SPACES: [i32; 4] = [
        ' ' as i32,
        '\n' as i32,
        '\t' as i32,
        '\r' as i32];
    const ZERO: i32 = '0' as i32;
    const NINE: i32 = '9' as i32;
    const NEG: i32 = '-' as i32;

    fn new(reader: &'a mut T) -> Scanner<'a, T> {
        Scanner {
            reader,
            buffer: [0; 4096],
            position: 0,
            size: 0
        }
    }

    fn read_block(&mut self) {
        self.size = self.reader.read(&mut self.buffer).unwrap();
        self.position = 0;
    }

    fn read_char(&mut self) -> i32 {
        if self.position >= self.size {
            self.read_block();
            if self.position >= self.size {
                return -1;
            }
        }

        let ch = self.buffer[self.position];
        self.position += 1;

        ch as i32
    }

    fn read_int(&mut self) -> Option<i32> {
        let mut ch = self.read_char();
        while ch != -1 && Scanner::<T>::SPACES.contains(&ch) {
            ch = self.read_char();
        }

        if ch == -1 {
            return None;
        }

        let mut negative = false;
        if ch == Scanner::<T>::NEG {
            negative = true;
            ch = self.read_char();
        }

        let mut result = 0;
        while ch != -1 && ch >= Scanner::<T>::ZERO && ch <= Scanner::<T>::NINE {
            result = result * 10 + ch - Scanner::<T>::ZERO;
            ch = self.read_char();
        }

        Some(if negative {
            -result
        } else {
            result
        })
    }

    fn read_str(&mut self) -> String {
        let mut ch = self.read_char();
        while ch != -1 && Scanner::<T>::SPACES.contains(&ch) {
            ch = self.read_char();
        }

        let mut s = String::new();
        while !Scanner::<T>::SPACES.contains(&ch) {
            s.push(std::char::from_u32(ch as u32).unwrap());
            ch = self.read_char();
        }

        return s;
    }
}

const MOD: i64 = 998244353i64;

fn main() {
    let mut stdin = std::io::stdin();
    let mut reader = Scanner::new(&mut stdin);

    let w = reader.read_int().unwrap();
    let h = reader.read_int().unwrap();

    // dp[i][j] = dp[i][j - 1] * 2 = dp[i - 1][j] * 2
    let mut dp = vec![vec![0i64; (w + 1) as usize]; (h + 1) as usize];
    dp[1][1] = 4;

    for j in 2..=w as usize {
        dp[1][j] = dp[1][j - 1] * 2 % MOD;
    }
    for i in 2..=h as usize {
        dp[i][1] = dp[i - 1][1] * 2 % MOD;
    }

    for i in 2..=h as usize {
        for j in 2..=w as usize {
            dp[i][j] = dp[i][j - 1] * 2 % MOD;
        }
    }

    println!("{}", dp[h as usize][w as usize]);
}


use std::io;
use std::io::prelude::*;

fn main() {
  let l1 = read_line_iter(); //Se lee cada una de las lineas del tablero
  let l2 = read_line_iter();
  let l3 = read_line_iter();
  let l4 = read_line_iter();
  let l5 = read_line_iter();
  let l6 = read_line_iter();
  let l7 = read_line_iter();
  let l8 = read_line_iter();

  let L1 = l1.as_bytes(); //Se convierten para poder leerse letra a letra
  let L2 = l2.as_bytes();
  let L3 = l3.as_bytes();
  let L4 = l4.as_bytes();
  let L5 = l5.as_bytes();
  let L6 = l6.as_bytes();
  let L7 = l7.as_bytes();
  let L8 = l8.as_bytes();

  let mut white = 0; //Puntaje total de cada jugador
  let mut black = 0;

  for i in 0..8{ //Recorre la linea letra a letra
    match L1[i] as char{ //Asigna el puntaje correspondiente a cada jugador
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{ //Se repite lo mismo que en lo anterior para la siguiente linea
    match L2[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L3[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L4[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L5[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L6[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L7[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L8[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  let advantage = white-black; //Calcula la diferencia de puntaje
  match advantage{
    1..=576 => println!("White"),//Si es positiva va ganando blanco
    -576..=-1 => println!("Black"), //Si es negativa va ganando negro
    _ => println!("Draw"), //En otro caso se considera empate
  }

}

fn read_line_iter() -> String { //Funcion para recibir inputs y convertirlos en strings (Fuente: https://subscription.packtpub.com/book/application_development/9781788623926/1/ch01lvl1sec23/reading-from-stdin)
  let stdin = io::stdin();
  // Read one line of input iterator-style
  let input = stdin.lock().lines().next();
  input
    .expect("No lines in buffer")
    .expect("Failed to read line")
    .trim()
    .to_string()
}


use std::io;

fn calcular_linea(line: String, tipo: i32) -> i32{
    let mut total = 0;
    for c in line.chars(){
        if tipo == 0 {
            match c{
                'Q' => total += 9,
                'R' => total += 5,
                'B' => total += 3,
                'N' => total += 3,
                'P' => total += 1,
                _ => (),
            };
        }
        else {
            match c{
                'q' => total += 9,
                'r' => total += 5,
                'b' => total += 3,
                'n' => total += 3,
                'p' => total += 1,
                _ => (),
            };
        }
    }
    total
}

fn main() {
    let mut total_black = 0;
    let mut total_white = 0;

    for i in 0..8{
        let mut input = String::new();
        io::stdin().read_line(&mut input);
        let mut input2 = input.clone();
        total_white += calcular_linea(input, 0);
        total_black += calcular_linea(input2, 1);
    }

    if total_black > total_white {
        println!("Black");
    }
    else if total_black == total_white {
        println!("Draw");
    }
    else {
        println!("White");
    }
}


fn add_from_input(input: String) -> (i32, i32) {
    let mut w :i32 = 0;
    let mut b :i32 = 0;
    for c in input.chars() {
        match c {
            'Q' => w += 9,
            'R' => w += 5,
            'B' | 'N' => w += 3,
            'P' => w += 1,
            'q' => b += 9,
            'r' => b += 5,
            'b' | 'n' => b += 3,
            'p' => b += 1,
            _ => (),
        }
    }
    (w, b)
}

fn main(){
    let mut input = String::new();
    for _t in 0..8 {
        std::io::stdin().read_line(&mut input).unwrap();
    }
    let w_b = add_from_input((*input).to_string());
    if w_b.0 > w_b.1 {
        println!("White");
    } else if w_b.0 < w_b.1 {
        println!("Black");
    } else {
        println!("Draw");
    }
}


use std::io;

fn board_calc(mut sc: i32, piece: char) -> i32 {
	match piece {
	    'Q' => sc += 9,
	    'q' => sc -= 9,
	    'R' => sc += 5,
	    'r' => sc -= 5,
	    'B' | 'N' => sc += 3,
	    'b' | 'n' => sc -= 3,
	    'P' => sc += 1,
	    'p' => sc -= 1,
	    _ => sc += 0
	};
	sc
}

fn main() {
    let mut inputnum = 0;
	let mut board = String::new();
	while inputnum < 8 {
	    let mut input = String::new();
	    io::stdin().read_line(&mut input).unwrap();
	    board.push_str(&input);
	    inputnum += 1;
	}

    let mut score = 0;
	for cell in board.chars() {
	    score = board_calc(score, cell);
	}

	let winner = match score {
	    1..=576 => "White",
	    0 => "Draw",
	    _ => "Black"
	};

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


fn contar_negras (vector_c: &Vec<char>) -> i32 {
    let mut negras: i32 = 0;

    for caracter in vector_c{
        match caracter{
            'q' => negras +=9,
            'r' => negras +=5,
            'b' => negras +=3,
            'n' => negras +=3,
            'p' => negras +=1,
            _ => negras +=0,
        }
    }
    negras
}

fn contar_blancas (vector_c: &Vec<char>) -> i32 {
    let mut blancas: i32 = 0;

    for caracter in vector_c{
        match caracter{
            'Q' => blancas +=9,
            'R' => blancas +=5,
            'B' => blancas +=3,
            'N' => blancas +=3,
            'P' => blancas +=1,
            _ => blancas +=0,
        }
    }
    blancas
}

fn main() {
    use std::io::{stdin};
    let mut blanco :i32 = 0;
    let mut negro :i32 = 0;
    let mut s=String::new();
    for _ in 0..8{
        stdin().read_line(&mut s).expect("Error");
        let char_vec: Vec<char> = s.chars().collect();
        negro = contar_negras(&char_vec);
        blanco = contar_blancas(&char_vec);
    }
    if blanco > negro {
        println!("White");
    } else if blanco == negro{
        println!("Draw");
    } else {
        println!("Black")
    }
    //println!("{}, {}",negro, blanco);
}


use std::io;
use std::io::prelude::*;

fn main() {
  let l1 = read_line_iter();
  let l2 = read_line_iter();
  let l3 = read_line_iter();
  let l4 = read_line_iter();
  let l5 = read_line_iter();
  let l6 = read_line_iter();
  let l7 = read_line_iter();
  let l8 = read_line_iter();

  let L1 = l1.as_bytes();
  let L2 = l2.as_bytes();
  let L3 = l3.as_bytes();
  let L4 = l4.as_bytes();
  let L5 = l5.as_bytes();
  let L6 = l6.as_bytes();
  let L7 = l7.as_bytes();
  let L8 = l8.as_bytes();

  let mut white = 0;
  let mut black = 0;

  //println!(
  //  "L1:{},L2:{},L3:{},L4:{},L5:{},L6:{},L7:{},L8:{}",
  //  l1,l2,l3,l4,l5,l6,l7,l8
  //);
  for i in 0..8{
    match L1[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L2[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L3[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L4[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L5[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L6[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L7[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  for i in 0..8{
    match L8[i] as char{
      'p' => black += 1,
      'n' => black += 3,
      'b' => black += 3,
      'r' => black += 5,
      'q' => black += 9,
      'P' => white += 1,
      'N' => white += 3,
      'B' => white += 3,
      'R' => white += 5,
      'Q' => white += 9,
      _ => (),
    }
  }
  let advantage = white-black;
  match advantage{
    1..=576 => println!("White"),
    -576..=-1 => println!("Black"),
    _ => println!("Draw"),
  }

}

fn read_line_iter() -> String {
  let stdin = io::stdin();
  // Read one line of input iterator-style
  let input = stdin.lock().lines().next();
  input
    .expect("No lines in buffer")
    .expect("Failed to read line")
    .trim()
    .to_string()
}


fn main(){
	let mut puntos = 0;
	for _ in 0..8 {
		let mut input = String::new();
		std::io::stdin().read_line(&mut input).unwrap();
		puntos+=getPuntos(input);
	}
	if puntos > 0 {
		println!("White");
	}
	else if puntos < 0 {
		println!("Black");
	}
	else {
		println!("Draw");
	}
}

fn getPuntos(input :String) -> i32{
	let mut white = 0;
	let mut black = 0;
	for letra in input.chars(){
		match letra {
			'Q' => white+=9,
			'q' => black+=9,
			'R' => white+=5,
			'r' => black+=5,
			'B' | 'N' => white+=3,
			'b' | 'n' => black+=3,
			'P' => white+=1,
			'p' => black+=1,
			_ => {},
		}
	}
	return white-black
}


#[allow(unused_imports)]
use std::cmp::{max,min};
#[allow(unused_imports)]
use std::collections::HashMap;

#[allow(unused_macros)]
macro_rules! readln {
    () => {{
        use std::io;

        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim().to_string()
    }};
    ( $t:ty ) => {{
        let input = readln!();
        input.parse::<$t>().unwrap()
    }};
    ( $( $t:ty ),+ ) => {{
        let input = readln!();
        let mut input = input.split_whitespace();
        (
            $(
                input.next().unwrap().parse::<$t>().unwrap(),
            )+
        )
    }}
}

#[allow(unused_macros)]
macro_rules! readvec {
    ( $t:ty ) => {{
        let input = readln!();
        let mut input = input.split_whitespace();
        let mut result = Vec::new();
        for elem in input {
            result.push(elem.parse::<$t>().unwrap());
        }
        result
    }}
}

fn main() {
    let mut weights : HashMap<String,i32> = HashMap::new();
    weights.insert(String::from("q"),9);
    weights.insert(String::from("r"),5);
    weights.insert(String::from("b"),3);
    weights.insert(String::from("n"),3);
    weights.insert(String::from("p"),1);
    weights.insert(String::from("k"),0);
    let mut a = String::new();
    for _ in 0..8 {
        a += &readln!();
    }
    let w :i32 = a.chars().filter(|c|c.is_uppercase()).map(|x|x.to_lowercase()).map(|x| {
        let sx : String = x.to_string();
        weights.get(&sx).unwrap()
    }).sum();
    let b :i32 = a.chars().filter(|c|c.is_lowercase()).map(|x|{
        let sx : String = x.to_string();
        weights.get(&sx).unwrap()
    }).sum();
    println!("{}",if w>b { "White" } else if w<b { "Black" } else { "Draw" });
}


// use wyf_lib::*;

fn calc(x: i64) -> i64 {
    if x < 1200 {
        1200
    } else if x < 1400 {
        1400
    } else if x < 1600 {
        1600
    } else if x < 1900 {
        1900
    } else if x < 2100 {
        2100
    } else if x < 2300 {
        2300
    } else if x < 2400 {
        2400
    } else if x < 2600 {
        2600
    } else {
        3000
    }
}

fn main() {
    let x: i64 = read();
    // (x + 1).println();
    calc(x).println();
}

use std::error;
use std::fmt;
use std::str::FromStr;

#[non_exhaustive]
#[derive(Debug, PartialEq)]
pub enum Error {
    MissingMatch,
    MissingClosingBrace,
    UnexpectedValue(u8, Option<u8>),
    InvalidUtf8(Vec<u8>),
    PartialUtf8(usize, Vec<u8>),
    Parse(String, &'static str),
}

impl error::Error for Error {}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use crate::Error::*;
        use std::str::from_utf8;

        match *self {
            InvalidUtf8(ref raw) => write!(f, "input was not valid utf8: {:?}", raw),
            Parse(ref s, arg) => write!(f, "could not parse {} as target type of {}", s, arg),
            UnexpectedValue(exp, act) => write!(
                f,
                "found value {:?} not matching the pattern value {}",
                act.map(|b| b as char),
                exp as char
            ),
            PartialUtf8(n, ref raw) => write!(
                f,
                "input was only partially valid utf8: \"{}\" followed by {:?}",
                from_utf8(&raw[..n]).unwrap(),
                &raw[n..]
            ),
            MissingMatch => write!(f, "Bad read! format string: did not contain {{}}"),
            MissingClosingBrace => write!(
                f,
                "found single open curly brace at the end of the format string"
            ),
        }
    }
}

pub fn match_next(expected: u8, iter: &mut dyn Iterator<Item = u8>) -> Result<(), Error> {
    let next = iter.next();
    if next != Some(expected) {
        return Err(Error::UnexpectedValue(expected, next));
    }
    Ok(())
}

pub fn parse_capture<T>(
    name: &'static str,
    next: Option<u8>,
    iter: &mut dyn Iterator<Item = u8>,
) -> Result<T, Error>
where
    T: FromStr,
    <T as FromStr>::Err: ::std::fmt::Debug,
{
    static WHITESPACES: &[u8] = b"\t\r\n ";
    let raw: Vec<u8> = match next {
        Some(c) => iter.take_while(|&ch| ch != c).collect(),
        None => iter
            .skip_while(|ch| WHITESPACES.contains(ch))
            .take_while(|ch| !WHITESPACES.contains(ch))
            .collect(),
    };
    match String::from_utf8(raw) {
        Ok(s) => FromStr::from_str(&s).map_err(|_| Error::Parse(s, name)),
        Err(e) => {
            let n = e.utf8_error().valid_up_to();
            let raw = e.into_bytes();
            if n == 0 {
                Err(Error::InvalidUtf8(raw))
            } else {
                Err(Error::PartialUtf8(n, raw))
            }
        }
    }
}

#[macro_export]
macro_rules! try_read(
    () => { $crate::try_read!("{}") };
    ($text:expr) => {{
        (|| -> std::result::Result<_, $crate::Error> {
            let __try_read_var__;
            $crate::try_scan!($text, __try_read_var__);
            Ok(__try_read_var__)
        })()
    }};
    ($text:expr, $input:expr) => {{
        (|| -> std::result::Result<_, $crate::Error> {
            let __try_read_var__;
            $crate::try_scan!($input => $text, __try_read_var__);
            Ok(__try_read_var__)
        })()
    }};
);

#[macro_export]
macro_rules! try_scan(
    ($pattern:expr, $($arg:expr),*) => {
        use ::std::io::Read;
        $crate::try_scan!(::std::io::stdin().bytes().map(std::result::Result::unwrap) => $pattern, $($arg),*);
    };
    ($input:expr => $pattern:expr, $($arg:expr),*) => {{
        $crate::try_scan!(@impl question_mark; $input => $pattern, $($arg),*)
    }};
    (@question_mark: $($e:tt)+) => {{
        ($($e)+)?
    }};
    (@unwrap: $($e:tt)+) => {{
        ($($e)+).unwrap()
    }};
    (@impl $action:tt; $input:expr => $pattern:expr, $($arg:expr),*) => {{
        #![allow(clippy::try_err)]
        use $crate::{Error, match_next, parse_capture};

        // typesafe macros :)
        let pattern: &'static str = $pattern;
        let stdin: &mut dyn Iterator<Item = u8> = &mut ($input);

        let mut pattern = pattern.bytes();

        $(
            $arg = loop {
                match $crate::try_scan!(@$action: pattern.next().ok_or(Error::MissingMatch)) {
                    b'{' => match $crate::try_scan!(@$action: pattern.next().ok_or(Error::MissingClosingBrace)) {
                        b'{' => $crate::try_scan!(@$action: match_next(b'{', stdin)),
                        b'}' => break $crate::try_scan!(@$action: parse_capture(stringify!($arg), pattern.next(), stdin)),
                        _ => return $crate::try_scan!(@$action: Err(Error::MissingClosingBrace)),
                    },
                    c => $crate::try_scan!(@$action: match_next(c, stdin)),
                }
            };
        )*

        for c in pattern {
            $crate::try_scan!(@$action: match_next(c, stdin))
        }

        format_args!($pattern, $($arg),*);
    }};
);

#[macro_export]
macro_rules! read(
    ($($arg:tt)*) => {
        $crate::try_read!($($arg)*).unwrap()
    };
);

#[macro_export]
macro_rules! scan(
    ($text:expr, $($arg:expr),*) => {
        {
            use ::std::io::Read;
            $crate::scan!(::std::io::stdin().bytes().map(std::result::Result::unwrap) => $text, $($arg),*);
        }
    };
    ($input:expr => $pattern:expr, $($arg:expr),*) => {{
        $crate::try_scan!(@impl unwrap; $input => $pattern, $($arg),*)
    }};
);
use std::marker::PhantomData;
use std::ops;

// use text_io::read;

/*** READ and WRITE ***/

pub trait Readable {
    fn read() -> Self;
}

pub trait Printable {
    fn print(self: &Self);
    fn println(self: &Self) {
        self.print();
        println!();
    }
}

macro_rules! impl_rp_simple {
    ($($t:ident), +) => {
        $(
            impl Readable for $t {
                fn read() -> Self {
                    read!()
                }
            }

            impl Printable for $t {
                fn print(self: &Self) {
                    print!("{self} ");
                }
            }
        )+
    };
}

impl_rp_simple!(
    String, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64, char
);

macro_rules! impl_rp_tuple {
    () => {};
    ($t0:ident, $($t:ident,) *) => {
        impl<$t0: Readable, $($t: Readable), *> Readable for ($t0, $($t,)*) {
            fn read() -> Self {
                (read(), $(read::<$t>(),)*)
            }
        }

        impl<$t0: Printable, $($t: Printable), *> Printable for ($t0, $($t,)*) {
            fn print(self: &Self) {
                #[allow(non_snake_case)]
                let (ref $t0, $(ref $t,)*) = &self;
                $t0.print();
                $(
                    $t.print();
                )*
            }
        }

        impl_rp_tuple!{$($t,) *}
    };
}

impl<T: Printable> Printable for Vec<T> {
    fn print(self: &Self) {
        for x in self {
            x.print();
        }
    }
}

impl<T: Printable> Printable for [T] {
    fn print(self: &Self) {
        for x in self {
            x.print();
        }
    }
}

impl_rp_tuple! {T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,}

pub fn read<T: Readable>() -> T {
    T::read()
}

pub fn readv<T: Readable>(size: usize) -> Vec<T> {
    let mut res = Vec::with_capacity(size);
    for _ in 0..size {
        res.push(read());
    }
    res
}

pub fn readb() -> Vec<u8> {
    let s: String = read!();
    s.as_bytes().into_iter().cloned().collect()
}

/*** RECURSIVE LAMBDA ***/

macro_rules! recursive_fn {
    () => {};
    ($name0:ident $trait0:ident $_:ident $__:ident, $($name:ident $trait:ident $Arg:ident $arg:ident,)*) => {
        pub trait $trait0<$($Arg,)* Output> {
            fn call(&mut self, $($arg: $Arg,)*) -> Output;
        }

        pub struct $name0<F, $($Arg,)* Output>
        where
            F: FnMut(&mut dyn $trait0<$($Arg,)* Output>, $($Arg,)*) -> Output,
        {
            f: std::cell::UnsafeCell<F>,
            $(
                $arg: PhantomData<$Arg>,
            )*
            phantom_output: PhantomData<Output>,
        }

        impl<F, $($Arg,)* Output> $name0<F, $($Arg,)* Output>
        where
            F: FnMut(&mut dyn $trait0<$($Arg,)* Output>, $($Arg,)*) -> Output,
        {
            pub fn new(f: F) -> Self {
                Self {
                    f: std::cell::UnsafeCell::new(f),
                    $(
                        $arg: PhantomData,
                    )*
                    phantom_output: PhantomData,
                }
            }
        }

        impl<F, $($Arg,)* Output> $trait0<$($Arg,)* Output> for $name0<F, $($Arg,)* Output>
        where
            F: FnMut(&mut dyn $trait0<$($Arg,)* Output>, $($Arg,)*) -> Output,
        {
            fn call(&mut self, $($arg: $Arg,)*) -> Output {
                unsafe { (&mut *self.f.get())(self, $($arg,)*) }
            }
        }

        recursive_fn!{$($name $trait $Arg $arg,)*}
    };
}

recursive_fn! {
    RecursiveFn11 Callable11 Arg11 arg11,
    RecursiveFn10 Callable10 Arg10 arg10,
    RecursiveFn9 Callable9 Arg9 arg9,
    RecursiveFn8 Callable8 Arg8 arg8,
    RecursiveFn7 Callable7 Arg7 arg7,
    RecursiveFn6 Callable6 Arg6 arg6,
    RecursiveFn5 Callable5 Arg5 arg5,
    RecursiveFn4 Callable4 Arg4 arg4,
    RecursiveFn3 Callable3 Arg3 arg3,
    RecursiveFn2 Callable2 Arg2 arg2,
    RecursiveFn1 Callable1 Arg1 arg1,
    RecursiveFn0 Callable0 Arg0 arg0,
}

/*** MOD ***/

// gcd, x, y
pub fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) {
    if a == 0 {
        (b, 0, 1)
    } else {
        let (g, y, mut x) = extended_gcd(b % a, a);
        x -= (b / a) * y;
        (g, x, y)
    }
}

pub trait HasConstVal {
    const VAL: i64;
}

// const of V has to be prime
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct ModBase<M: HasConstVal + Copy> {
    v: i64,
    phantom: PhantomData<M>,
}

impl<M: HasConstVal + Copy> ModBase<M> {
    pub fn new(mut v: i64) -> Self {
        v %= M::VAL;
        if v < 0 {
            v = v + M::VAL;
        }
        Self {
            v,
            phantom: PhantomData,
        }
    }

    pub fn inv(&self) -> Self {
        let (_, x, _) = extended_gcd(self.v, M::VAL);
        Self::new(x)
    }

    pub fn pow(&self, n: usize) -> Self {
        let v = self.v;
        let mut res = Self::new(1);
        for _ in 0..n {
            res *= v;
        }
        res
    }
}

impl<M: HasConstVal + Copy> ops::Add<i64> for ModBase<M> {
    type Output = Self;

    fn add(self, rhs: i64) -> Self {
        Self::new(self.v + rhs)
    }
}

impl<M: HasConstVal + Copy> ops::Add for ModBase<M> {
    type Output = Self;

    fn add(self, rhs: Self) -> Self {
        Self::new(self.v + rhs.v)
    }
}

impl<M: HasConstVal + Copy> ops::AddAssign<i64> for ModBase<M> {
    fn add_assign(&mut self, rhs: i64) {
        self.v = (self.v + rhs) % M::VAL;
    }
}

impl<M: HasConstVal + Copy> ops::AddAssign for ModBase<M> {
    fn add_assign(&mut self, rhs: Self) {
        self.v = (self.v + rhs.v) % M::VAL;
    }
}

impl<M: HasConstVal + Copy> ops::Sub<i64> for ModBase<M> {
    type Output = Self;

    fn sub(self, rhs: i64) -> Self {
        Self::new(self.v - rhs)
    }
}

impl<M: HasConstVal + Copy> ops::Sub for ModBase<M> {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self {
        Self::new(self.v - rhs.v)
    }
}

impl<M: HasConstVal + Copy> ops::SubAssign<i64> for ModBase<M> {
    fn sub_assign(&mut self, rhs: i64) {
        self.v = (self.v - rhs) % M::VAL;
    }
}

impl<M: HasConstVal + Copy> ops::SubAssign for ModBase<M> {
    fn sub_assign(&mut self, rhs: Self) {
        self.v = (self.v - rhs.v) % M::VAL;
    }
}

impl<M: HasConstVal + Copy> ops::Mul<i64> for ModBase<M> {
    type Output = Self;

    fn mul(self, rhs: i64) -> Self::Output {
        Self::new(self.v * rhs)
    }
}

impl<M: HasConstVal + Copy> ops::Mul for ModBase<M> {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self::Output {
        Self::new(self.v * rhs.v)
    }
}

impl<M: HasConstVal + Copy> ops::MulAssign<i64> for ModBase<M> {
    fn mul_assign(&mut self, rhs: i64) {
        self.v = self.v * rhs % M::VAL;
    }
}

impl<M: HasConstVal + Copy> ops::MulAssign for ModBase<M> {
    fn mul_assign(&mut self, rhs: Self) {
        self.v = self.v * rhs.v % M::VAL;
    }
}

impl<M: HasConstVal + Copy> ops::Div<i64> for ModBase<M> {
    type Output = Self;

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

impl<M: HasConstVal + Copy> ops::Div for ModBase<M> {
    type Output = Self;

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

impl<M: HasConstVal + Copy> ops::DivAssign<i64> for ModBase<M> {
    fn div_assign(&mut self, rhs: i64) {
        self.v = (Self::new(self.v) / rhs).v;
    }
}

impl<M: HasConstVal + Copy> ops::DivAssign for ModBase<M> {
    fn div_assign(&mut self, rhs: Self) {
        self.v = (Self::new(self.v) / rhs).v;
    }
}

impl<M: HasConstVal + Copy> ops::Neg for ModBase<M> {
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self::new(-self.v)
    }
}

impl<M: HasConstVal + Copy> ops::Deref for ModBase<M> {
    type Target = i64;

    fn deref(&self) -> &Self::Target {
        &self.v
    }
}

#[macro_export]
macro_rules! Mod {
    ($val: expr) => {
        Mod!(Mod, ModV, $val);
    };
    ($name: ident, $v_name: ident, $val: expr) => {
        #[derive(Copy, Clone, Eq, PartialEq)]
        pub struct $v_name {}

        impl crate::HasConstVal for $v_name {
            const VAL: i64 = $val as i64;
        }

        type $name = ModBase<$v_name>;
    };
}


use std::io;
use std::str;

pub struct Scanner<R> {
    reader: R,
    buffer: Vec<String>,
}

impl<R: io::BufRead> Scanner<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            buffer: vec![],
        }
    }

    pub fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            self.reader.read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

fn gcd(a: u64, b: u64) -> u64 {
    if b == 0 {
        a
    } else {
        gcd(b, a % b)
    }
}

fn solve<R: io::BufRead, W: io::Write>(scan: &mut Scanner<R>, out: &mut W) {
    let n: u64 = scan.token();
    let ans: u64;
    if n == 1 {
        ans = 1;
    } else if n == 2 {
        ans = 2;
    } else if n == 3 {
        ans = 6;
    } else if n % 2 == 0 {
        let a = n - 1;
        let b = n - 2;
        let c = n - 3;
        ans = a * b * c;
    } else {
        let a = n;
        let b = n - 1;
        let c = n - 2;
        ans = a * b * c;
    }

    // pick n and n - 1, find another number coprime to both
    let mut ans2 = n * (n - 1);
    for p in (1..(n + 1)).rev() {
        if gcd(n, p) == 1 && gcd(n - 1, p) == 1 {
            ans2 *= p;
            break;
        }
    }

    writeln!(out, "{}", ans.max(ans2)).ok();
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    let mut out = io::BufWriter::new(stdout.lock());
    solve(&mut scan, &mut out);
}


#[doc = " https://github.com/hatoo/competitive-rust-snippets"]
#[allow(unused_imports)]
use std::cmp::{max, min, Ordering};
#[allow(unused_imports)]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
#[allow(unused_imports)]
use std::iter::FromIterator;
#[macro_export]
macro_rules ! chmax { ( $ x : expr , $ ( $ v : expr ) ,+ ) => { $ ( $ x = std :: cmp :: max ( $ x ,$ v ) ; ) + } ; }
#[macro_export]
macro_rules ! chmin { ( $ x : expr , $ ( $ v : expr ) ,+ ) => { $ ( $ x = std :: cmp :: min ( $ x ,$ v ) ; ) + } ; }
#[macro_export]
macro_rules ! max { ( $ x : expr ) => ( $ x ) ; ( $ x : expr , $ ( $ xs : expr ) ,+ ) => { std :: cmp :: max ( $ x , max ! ( $ ( $ xs ) ,+ ) ) } ; }
#[macro_export]
macro_rules ! min { ( $ x : expr ) => ( $ x ) ; ( $ x : expr , $ ( $ xs : expr ) ,+ ) => { std :: cmp :: min ( $ x , min ! ( $ ( $ xs ) ,+ ) ) } ; }
#[macro_export]
macro_rules ! dvec { ( $ t : expr ; $ len : expr ) => { vec ! [ $ t ; $ len ] } ; ( $ t : expr ; $ len : expr , $ ( $ rest : expr ) ,* ) => { vec ! [ dvec ! ( $ t ; $ ( $ rest ) ,* ) ; $ len ] } ; }
#[macro_export]
macro_rules ! cfor { ( ; $ ( $ rest : tt ) * ) => { cfor ! ( ( ) ; $ ( $ rest ) * ) } ; ( $ ( $ init : stmt ) ,+; ; $ ( $ rest : tt ) * ) => { cfor ! ( $ ( $ init ) ,+; ! false ; $ ( $ rest ) * ) } ; ( $ ( $ init : stmt ) ,+; $ cond : expr ; ; $ body : block ) => { cfor ! { $ ( $ init ) ,+; $ cond ; ( ) ; $ body } } ; ( $ ( $ init : stmt ) ,+; $ cond : expr ; $ ( $ step : expr ) ,+; $ body : block ) => { { $ ( $ init ; ) + while $ cond { let mut _first = true ; let mut _continue = false ; loop { if ! _first { _continue = true ; break } _first = false ; $ body } if ! _continue { break } $ ( $ step ; ) + } } } ; }
#[doc = " main"]
#[allow(unused_imports)]
use std::io::{stdin, stdout, BufWriter, Write};
#[macro_export]
macro_rules ! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut parser = Parser :: from_str ( $ s ) ; input_inner ! { parser , $ ( $ r ) * } } ; ( parser = $ parser : ident , $ ( $ r : tt ) * ) => { input_inner ! { $ parser , $ ( $ r ) * } } ; ( new_stdin_parser = $ parser : ident , $ ( $ r : tt ) * ) => { let stdin = std :: io :: stdin ( ) ; let reader = std :: io :: BufReader :: new ( stdin . lock ( ) ) ; let mut $ parser = Parser :: new ( reader ) ; input_inner ! { $ parser , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { input ! { new_stdin_parser = parser , $ ( $ r ) * } } ; }
#[macro_export]
macro_rules ! input_inner { ( $ parser : ident ) => { } ; ( $ parser : ident , ) => { } ; ( $ parser : ident , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ parser , $ t ) ; input_inner ! { $ parser $ ( $ r ) * } } ; }
#[macro_export]
macro_rules ! read_value { ( $ parser : ident , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ parser , $ t ) ) ,* ) } ; ( $ parser : ident , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ parser , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ parser : ident , chars ) => { read_value ! ( $ parser , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ parser : ident , usize1 ) => { read_value ! ( $ parser , usize ) - 1 } ; ( $ parser : ident , $ t : ty ) => { $ parser . next ::<$ t > ( ) . expect ( "Parse error" ) } ; }
use std::io;
use std::io::BufRead;
use std::str;
pub struct Parser<R> {
    reader: R,
    buf: Vec<u8>,
    pos: usize,
}
impl Parser<io::Empty> {
    pub fn from_str(s: &str) -> Parser<io::Empty> {
        Parser {
            reader: io::empty(),
            buf: s.as_bytes().to_vec(),
            pos: 0,
        }
    }
}
impl<R: BufRead> Parser<R> {
    pub fn new(reader: R) -> Parser<R> {
        Parser {
            reader: reader,
            buf: vec![],
            pos: 0,
        }
    }
    pub fn update_buf(&mut self) {
        self.buf.clear();
        self.pos = 0;
        loop {
            let (len, complete) = {
                let buf2 = self.reader.fill_buf().unwrap();
                self.buf.extend_from_slice(buf2);
                let len = buf2.len();
                if len == 0 {
                    break;
                }
                (len, buf2[len - 1] <= 0x20)
            };
            self.reader.consume(len);
            if complete {
                break;
            }
        }
    }
    pub fn next<T: str::FromStr>(&mut self) -> Result<T, T::Err> {
        loop {
            let mut begin = self.pos;
            while begin < self.buf.len() && (self.buf[begin] <= 0x20) {
                begin += 1;
            }
            let mut end = begin;
            while end < self.buf.len() && (self.buf[end] > 0x20) {
                end += 1;
            }
            if begin != self.buf.len() {
                self.pos = end;
                return str::from_utf8(&self.buf[begin..end]).unwrap().parse::<T>();
            } else {
                self.update_buf();
            }
        }
    }
}
#[allow(unused_macros)]
macro_rules ! debug { ( $ ( $ a : expr ) ,* ) => { eprintln ! ( concat ! ( $ ( stringify ! ( $ a ) , " = {:?}, " ) ,* ) , $ ( $ a ) ,* ) ; } }
#[doc = " https://github.com/hatoo/competitive-rust-snippets"]
const BIG_STACK_SIZE: bool = true;
#[allow(dead_code)]
fn main() {
    use std::thread;
    if BIG_STACK_SIZE {
        thread::Builder::new()
            .stack_size(32 * 1024 * 1024)
            .name("solve".into())
            .spawn(solve)
            .unwrap()
            .join()
            .unwrap();
    } else {
        solve();
    }
}
fn solve() {
    let out = stdout();
    let mut out = BufWriter::new(out.lock());
    input!{
        n: i64,
    }
    let mut tot = 0;
    let mut n = n;
    while n%2 == 1 {
        let pd = prime_decomposition(n);
        let mut primes = vec![];
        for k in pd.keys() {
            primes.push(k);
        }
        primes.sort();
        let minp = primes[0];
        n -= minp;
        tot += 1;
    }
    tot += n/2;
    writeln!(out,"{}",tot);
}
#[doc = "O(root(N))"]
fn prime_decomposition(n: i64) -> std::collections::HashMap<i64, i64> {
    fn root_int(n: i64) -> i64 {
        let mut d = 1;
        while d * d <= n {
            d += 1;
        }
        d - 1
    }
    let mut n = n;
    let mut m = std::collections::HashMap::new();
    for i in 2..root_int(n) + 1 {
        while n % i == 0 {
            if !m.contains_key(&i) {
                m.insert(i, 0);
            }
            *m.get_mut(&i).unwrap() += 1;
            n /= i;
        }
    }
    if n != 1 {
        m.insert(n, 1);
    }
    m
}


use std::io;

macro_rules! readln {
    () => {{
        use std::io;
        let mut buf = String::new();
        io::stdin().read_line(&mut buf).unwrap();
        buf.trim().to_string()
    }};
    ( $t:ty ) => {{
        let input = readln!();
        input.parse::<$t>().unwrap()
    }};
    ( $( $t:ty ),+ ) => {{
        let input = readln!();
        let mut input = input.split_whitespace();
        (
            $(
                input.next().unwrap().parse::<$t>().unwrap(),
            )+
        )
    }}
}

fn main() {
    let num = readln!(i64);

    println!("{}", if num % 2 != 0 {
        let mut div = 3;
        let end = (num as f64).sqrt() as i64 + 1;
        loop {
            if num % div == 0 {
                break;
            }
            if div >= end {
                div = num;
                break;
            }
            div += 1;
        }
        1 + (num - div) / 2
    } else {
        num / 2
    });
}


use std::io;
use std::str;

pub struct Scanner<R> {
    reader: R,
    buffer: Vec<String>,
}

impl<R: io::BufRead> Scanner<R> {
    pub fn new(reader: R) -> Self {
        Self {
            reader,
            buffer: vec![],
        }
    }

    pub fn token<T: str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buffer.pop() {
                return token.parse().ok().expect("Failed parse");
            }
            let mut input = String::new();
            self.reader.read_line(&mut input).expect("Failed read");
            self.buffer = input.split_whitespace().rev().map(String::from).collect();
        }
    }
}

fn get_mpf(n: u64) -> u64 {
    let mut d = 2;
    while d * d <= n {
        if n % d == 0 {
            return d;
        }
        d += 1;
    }
    n
}

fn solve<R: io::BufRead, W: io::Write>(scan: &mut Scanner<R>, out: &mut W) {
    let n: u64 = scan.token();
    let mpf = get_mpf(n);
    let ans;
    if mpf % 2 != 0 {
        if n == mpf {
            ans = 1;
        } else {
            ans = 1 + (n - mpf) / get_mpf(n - mpf);
        }
    } else {
        ans = n / mpf;
    }
    writeln!(out, "{}", ans).ok();
}

fn main() {
    let (stdin, stdout) = (io::stdin(), io::stdout());
    let mut scan = Scanner::new(stdin.lock());
    let mut out = io::BufWriter::new(stdout.lock());
    solve(&mut scan, &mut out);
}


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

use std::cmp::*;
use std::collections::*;
use std::io::{Write, BufWriter};
// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes
                .by_ref()
                .map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};

    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

macro_rules! read_value {
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };

    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };

    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };

    ($next:expr, usize1) => {
        read_value!($next, usize) - 1
    };

    ($next:expr, [ $t:tt ]) => {{
        let len = read_value!($next, usize);
        (0..len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    }};

    ($next:expr, $t:ty) => {
        $next().parse::<$t>().expect("Parse error")
    };
}

use std::io::*;
use std::str::FromStr;
use std::char::*;
macro_rules! debug {($($a:expr),*) => {eprintln!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);}}

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

use std::f64;

fn min<T: PartialOrd>(a:T, b:T) -> T {
    if a < b { a }
    else { b }
}

fn max<T: PartialOrd>(a:T, b:T) -> T {
    if a < b { b }
    else { a }
}

const MAX:i64 = 1000000009;
const INF:i64 = std::i64::MAX;
const MOD:i64 = 1e9 as i64 + 7;

struct Graph {
    e: Vec<Vec<usize>>,
    v: Vec<usize>,
    u: Vec<usize>,
    f: Vec<bool>,
    c: i64,
    flag: bool,
    vc: Vec<i64>,
}

impl Graph {
    fn new(n:usize) -> Self {
        Graph {
            e: vec![vec![];n],
            v: vec![],
            u: vec![n;n],
            f: vec![false;n],
            c: 0,
            flag: true,
            vc: vec![0;n],
        }
    }

    fn dfs(&mut self, crt: usize) {
        self.f[crt] = true;
        self.c = self.e[crt].len() as i64;
        if self.c != 2 {
            self.flag = false;
        }

        for i in 0..self.e[crt].len() {
            let v = self.e[crt][i];
            if self.f[v] { continue; }
            self.dfs(v);
        }
    }
}

fn binary_search(s: &Vec<i64>, v:i64) -> usize {
    let mut left = 0;
    let mut right = s.len();

    while right-left > 1 {
        let mid = (right+left)/2;
        //debug!(left,mid,right,s[mid]);
        if s[mid] < v { left = mid; }
        else { right = mid; }
    }
    left
}

fn neighbors(tree: &BTreeSet<usize>, val: usize) -> (Option<&usize>, Option<&usize>) {
    use std::ops::Bound::*;

    let mut before = tree.range((Unbounded, Excluded(val)));
    let mut after = tree.range((Excluded(val), Unbounded));

    (before.next_back(), after.next())
}

fn main() {
    // In order to avoid potential stack overflow, spawn a new thread.
    let stack_size = 104_857_600; // 100 MB
    let thd = std::thread::Builder::new().stack_size(stack_size);
    thd.spawn(|| solve()).unwrap().join().unwrap();
}

const MAX_A:i64 = 1e16 as i64;

fn gcd(a:i64, b:i64) -> i64 {
    if b==0 {return a;}
    gcd(b, a%b)
}

struct BIT {
    n: usize,
    bit: Vec<i64>,
}

impl BIT {
    fn new(n:usize) -> BIT {
        BIT {
            n,
            bit: vec![0;n+1],
        }
    }

    fn add(&mut self, a:usize, w:i64) {
        let mut x = a;
        while x <= self.n {
            self.bit[x] += w;
            x += (x as i64 & -(x as i64)) as usize;
        }
    }

    fn sum(&self, a:usize) -> i64 {
        let mut ret = 0;
        let mut x = a as i64;
        while x > 0 {
            ret += self.bit[x as usize];
            x -= x & -x;
        }
        ret
    }
}

fn prime_factor(n: i64) -> BTreeMap<i64,i64> {
    let mut n = n;
    let mut map = BTreeMap::new();
    let mut i = 2;
    while i*i <= n {
        while n%i == 0 {
            let count = map.entry(i).or_insert(0);
            *count += 1;
            n /= i;
        }
        i += 1;
    }
    if n!=1 { map.insert(n,1); }
    map
}

fn solve() {
    let out = std::io::stdout();
    let mut out = BufWriter::new(out.lock());
    macro_rules! puts {
        ($($format:tt)*) => (let _ = write!(out,$($format)*););
    }

    input! {
        n: i64,
    }

    let mut n = n;
    let fac = prime_factor(n);
    let d = *fac.iter().next().unwrap().0;
    //debug!(d);
    let mut ans = 0;
    if d != 2 {
        n -= d;
        ans += 1;
    }
    //debug!(d,n);
    puts!("{}\n", ans+n/2);
}

/*

n から最小の素数の約数を引いていく、何回操作ができるか。

34, 32, 30, 28, .., 2, 0
31, 0
6, 4, 2, 0
10, 8, 6, 4,
9, 6, 4, 2, 0
25, 20, 18, 16, 14, 12, 10
3*3 -> 3*2 -> 2*2 -> 2*1 -> 2*0
5*5 -> 10*2 (5*4) -> 9*2 -> 8*2 -> .. -> 1*2 -> 0*2
3*3*3 (3*9) -> 3*8 (2*12) -> 2*11 -> .. -> 2*0

素因数分解する。最小の約数が２じゃないなら、それで引く。
次の数字は必ず最小の素数の約数が２になるので答えに２で割った数を足す。

*/


fn main() {
    let mut input = String::new();
    use std::io::{self, prelude::*};
    io::stdin().read_to_string(&mut input).unwrap();

    let mut it = input.split_whitespace();
    let r0 = it.next().unwrap();
    let n = r0.len();
    let r1 = it.next().unwrap();

    #[derive(Clone, Copy, Debug)]
    enum Cell {
        Empty,
        Pawn,
    }

    let mut grid: Vec<_> = r0.chars().chain(r1.chars()).map(|c| {
        match c {
            '0' => Cell::Empty,
            'X' => Cell::Pawn,
            _ => panic!("Oops!"),
        }
    }).collect();

    let f = |c| {
        match c {
            Cell::Empty => 1,
            Cell::Pawn => 0,
        }
    };

    let cnt = |c, grid: &[Cell]| {
        f(grid[c]) + f(grid[n + c])
    };

    let mut ans = 0;
    for c in 0..n {
        if cnt(c, &grid) == 2 {
            if c > 0 && cnt(c - 1, &grid) == 1 {
                grid[c] = Cell::Pawn;
                grid[n + c] = Cell::Pawn;
                ans += 1;
            } else if c + 1 < n {
                if let Cell::Empty = grid[c + 1] {
                    grid[c + 1] = Cell::Pawn;
                    grid[c] = Cell::Pawn;
                    grid[n + c] = Cell::Pawn;
                    ans += 1;
                } else if let Cell::Empty = grid[n + c + 1] {
                    grid[n + c + 1] = Cell::Pawn;
                    grid[c] = Cell::Pawn;
                    grid[n + c] = Cell::Pawn;
                    ans += 1;
                }
            }
        }
    }

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


// 991D
use std::io;

fn main() {
    let mut a = String::new();
    io::stdin().read_line(&mut a).unwrap();
    let a = a.trim();
    let mut b = String::new();
    io::stdin().read_line(&mut b).unwrap();
    let b = b.trim();
    let mut v: Vec<u32> = Vec::with_capacity(a.len());
    for (p, q) in a.chars().zip(b.chars()) {
        let mut slots = if p == '0' { 1 } else { 0 } + if q == '0' { 1 } else { 0 };
        v.push(slots);
    }
    let mut bishwocks = 0;
    for i in 0..v.len() {
        if v[i] == 2 {
            if i != 0 && v[i - 1] == 1 {
                v[i] = 0;
                bishwocks += 1;
            } else if i + 1 != v.len() {
                if v[i + 1] != 0 {
                    v[i] = 0;
                    v[i + 1] -= 1;
                    bishwocks += 1;
                }
            }
        }
    }
    println!("{}", bishwocks);
}


#![allow(dead_code, unused_imports)]
#[rustfmt::skip] mod writer {use std::fmt::Display;use std::io::{stdout, BufWriter, Error as IoError, Stdout, Write};#[derive(Debug)] pub struct Writer<W: Write> { writer: BufWriter<W>, }  #[derive(Debug, Clone)] pub struct Format<'a> {  separator: &'a str,  ending: &'a str, }  impl<'a> Format<'a> { pub fn separator(self, separator: &'a str) -> Self { Self { separator, ..self } }  pub fn ending(self, ending: &'a str) -> Self { Self { ending, ..self } } }  impl Default for Format<'_> { fn default() -> Self { Format { separator: " ", ending: "\n", } } }  impl Writer<Stdout> { pub fn stdout() -> Self { Self::new(stdout()) } }  impl<W: Write> Writer<W> { pub fn new(writer: W) -> Self { Self { writer: BufWriter::new(writer), } }  pub fn write<M, T: Writable<M>>(&mut self, val: T) -> Result<(), IoError> { self.write_with(val, &Format::default()) }  pub fn write_with<M, T: Writable<M>>(&mut self, val: T, fmt: &Format) -> Result<(), IoError> { val.write_to(&mut self.writer, fmt) }  pub fn flush(&mut self) -> Result<(), IoError> { self.writer.flush() } }  pub trait Writable<Mode> { fn write_to<W: Write>(self, w: &mut W, fmt: &Format) -> Result<(), IoError>;}  #[non_exhaustive] pub struct Single;impl<T: Display> Writable<Single> for T { fn write_to<W: Write>(self, w: &mut W, fmt: &Format) -> Result<(), IoError> { write!(w, "{}{}", self, fmt.ending) } }  #[non_exhaustive] pub struct Many;impl<I> Writable<Many> for I where I: Iterator, I::Item: Display, { fn write_to<W: Write>(mut self, w: &mut W, fmt: &Format) -> Result<(), IoError> { if let Some(x) = self.next() { write!(w, "{}", x)?;} else {  return Ok(());}  for x in self { write!(w, "{}{}", fmt.separator, x)?;} write!(w, "{}", fmt.ending) } }  #[non_exhaustive] pub struct Slice;impl<T: Display> Writable<Slice> for &[T] { fn write_to<W: Write>(self, w: &mut W, fmt: &Format) -> Result<(), IoError> { self.iter().write_to(w, fmt) } }  #[macro_export]   macro_rules! out { ($writer:expr, $val:expr) => { $writer.write($val).expect("failed to write token");};($writer:expr, $val:expr, $($builder_name:ident = $value:expr),+) => { let mut fmt = Format::default();$( fmt = fmt.$builder_name($value);)+ $writer.write_with($val, &fmt).expect("failed to write token");};} }
#[rustfmt::skip] mod scanner {use std::fmt::Debug;use std::io::{stdin, BufReader, Bytes, Error as IoError, Read, Stdin};use std::str::{self, FromStr, Utf8Error};#[derive(Debug)] pub struct Scanner<R: Read> { bytes: Bytes<BufReader<R>>, buf: Vec<u8>, }      pub trait Instructions { type Target;type Error;fn read_from<R: Read>(scanner: &mut Scanner<R>) -> Result<Self::Target, Self::Error>;}  impl<T: FromStr> Instructions for T { type Target = T;type Error = ScanError<T>;fn read_from<R: Read>(scanner: &mut Scanner<R>) -> Result<Self::Target, Self::Error> { scanner.read_token() } }  #[derive(Debug)] pub enum ScanError<T: FromStr> { Io(IoError), Parse(T::Err, String), NonUtf8(Utf8Error, Vec<u8>), }  impl Scanner<Stdin> { pub fn stdin() -> Self { Self::new(stdin()) } }  impl<R: Read> Scanner<R> { pub fn new(reader: R) -> Self { Self { bytes: BufReader::new(reader).bytes(), buf: Vec::new(), } }  pub fn read_token<T: FromStr>(&mut self) -> Result<T, ScanError<T>> { debug_assert!(self.buf.is_empty());for b in &mut self.bytes { let b = b.map_err(ScanError::Io)?;if b.is_ascii_whitespace() {  if self.buf.is_empty() { continue;} else { break;} } else { self.buf.push(b);} }   match str::from_utf8(&self.buf) { Err(err) => Err(ScanError::NonUtf8(err, std::mem::take(&mut self.buf))), Ok(s) => { let ret = s.parse().map_err(|err| ScanError::Parse(err, s.to_owned()));self.buf.clear();ret } } }  pub fn read<T: Instructions>(&mut self) -> Result<T::Target, T::Error> { T::read_from(self) } }  #[macro_use] pub mod macros { use super::*;use std::fmt::{self, Debug};use std::io::Read;use std::marker::PhantomData;use std::num::NonZeroUsize;use std::str::FromStr;pub struct UsizeM1(());impl Instructions for UsizeM1 { type Target = usize;type Error = ScanError<NonZeroUsize>;fn read_from<R: Read>(scanner: &mut Scanner<R>) -> Result<Self::Target, Self::Error> { Ok(scanner.read_token::<NonZeroUsize>()?.get() - 1) } }   pub struct LenArray<T>(PhantomData<T>);impl<T: FromStr> Instructions for LenArray<T> { type Target = Vec<T>;type Error = LenArrayScanError<T>;fn read_from<R: Read>(scanner: &mut Scanner<R>) -> Result<Self::Target, Self::Error> { let len = scanner .read_token::<usize>() .map_err(LenArrayScanError::Len)?;let mut arr = Vec::with_capacity(len);for i in 0..len { let elem = scanner .read_token::<T>() .map_err(|e| LenArrayScanError::Data(i, e))?;arr.push(elem);} Ok(arr) } }  pub enum LenArrayScanError<T: FromStr> { Len(ScanError<usize>), Data(usize, ScanError<T>), }  impl<T> Debug for LenArrayScanError<T> where T: Debug + FromStr, T::Err: Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::LenArrayScanError::*;match self { Len(e) => f.debug_tuple("Len").field(e).finish(), Data(i, e) => f.debug_tuple("Data").field(i).field(e).finish(), } } }  #[macro_export] macro_rules! scan { (@scan 1 $scan:expr, $type:ty) => { $scan .read::<$type>() .expect(concat!("failed to read token of type ", stringify!($type))) };(@scan 2 $scan:expr, $type:ty, $n:expr) => { (0..$n) .map(|_| scan!(@scan 1 $scan, $type)) .collect::<Vec<_>>() };(@accum ($scan:expr) () -> ($($body:tt)*)) => { ($($body)*) };(@accum ($scan:expr) ($type:ty) -> ($($body:tt)*)) => { scan!(@accum ($scan) () -> ($($body)* scan!(@scan 1 $scan, $type))) };(@accum ($scan:expr) ($type:ty, $($next:tt)*) -> ($($body:tt)*)) => { scan!(@accum ($scan) ($($next)*) -> ($($body)* scan!(@scan 1 $scan, $type),)) };(@accum ($scan:expr) ($n:tt * $type:ty) -> ($($body:tt)*)) => { scan!(@accum ($scan) () -> ($($body)* scan!(@scan 2 $scan, $type, $n))) };(@accum ($scan:expr) ($n:tt * $type:ty, $($next:tt)*) -> ($($body:tt)*)) => { scan!(@accum ($scan) ($($next)*) -> ($($body)* scan!(@scan 2 $scan, $type, $n),)) };($scan:expr, $($arg:tt)+) => { scan!(@accum ($scan) ($($arg)+) -> ()) };} } }
#[rustfmt::skip] mod util {   use std::cmp::Reverse; pub trait IntoVec<T, _Hack> { fn into_vec(self) -> Vec<T>;}  #[non_exhaustive] pub struct Owned;impl<I, T> IntoVec<T, Owned> for I where I: Iterator<Item = T>, { fn into_vec(self) -> Vec<T> { self.collect() } }  #[non_exhaustive] pub struct Reference;impl<'a, I, T> IntoVec<T, Reference> for I where I: Iterator<Item = &'a T>, T: Clone + 'a, { fn into_vec(self) -> Vec<T> { self.cloned().collect() } }  pub trait Argmax { fn argmax(self) -> Option<usize>;fn argmin(self) -> Option<usize>;}  impl<I> Argmax for I where I: Iterator, I::Item: Ord, { fn argmax(self) -> Option<usize> { self.fold((0, None), |(i, mx), next| { if let Some((mx_i, mx_v)) = mx { if next.gt(&mx_v) { (i + 1, Some((i, next))) } else { (i + 1, Some((mx_i, mx_v))) } } else { (i + 1, Some((i, next))) } }) .1 .map(|x| x.0) }  fn argmin(self) -> Option<usize> { self.map(Reverse).argmax() } }  pub trait Sorted<T> { fn sorted(self) -> Self;}  impl<T> Sorted<T> for Vec<T> where T: Ord, { fn sorted(mut self) -> Self { self.sort();self } }  pub trait SortedBy<T> { fn sorted_by<F, K>(self, f: F) -> Self where F: FnMut(&T) -> K, K: Ord;}  impl<T> SortedBy<T> for Vec<T> { fn sorted_by<F, K>(mut self, f: F) -> Self where F: FnMut(&T) -> K, K: Ord, { self.sort_by_key(f);self } }  pub trait Choose { fn choose<T>(self, a: T, b: T) -> T;fn choose_by<T>(self, a: impl FnOnce() -> T, b: impl FnOnce() -> T) -> T;}  impl Choose for bool { fn choose<T>(self, a: T, b: T) -> T { if self { a } else { b } }  fn choose_by<T>(self, a: impl FnOnce() -> T, b: impl FnOnce() -> T) -> T { if self { a() } else { b() } } }  #[macro_export] macro_rules! p { ( $( $x:expr ),* ) => { #[cfg(any(debug_assertions, debug_print))] { dbg!( $( & $x, )* );} };}  pub fn fix<A, R>(f: &dyn Fn(&dyn Fn(A) -> R, A) -> R) -> impl Fn(A) -> R + '_ { move |arg| f(&fix(&f), arg) }  pub trait Assign<T> { fn assign(&mut self, val: T);}  impl<T> Assign<T> for Option<T> {  fn assign(&mut self, val: T) { assert!(self.is_none(), ".assign() called on Some variant");*self = Some(val);} } }
#[rustfmt::skip] mod prefix_sum {use std::{ fmt::{self, Debug, Formatter}, marker::PhantomData, ops::{Add, Bound, Range, RangeBounds, Sub}, };#[derive(Clone)] pub struct PrefixOp<T, F, I> { fwd: F, inv: Option<I>, marker: PhantomData<fn(&T, &T) -> T>, }  impl<T, F> PrefixOp<T, F, ()> where F: Fn(&T, &T) -> T, {  pub fn new(op: F) -> Self { PrefixOp { fwd: op, inv: None, marker: PhantomData, } } }  impl<T, F, I> PrefixOp<T, F, I> where F: Fn(&T, &T) -> T, I: Fn(&T, &T) -> T, {     pub fn new_invertible(op: F, inverse: I) -> Self { PrefixOp { fwd: op, inv: Some(inverse), marker: PhantomData, } } }  impl<T, F, I> PrefixOp<T, F, I> where F: Fn(&T, &T) -> T, I: Clone, {  pub fn build(&self, mut arr: Vec<T>) -> PrefixArray<T, F, I> { for i in 1..arr.len() { arr[i] = (self.fwd)(&arr[i - 1], &arr[i]);} PrefixArray { pref: arr, fwd: PhantomData, inv: self.inv.clone(), } } }        #[derive(Clone)] pub struct PrefixArray<T, F, I> { pref: Vec<T>,   fwd: PhantomData<F>, inv: Option<I>, }  impl<T, F, I> PrefixArray<T, F, I> {  pub fn len(&self) -> usize { self.pref.len() }   pub fn is_empty(&self) -> bool { self.pref.is_empty() }   #[track_caller] fn verify_range_bounds(&self, range: impl RangeBounds<usize>) -> Range<usize> { let start = match range.start_bound() { Bound::Unbounded => 0, Bound::Included(&x) => x, Bound::Excluded(&x) => x + 1, };let end = match range.end_bound() { Bound::Unbounded => self.len(), Bound::Included(&x) => x + 1, Bound::Excluded(&x) => x, };assert!( start < end, "range inverted: start >= end ({} >= {})", start, end );assert!( end <= self.len(), "range out of bounds: end > len ({} > {})", end, self.len() );Range { start, end } }     #[track_caller] pub fn query_prefix(&self, range: impl RangeBounds<usize>) -> T where T: Clone, { let Range { start, end } = self.verify_range_bounds(range);assert!(start == 0, "query start bound is non-zero: {} > 0", start);self.pref[end - 1].clone() } }  impl<T, F, I> PrefixArray<T, F, I> where I: Fn(&T, &T) -> T, {  #[track_caller] pub fn query(&self, range: impl RangeBounds<usize>) -> T where T: Clone, { let Range { start, end } = self.verify_range_bounds(range);if start == 0 { self.pref[end - 1].clone() } else { (self .inv .as_ref() .expect("range query is not supported on non-invertible operation"))( &self.pref[end - 1], &self.pref[start - 1], ) } } }  impl<T, F, I> Debug for PrefixOp<T, F, I> where T: Debug, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("PrefixOp").finish_non_exhaustive() } }  impl<T, F, I> Debug for PrefixArray<T, F, I> where T: Debug, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("PrefixArray") .field("pref", &self.pref) .finish_non_exhaustive() } }  type NextFn<T> = fn(&T, &T) -> T;pub struct PrefixSum<T>(PhantomData<T>);impl<T> PrefixSum<T> where T: Add<Output = T> + Sub<Output = T> + Clone, {  pub fn op() -> PrefixOp<T, NextFn<T>, NextFn<T>> { PrefixOp::new_invertible(|a, b| a.clone() + b.clone(), |b, a| b.clone() - a.clone()) }   pub fn build(arr: Vec<T>) -> PrefixArray<T, NextFn<T>, NextFn<T>> { Self::op().build(arr) } } }
#[rustfmt::skip] mod combinatorics {use crate::{num::Integer, number_theory::mod_mulinv};pub fn next_permutation<T>(perm: &mut [T]) -> bool where T: Ord, { if perm.is_empty() { return false;}   let i = match Iterator::zip(perm.iter(), perm[1..].iter()).rposition(|(x, y)| x < y) { None => {  perm.reverse();return false;} Some(x) => x, };let j = perm .iter() .rposition(|x| &perm[i] < x) .expect("inconsistent Ord implementation");perm.swap(i, j);perm[i + 1..].reverse();true }       #[derive(Debug, Clone)]  pub struct Factorials<N> { m: N, fact: Vec<N>, fact_inv: Vec<N>, }  impl<N> Factorials<N> where N: Integer + Clone, { #[inline] fn as_n(x: usize) -> N { N::from_usize(x).expect("inconsistent Integer implementation") } #[inline] fn as_usize(x: &N) -> usize { N::as_usize(x).expect("inconsistent Integer implementation") }      #[track_caller] pub fn new(n: N, m: N) -> Self { let cap = n .as_usize() .and_then(|x| x.checked_add(1)) .expect("required capacity overflowed usize");assert!(cap > 0, "n must be non-negative");let mut fact = Vec::with_capacity(cap);fact.push(N::one());let mut cur = N::one();for i in 1..cap { cur = (cur * Self::as_n(i)).imod(&m);fact.push(cur.clone());}   let mut fact_inv = Vec::with_capacity(cap);let mut cur = mod_mulinv(fact[cap - 1].clone(), m.clone());for i in (0..cap).rev() { fact_inv.push(cur.clone());cur = (cur * Self::as_n(i)).imod(&m);} fact_inv.reverse();debug_assert_eq!(fact.len(), cap);debug_assert_eq!(fact_inv.len(), cap);Factorials { m, fact, fact_inv } }   pub fn len(&self) -> usize { self.fact.len() }    pub fn is_empty(&self) -> bool { false }   pub fn n(&self) -> N { Self::as_n(self.fact.len() - 1) }   #[track_caller] fn verify_n<'a>(&self, n: &'a N) -> &'a N { assert!( N::zero() <= *n && *n <= self.n(), "n is outside precomputed range" );n }     #[track_caller] pub fn factorial(&self, n: &N) -> N { let n = self.verify_n(n);self.fact[Self::as_usize(n)].clone() }     #[track_caller] pub fn factorial_inverse(&self, n: &N) -> N { let n = self.verify_n(n);self.fact_inv[Self::as_usize(n)].clone() }     #[track_caller] pub fn choose(&self, n: N, k: N) -> N { self.verify_n(&n);assert!(k >= N::zero(), "k is negative");if k <= n {  ((self.fact[Self::as_usize(&n)].clone() * self.fact_inv[Self::as_usize(&k)].clone()) .imod(&self.m) * self.fact_inv[Self::as_usize(&(n - k))].clone()) .imod(&self.m) } else { N::zero() } } } }
#[rustfmt::skip] mod number_theory {use crate::num::Integer;use std::mem;pub fn gcd<N: Integer>(mut a: N, mut b: N) -> N { while b != N::zero() { mem::swap(&mut a, &mut b);b = b.imod(&a);} a.iabs() }      #[allow(clippy::many_single_char_names)] pub fn egcd<N: Integer + Clone>(a: N, b: N) -> (N, N, N) { if b == N::zero() { ( a.iabs(), if a >= N::zero() { N::one() } else { N::zero() - N::one() }, N::zero(), ) } else { let (g, s, t) = egcd(b.clone(), a.imod(&b));(g, t.clone(), s - a.idiv(&b) * t) } }       #[track_caller] pub fn mod_exp<N: Integer + Clone>(a: N, mut b: N, m: N) -> N { let zero = N::zero();let one = N::one();let two = N::one() + N::one();assert!(m > zero, "modulus must be positive");if b < zero { return mod_exp(mod_mulinv(a, m.clone()), zero - b, m);}  let mut x = N::one();let mut pwr = a;while b > N::zero() { if b.imod(&two) == one { x = (x * pwr.clone()).imod(&m);} pwr = (pwr.clone() * pwr).imod(&m);b = b.idiv(&two);} x }      #[track_caller] pub fn mod_mulinv<N: Integer + Clone>(a: N, m: N) -> N { let zero = N::zero();let one = N::one();assert!(m > zero, "modulus must be positive");let (g, s, _) = egcd(a, m.clone());assert!(g == one, "multiplicative inverse does not exist");s.imod(&m) }         #[derive(Debug, Clone)]   pub struct PrimeSieve<N> { lowest_factor: Vec<N>, primes: Vec<N>, }  impl<N> PrimeSieve<N> where N: Integer + Clone, { #[inline] fn as_n(x: usize) -> N { N::from_usize(x).expect("inconsistent Integer implementation") } #[inline] fn as_usize(x: &N) -> usize { N::as_usize(x).expect("inconsistent Integer implementation") }     #[track_caller] pub fn new(n: N) -> Self { let cap = n .as_usize() .and_then(|x| x.checked_add(1)) .expect("capacity overflowed usize");assert!(cap > 0, "n must be non-negative");let mut lowest_factor = vec![N::zero(); cap];let mut primes = vec![];for i in 2..cap { if lowest_factor[i] == N::zero() { lowest_factor[i] = Self::as_n(i);primes.push(Self::as_n(i));}    let lowest_factor_i = lowest_factor[i].clone();for (p, p_usize) in primes .iter() .map(|p| (p, Self::as_usize(p))) .take_while(|(p, p_usize)| i * p_usize < cap && p <= &&lowest_factor_i) { lowest_factor[i * p_usize] = p.clone();} }  PrimeSieve { lowest_factor, primes, } }   pub fn len(&self) -> usize { self.lowest_factor.len() }    pub fn is_empty(&self) -> bool { false }   pub fn n(&self) -> N { Self::as_n(self.lowest_factor.len() - 1) }      #[track_caller] pub fn is_prime(&self, x: &N) -> bool { assert!(*x >= N::zero(), "x must be non-negative");let n = self.n();if *x <= n { *x > N::zero() && self.lowest_factor[Self::as_usize(x)] == *x } else if *x <= n.clone() * n { for p in self.primes.iter() { if x.imod(p) == N::zero() { return false;} } true } else { panic!("unable to determine primality: x > n^2");} }       #[track_caller] pub fn lowest_factor(&self, x: &N) -> N { assert!(*x >= N::zero(), "x must be non-negative");let n = self.n();if *x <= n { self.lowest_factor[Self::as_usize(x)].clone() } else if *x <= n.clone() * n { for p in self .primes .iter() .take_while(|&p| p.clone() * p.clone() <= *x) { if x.imod(p) == N::zero() { return p.clone();} } x.clone() } else { panic!("unable to determine lowest factor: x > n^2",) } }      #[track_caller] pub fn factorize(&self, mut x: N) -> Vec<N> { let n = self.n();assert!(x > N::zero(), "cannot factorize non-positive numbers");assert!(x <= n.clone() * n.clone(), "unable to factorize: x > n^2",);let mut factors = Vec::new();let x2 = x.clone();let mut primes = self .primes .iter() .take_while(|&p| p.clone() * p.clone() <= x2);while x > N::one() { if x <= n { let f = &self.lowest_factor[Self::as_usize(&x)];factors.push(f.clone());x = x.idiv(f);} else if let Some(p) = primes.next() { while x.imod(p) == N::zero() { factors.push(p.clone());x = x.idiv(p);} } else {  factors.push(x);break;} } factors } } }
#[rustfmt::skip] mod num {use std::convert::{TryFrom, TryInto};use std::ops::{Add, Div, Mul, Rem, Sub};pub trait Num: Ord + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self> + FromPrimitive + IntoPrimitive + Sized {  fn zero() -> Self;fn one() -> Self;}  pub trait FromPrimitive: Sized {  fn from_u64(x: u64) -> Option<Self>;fn from_i64(x: i64) -> Option<Self>;fn from_usize(x: usize) -> Option<Self> { Self::from_u64(x as u64) }  fn from_isize(x: isize) -> Option<Self> { Self::from_i64(x as i64) } }  pub trait IntoPrimitive {  fn as_u64(&self) -> Option<u64>;fn as_i64(&self) -> Option<i64>;fn as_usize(&self) -> Option<usize> { self.as_u64().and_then(|x| x.try_into().ok()) }  fn as_isize(&self) -> Option<isize> { self.as_i64().and_then(|x| x.try_into().ok()) } }       pub trait Integer: Num {  fn idiv(&self, x: &Self) -> Self;fn imod(&self, x: &Self) -> Self;fn iabs(&self) -> Self;}  macro_rules! generate_integer_impl_for_primitive { ($( ($ty:ty, $unsigned:tt) ),+) => { $( impl FromPrimitive for $ty { #[inline(always)] fn from_u64(x: u64) -> Option<Self> { <$ty>::try_from(x).ok() } #[inline(always)] fn from_i64(x: i64) -> Option<Self> { <$ty>::try_from(x).ok() } }  impl IntoPrimitive for $ty { #[inline(always)] fn as_u64(&self) -> Option<u64> { u64::try_from(*self).ok() } #[inline(always)] fn as_i64(&self) -> Option<i64> { i64::try_from(*self).ok() } }  impl Num for $ty { #[inline(always)] fn zero() -> Self { 0 } #[inline(always)] fn one() -> Self { 1 } }  impl Integer for $ty { #[inline(always)] fn idiv(&self, x: &Self) -> Self { self.div_euclid(*x) } #[inline(always)] fn imod(&self, x: &Self) -> Self { self.rem_euclid(*x) } generate_iabs_impl!($unsigned);} )+ };}  macro_rules! generate_iabs_impl { (true) => { #[inline(always)] fn iabs(&self) -> Self { *self } };(false) => { #[inline(always)] fn iabs(&self) -> Self { self.abs() } };}  generate_integer_impl_for_primitive!( (u8, true), (u16, true), (u32, true), (u64, true), (u128, true), (usize, true), (i8, false), (i16, false), (i32, false), (i64, false), (i128, false), (isize, false) );}

use combinatorics::{next_permutation, Factorials};
use number_theory::{egcd, gcd, mod_exp, mod_mulinv, PrimeSieve};
use prefix_sum::{PrefixOp, PrefixSum};
use scanner::{
    macros::{LenArray, UsizeM1},
    Scanner,
};
use util::{fix, Argmax, Assign, Choose, IntoVec, Sorted};
use writer::{Format, Writer};

fn main() {
    let mut sc = Scanner::stdin();
    let mut wr = Writer::stdout();

    const MOD: i64 = 1_000_000_007;
    const N: i64 = 100_000;
    let n = scan!(sc, i64);
    let primes = PrimeSieve::new(N);

    let totient = |n: i64| {
        let mut t = n;
        let mut pf = primes.factorize(n);
        pf.sort();
        pf.dedup();
        for f in pf {
            t -= t / f
        }
        t
    };
    let totient_pre = (0..=N)
        .map(|i| if i <= 1 { 0 } else { totient(i) })
        .into_vec();
    p!(&totient_pre[..10]);

    let mut total = 0;
    for c in 1..=n - 2 {
        let mut gs = vec![];
        for g in (1..).take_while(|g| g * g <= n - c) {
            if (n - c) % g == 0 {
                gs.push(g);
                if g * g != n - c {
                    gs.push((n - c) / g);
                }
            }
        }
        p!(c, gs);

        for g in gs {
            let cnt = totient_pre[((n - c) / g) as usize];
            p!(g, cnt, (n - c) / g);
            total = (total + cnt * c * g / gcd(c, g)) % MOD;
        }
    }

    out!(wr, total);
}


use std::{
    io::{prelude::*, stdin, stdout, BufWriter},
    mem::swap,
};

const MOD: i64 = 1000000007;

fn main() {
    let std_in = stdin();
    let mut input = Scanner::new(std_in.lock());

    let std_out = stdout();
    let mut output = BufWriter::new(std_out.lock());

    let n: usize = input.token();

    let mut phi: Vec<usize> = (0..=n).collect();
    for i in 2..=n {
        if phi[i] == i {
            for j in (i..=n).step_by(i) {
                phi[j] -= phi[j] / i;
            }
        }
    }

    let mut result = 0;
    for c in 1..n {
        let sum = n - c;
        if sum < 2 {
            continue;
        }

        add_to_result(c as i64, 1, phi[sum] as i64, &mut result);
        for x in 2..=sum {
            if x * x > sum {
                break;
            }
            if sum % x != 0 {
                continue;
            }

            let y = sum / x;
            if phi[y] != 0 {
                add_to_result(c as i64, x as i64, phi[y] as i64, &mut result);
            }
            if x != y && phi[x] != 0 {
                add_to_result(c as i64, y as i64, phi[x] as i64, &mut result);
            }
        }
    }
    writeln!(output, "{}", result).unwrap();
}

fn add_m(x: i64, y: i64) -> i64 {
    let mut tmp = x + y;
    if tmp < 0 {
        tmp += MOD;
    }
    if tmp >= MOD {
        tmp -= MOD;
    }
    tmp
}

fn mul_m(x: i64, y: i64) -> i64 {
    (x * y) % MOD
}

fn gcd(mut a: i64, mut b: i64) -> i64 {
    while b != 0 {
        a %= b;
        swap(&mut a, &mut b);
    }
    a
}

fn add_to_result(c: i64, g: i64, cnt: i64, result: &mut i64) {
    *result = add_m(*result, mul_m(cnt, c * g / gcd(c, g)));
}

pub struct Scanner<B> {
    reader: B,
    buf_str: Vec<u8>,
    buf_iter: std::str::SplitWhitespace<'static>,
}
impl<B: BufRead> Scanner<B> {
    pub fn new(reader: B) -> Self {
        Self {
            reader,
            buf_str: Vec::new(),
            buf_iter: "".split_whitespace(),
        }
    }
    pub fn token<T: std::str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buf_iter.next() {
                return token.parse().ok().expect("Failed parse");
            }
            self.buf_str.clear();
            self.reader
                .read_until(b'\n', &mut self.buf_str)
                .expect("Failed read");
            self.buf_iter = unsafe {
                let slice = std::str::from_utf8_unchecked(&self.buf_str);
                std::mem::transmute(slice.split_whitespace())
            }
        }
    }
}