#[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 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())
            }
        }
    }
}


#![allow(dead_code, unused_macros, unused_imports)]
use std::{cell::{Cell, RefCell, UnsafeCell}, cmp::{Ordering, Reverse, max, min}, collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque, hash_map::{DefaultHasher, RandomState}}, error::Error, fmt::{Display, Write as FmtWrite}, hash::{BuildHasher, Hash, Hasher}, io::{BufWriter, Read, Stdin, Stdout, Write}, iter::{FromIterator, Peekable}, mem::swap, ops::*, process::exit, rc::Rc, str::{FromStr, from_utf8_unchecked}, time::{Duration, Instant}, convert::{TryInto, TryFrom}, marker::PhantomData};

const IO_BUF_SIZE: usize = 1 << 16;
type Input = Scanner<Stdin>;
type Output = BufWriter<Stdout>;
fn _init_input() -> Input { Scanner::new(std::io::stdin()) }
fn _init_output() -> Output { BufWriter::with_capacity(IO_BUF_SIZE, std::io::stdout()) }

#[repr(transparent)] struct Unsync<T>(T);
unsafe impl<T> Sync for Unsync<T> {}

type BadLazy<T> = Unsync<UnsafeCell<Option<T>>>;
impl<T> BadLazy<T> {
    const fn new() -> Self { Self(UnsafeCell::new(None)) }
}

static INPUT: BadLazy<Input> = BadLazy::new();
static OUTPUT: BadLazy<Output> = BadLazy::new();

fn inp<F: FnOnce(&mut Input) -> R, R>(f: F) -> R {
    unsafe { f((&mut *INPUT.0.get()).get_or_insert_with(_init_input)) }
}
fn out<F: FnOnce(&mut Output) -> R, R>(f: F) -> R {
    unsafe { f((&mut *OUTPUT.0.get()).get_or_insert_with(_init_output)) }
}

macro_rules! read {
    () => { read() };
    ($t: ty) => { read::<$t>() };
    ($t: ty, $($tt: ty),*) => { (read::<$t>(), $(read::<$tt>(),)*) };
    [$t: ty; $n: expr] => { read_vec::<$t>($n) };
}
macro_rules! println {
    () => { out(|x| { let _ = writeln!(x); }) };
    ($exp: expr) => { out(|x| { let _ = writeln!(x, "{}", $exp); }) };
    ($fmt: expr, $($arg : tt )*) => { out(|x| { let _ = writeln!(x, $fmt, $($arg)*); }) }
}
macro_rules! print {
    ($exp: expr) => { out(|x| { let _ = write!(x, "{}", $exp); }) };
    ($fmt: expr, $($arg : tt )*) => { out(|x| { let _ = write!(x, $fmt, $($arg)*); }) }
}

fn out_flush() { out(|x| { let _ = x.flush(); }); }

fn input_is_eof() -> bool { inp(|x| x.eof()) }
fn read_byte() -> u8 { inp(|x| x.byte()) }
fn read_bytes_no_skip(n: usize) -> Vec<u8> { inp(|x| x.bytes_no_skip(n)) }
fn read_bytes(n: usize) -> Vec<u8> { inp(|x| x.bytes(n)) }
fn read_bytes2(n: usize, m: usize) -> Vec<Vec<u8>> { inp(|x| x.bytes2(n, m)) }
fn read_token() -> Vec<u8> { inp(|x| x.token_bytes()) }
fn read_token_str() -> String { unsafe { String::from_utf8_unchecked(read_token()) } }
fn read_line() -> Vec<u8> { inp(|x| x.line_bytes()) }
fn read_line_str() -> String { unsafe { String::from_utf8_unchecked(read_line()) } }
fn read<T: FromStr>() -> T { read_token_str().parse::<T>().ok().expect("failed parse") }
fn read_vec<T: FromStr>(n: usize) -> Vec<T> { (0..n).map(|_| read()).collect() }
fn read_vec2<T: FromStr>(n: usize, m: usize) -> Vec<Vec<T>> { (0..n).map(|_| read_vec(m)).collect() }

struct Scanner<R: Read> {
    src: R,
    _buf: Vec<u8>,
    _pt: usize, // pointer
    _rd: usize, // bytes read
}

#[allow(dead_code)]
impl<R: Read> Scanner<R> {
    fn new(src: R) -> Scanner<R> {
        Scanner { src, _buf: vec![0; IO_BUF_SIZE], _pt: 1, _rd: 1 }
    }

    fn _check_buf(&mut self) {
        if self._pt == self._rd {
            self._rd = self.src.read(&mut self._buf).unwrap_or(0);
            self._pt = (self._rd == 0) as usize;
        }
    }

    // returns true if end of file
    fn eof(&mut self) -> bool {
        self._check_buf();
        self._rd == 0
    }

    // filters \r, returns \0 if eof
    fn byte(&mut self) -> u8 {
        loop {
            self._check_buf();
            if self._rd == 0 { return 0; }
            let res = self._buf[self._pt];
            self._pt += 1;
            if res != b'\r' { return res; }
        }
    }

    fn bytes_no_skip(&mut self, n: usize) -> Vec<u8> { (0..n).map(|_| self.byte()).collect() }
    fn bytes(&mut self, n: usize) -> Vec<u8> {
        let res = self.bytes_no_skip(n);
        self.byte();
        res
    }
    fn bytes2(&mut self, n: usize, m: usize) -> Vec<Vec<u8>> { (0..n).map(|_| self.bytes(m)).collect() }

    fn token_bytes(&mut self) -> Vec<u8> {
        let mut res = Vec::new();
        let mut c = self.byte();
        while c <= b' ' {
            if c == b'\0' { return res; }
            c = self.byte();
        }
        loop {
            res.push(c);
            c = self.byte();
            if c <= b' ' { return res; }
        }
    }

    fn line_bytes(&mut self) -> Vec<u8> {
        let mut res = Vec::new();
        let mut c = self.byte();
        while c != b'\n' && c != b'\0' {
            res.push(c);
            c = self.byte();
        }
        res
    }
}

trait JoinToStr {
    fn join_to_str(self, sep: &str) -> String;
    fn concat_to_str(self) -> String;
}
impl<T: Display, I: Iterator<Item = T>> JoinToStr for I {
    fn join_to_str(mut self, sep: &str) -> String {
        match self.next() {
            Some(first) => {
                let mut res = first.to_string();
                while let Some(item) = self.next() {
                    res.push_str(sep);
                    res.push_str(&item.to_string());
                }
                res
            }
            None => { String::new() }
        }
    }

    fn concat_to_str(self) -> String {
        let mut res = String::new();
        for item in self { res.push_str(&item.to_string()); }
        res
    }
}
trait AsStr { fn as_str(&self) -> &str; }
impl AsStr for [u8] { fn as_str(&self) -> &str {std::str::from_utf8(self).expect("attempt to convert non-UTF8 byte string.")} }

macro_rules! veci {
    ($n:expr , $i:ident : $gen:expr) => {{
        let _veci_n = $n;
        let mut _veci_list = Vec::with_capacity(_veci_n);
        for $i in 0.._veci_n {
            _veci_list.push($gen);
        }
        _veci_list
    }};
    ($n:expr , $gen:expr) => { veci!($n, _veci_: $gen) }
}

fn abs_diff<T: Sub<Output = T> + PartialOrd>(x: T, y: T) -> T {
    if x < y { y - x } else { x - y }
}

trait CommonNumExt {
    fn div_ceil(self, b: Self) -> Self;
    fn div_floor(self, b: Self) -> Self;
    fn gcd(self, b: Self) -> Self;
    fn highest_one(self) -> Self;
    fn lowest_one(self) -> Self;
    fn sig_bits(self) -> u32;
}

macro_rules! impl_common_num_ext {
    ($($ix:tt = $ux:tt),*) => {
        $(
            impl CommonNumExt for $ux {
                fn div_ceil(self, b: Self) -> Self {
                    let q = self / b; let r = self % b;
                    if r != 0 { q + 1 } else { q }
                }
                fn div_floor(self, b: Self) -> Self { self / b }
                fn gcd(self, mut b: Self) -> Self {
                    let mut a = self;
                    if a == 0 || b == 0 { return a | b; }
                    let shift = (a | b).trailing_zeros();
                    a >>= a.trailing_zeros();
                    b >>= b.trailing_zeros();
                    while a != b {
                        if a > b { a -= b; a >>= a.trailing_zeros(); }
                        else { b -= a; b >>= b.trailing_zeros(); }
                    }
                    a << shift
                }
                #[inline] fn highest_one(self) -> Self {
                    if self == 0 { 0 } else { const ONE: $ux = 1; ONE << self.sig_bits() - 1 }
                }
                #[inline] fn lowest_one(self) -> Self { self & self.wrapping_neg() }
                #[inline] fn sig_bits(self) -> u32 { std::mem::size_of::<$ux>() as u32 * 8 - self.leading_zeros() }
            }

            impl CommonNumExt for $ix {
                fn div_ceil(self, b: Self) -> Self {
                    let q = self / b; let r = self % b;
                    if self ^ b >= 0 && r != 0 { q + 1 } else { q }
                }
                fn div_floor(self, b: Self) -> Self {
                    let q = self / b; let r = self % b;
                    if self ^ b < 0 && r != 0 { q - 1 } else { q }
                }
                fn gcd(self, b: Self) -> Self {
                    fn w_abs(x: $ix) -> $ux { (if x.is_negative() { x.wrapping_neg() } else { x }) as _ }
                    w_abs(self).gcd(w_abs(b)) as _
                }
                #[inline] fn highest_one(self) -> Self { (self as $ux).highest_one() as _ }
                #[inline] fn lowest_one(self) -> Self { self & self.wrapping_neg() }
                #[inline] fn sig_bits(self) -> u32 { std::mem::size_of::<$ix>() as u32 * 8 - self.leading_zeros() }
            }
        )*
    }
}
impl_common_num_ext!(i8 = u8, i16 = u16, i32 = u32, i64 = u64, i128 = u128, isize = usize);

trait ChMaxMin<T> {
    fn chmax(&mut self, v: T) -> bool;
    fn chmin(&mut self, v: T) -> bool;
}
impl<T: PartialOrd> ChMaxMin<T> for Option<T> {
    fn chmax(&mut self, v: T) -> bool { if self.is_none() || v > *self.as_ref().unwrap() { *self = Some(v); true } else { false } }
    fn chmin(&mut self, v: T) -> bool { if self.is_none() || v < *self.as_ref().unwrap() { *self = Some(v); true } else { false } }
}
impl<T: PartialOrd> ChMaxMin<T> for T {
    fn chmax(&mut self, v: T) -> bool { if v > *self { *self = v; true } else { false } }
    fn chmin(&mut self, v: T) -> bool { if v < *self { *self = v; true } else { false } }
}

// * end commons * //

#[macro_use]
#[allow(dead_code)]
mod modint {
    use std::{fmt::{Display, Formatter}, marker::PhantomData, mem::swap, ops::*, str::FromStr, cell::Cell};
    use crate::ModInt;

    pub trait RemEuclidU32: Copy {
        /// Calculates `self` _mod_ `modulus` losslessly.
        fn rem_euclid_u32(self, modulus: u32) -> u32;
    }

    macro_rules! impl_rem_euclid_u32_for_small_signed {
        ($($ty:tt),*) => {
            $(
                impl RemEuclidU32 for $ty {
                    #[inline]
                    fn rem_euclid_u32(self, modulus: u32) -> u32 {
                        (self as i64).rem_euclid(i64::from(modulus)) as _
                    }
                }
            )*
        }
    }

    impl_rem_euclid_u32_for_small_signed!(i8, i16, i32, i64, isize);

    impl RemEuclidU32 for i128 {
        #[inline]
        fn rem_euclid_u32(self, modulus: u32) -> u32 {
            self.rem_euclid(i128::from(modulus)) as _
        }
    }

    macro_rules! impl_rem_euclid_u32_for_small_unsigned {
        ($($ty:tt),*) => {
            $(
                impl RemEuclidU32 for $ty {
                    #[inline]
                    fn rem_euclid_u32(self, modulus: u32) -> u32 {
                        self as u32 % modulus
                    }
                }
            )*
        }
    }

    macro_rules! impl_rem_euclid_u32_for_large_unsigned {
        ($($ty:tt),*) => {
            $(
                impl RemEuclidU32 for $ty {
                    #[inline]
                    fn rem_euclid_u32(self, modulus: u32) -> u32 {
                        (self % (modulus as $ty)) as _
                    }
                }
            )*
        }
    }

    impl_rem_euclid_u32_for_small_unsigned!(u8, u16, u32);
    impl_rem_euclid_u32_for_large_unsigned!(u64, u128);

    #[cfg(target_pointer_width = "32")]
    impl_rem_euclid_u32_for_small_unsigned!(usize);

    #[cfg(target_pointer_width = "64")]
    impl_rem_euclid_u32_for_large_unsigned!(usize);
    #[inline]
    pub fn mul_mod_u32(a: u32, b: u32, m: u32) -> u32 {
        (a as u64 * b as u64 % m as u64) as u32
    }

    // for a, b < m, unspecified otherwise
    #[inline]
    fn add_mod_raw(a: u32, b: u32, m: u32) -> u32 {
        let (r, c) = a.wrapping_sub(m).overflowing_add(b);
        if c { r } else { a + b }
    }
    #[inline]
    fn sub_mod_raw(a: u32, b: u32, m: u32) -> u32 {
        let (r, c) = a.overflowing_sub(b);
        if c { r.wrapping_add(m) } else { r }
    }
    fn pow_mod_raw(a: u32, mut k: u64, m: u32) -> u32 {
        if m == 1 { return 0; }
        let mut a = a as u64;
        let m = m as u64;
        let mut r: u64 = 1;
        while k > 0 {
            if k & 1 == 1 {
                r = r * a % m;
            }
            k >>= 1;
            a = a * a % m;
        }
        r as u32
    }

    /// # Parameters
    /// * `b` `1 <= b`
    /// # Returns
    /// (x, g) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
    fn inv_gcd(a: i64, b: i64) -> (i64, i64) {
        let a = a.rem_euclid(b);
        if a == 0 { return (0, b); }
        let mut s = b;
        let mut t = a;
        let mut m0 = 0;
        let mut m1 = 1;

        while t != 0 {
            let u = s / t;
            s -= t * u;
            m0 -= m1 * u;
            swap(&mut s, &mut t);
            swap(&mut m0, &mut m1);
        }

        if m0 < 0 { m0 += b / s; }
        (m0, s)
    }

    pub trait Modulus: Copy + Eq {
        fn get_modulus() -> u32;
        fn mul(a: u32, b: u32) -> u32;
    }

    #[derive(Clone, Copy, PartialEq, Eq, Hash)]
    #[repr(transparent)]
    pub struct ModIntBase<M: Modulus> {
        val: u32,
        _phantom: PhantomData<M>
    }

    impl <M: Modulus> ModIntBase<M> {
        #[inline(always)]
        pub fn modulus() -> u32 { M::get_modulus() }
        #[inline] pub fn new<I: RemEuclidU32>(val: I) -> Self { Self::raw(val.rem_euclid_u32(Self::modulus())) }
        #[inline] pub fn raw(val: u32) -> Self { Self { val, _phantom: PhantomData } }
        pub fn inv(self) -> Self {
            let (x, gcd) = inv_gcd(self.val.into(), Self::modulus().into());
            debug_assert!(gcd == 1, "the multiplicative inverse {}^-1 mod {} does not exist", self.val, Self::modulus());
            Self::raw(x as u32)
        }
        #[inline] pub fn val(self) -> u32 { self.val }
        #[inline] pub fn pow(self, k: u64) -> Self {
            Self::raw(pow_mod_raw(self.val, k, Self::modulus()))
        }
        pub fn powi(self, k: i64) -> Self { if k < 0 { self.inv().pow(-k as _) } else { self.pow(k as _) } }
        pub fn pow_vec(self, n: usize) -> Vec<Self> {
            let mut res = vec![Self::raw(0); n+1];
            res[0] += 1;
            for i in 1..=n {
                res[i] = res[i-1] * self;
            }
            res
        }

        pub fn invs(a: &[Self]) -> Vec<Self> {
            let n = a.len();
            if n == 0 { return vec![]; }
            let mut acc = Self::new(1);
            let mut res = Vec::with_capacity(n);
            for i in 0..n {
                if a[i].val() != 0 { acc *= a[i]; }
                res.push(acc);
            }
            acc = acc.inv();
            for i in (1..n).rev() {
                res[i] = acc * res[i-1];
                if a[i].val() != 0 { acc *= a[i]; }
            }
            res[0] = acc;
            res
        }
    }

    #[inline]
    pub fn mi<I: RemEuclidU32>(val: I) -> ModInt { ModIntBase::new(val) }
    #[inline] pub fn mir(v: u32) -> ModInt { ModIntBase::raw(v) }

    impl<V: RemEuclidU32, M: Modulus> From<V> for ModIntBase<M> {
        #[inline]
        fn from(from: V) -> Self { Self::new(from) }
    }
    impl<M: Modulus> Default for ModIntBase<M> {
        fn default() -> Self { Self::raw(0) }
    }
    impl<M: Modulus> FromStr for ModIntBase<M> {
        type Err = std::convert::Infallible;
        #[inline]
        fn from_str(s: &str) -> Result<Self, Self::Err> {
            Ok(s.parse::<i64>()
            .map(Self::new)
            .unwrap_or_else(|_| todo!("parsing as an arbitrary precision integer?")))
        }
    }
    impl<M: Modulus> Display for ModIntBase<M> {
        #[inline]
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
            self.val.fmt(f)
        }
    }
    impl<M: Modulus> std::fmt::Debug for ModIntBase<M> {
        #[inline]
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
            std::fmt::Debug::fmt(&self.val, f)
        }
    }
    impl<M: Modulus> Neg for ModIntBase<M> {
        type Output = Self;

        #[inline]
        fn neg(self) -> Self::Output {
            Self::raw(0) - self
        }
    }

    impl<V: Into<ModIntBase<M>>, M: Modulus> Add<V> for ModIntBase<M> {
        type Output = Self;
        #[inline]
        fn add(self, rhs: V) -> Self::Output {
            Self::raw(add_mod_raw(self.val, rhs.into().val, Self::modulus()))
        }
    }
    impl<V: Into<ModIntBase<M>>, M: Modulus> Sub<V> for ModIntBase<M> {
        type Output = Self;
        #[inline]
        fn sub(self, rhs: V) -> Self::Output {
            Self::raw(sub_mod_raw(self.val, rhs.into().val, Self::modulus()))
        }
    }
    impl<V: Into<ModIntBase<M>>, M: Modulus> Mul<V> for ModIntBase<M> {
        type Output = Self;
        #[inline]
        fn mul(self, rhs: V) -> Self::Output {
            Self::raw(M::mul(self.val, rhs.into().val))
        }
    }
    impl<V: Into<ModIntBase<M>>, M: Modulus> Div<V> for ModIntBase<M> {
        type Output = Self;
        #[inline]
        fn div(self, rhs: V) -> Self::Output { self * rhs.into().inv() }
    }

    impl <V: Into<ModIntBase<M>>, M: Modulus> AddAssign<V> for ModIntBase<M> {
        #[inline]
        fn add_assign(&mut self, rhs: V) { *self = *self + rhs; }
    }
    impl <V: Into<ModIntBase<M>>, M: Modulus> SubAssign<V> for ModIntBase<M> {
        #[inline]
        fn sub_assign(&mut self, rhs: V) { *self = *self - rhs; }
    }
    impl <V: Into<ModIntBase<M>>, M: Modulus> MulAssign<V> for ModIntBase<M> {
        #[inline]
        fn mul_assign(&mut self, rhs: V) { *self = *self * rhs; }
    }
    impl <V: Into<ModIntBase<M>>, M: Modulus> DivAssign<V> for ModIntBase<M> {
        #[inline]
        fn div_assign(&mut self, rhs: V) { *self = *self / rhs; }
    }

    impl <M: Modulus> std::iter::Sum for ModIntBase<M> {
        #[inline] fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
            iter.fold(Self::raw(0), Add::add)
        }
    }
    impl <M: Modulus> std::iter::Product for ModIntBase<M> {
        #[inline] fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
            iter.fold(1.into(), Mul::mul)
        }
    }
    impl<'a, M: Modulus> std::iter::Sum<&'a Self> for ModIntBase<M> {
        #[inline] fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> ModIntBase<M> {
            iter.fold(Self::raw(0), |a, &b| a + b)
        }
    }
    impl<'a, M: Modulus> std::iter::Product<&'a Self> for ModIntBase<M> {
        #[inline] fn product<I: Iterator<Item = &'a Self>>(iter: I) -> ModIntBase<M> {
            iter.fold(1.into(), |a, &b| a * b)
        }
    }

    macro_rules! const_modulus {
        ($mint: ident, $name: ident, $modulus: expr) => {
            #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
            pub enum $name {}
            impl Modulus for $name {
                #[inline(always)] fn get_modulus() -> u32 { $modulus }
                fn mul(a: u32, b: u32) -> u32 {
                    mul_mod_u32(a, b, Self::get_modulus())
                }
            }
            pub type $mint = ModIntBase<$name>;
        }
    }

    #[derive(Debug, Clone, Copy)]
    pub struct ModulusCalc {
        pub modulus: u32,
        pub inv: u64
    }

    macro_rules! dynamic_modulus {
        ($mint: ident, $name: ident, $modulus: ident) => {
            static $modulus: crate::Unsync<Cell<ModulusCalc>> = crate::Unsync(Cell::new(ModulusCalc { modulus: 0, inv: 0 }));
            #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
            pub enum $name {}
            impl Modulus for $name {
                fn get_modulus() -> u32 { $modulus.0.get().modulus }
                fn mul(a: u32, b: u32) -> u32 {
                    let ModulusCalc { modulus, inv } = $modulus.0.get();
                    let p = a as u64 * b as u64;
                    let g = ((p as u128 * inv as u128) >> 64) as u64;
                    let (r, c) = p.overflowing_sub(g * modulus as u64);
                    if c { (r as u32).wrapping_add(modulus) } else { r as u32 }
                }
            }
            impl $name {
                pub fn set_modulus(val: u32) {
                    let inv = (1u64.wrapping_neg() / val as u64).wrapping_add(1);
                    $modulus.0.set(ModulusCalc { modulus: val, inv })
                }
            }
            pub type $mint = ModIntBase<$name>;
        }
    }

    const_modulus!(ModInt998_244_353, Mod998_244_353, 998_244_353);
    const_modulus!(ModInt1_000_000_007, Mod1_000_000_007, 1_000_000_007);
    dynamic_modulus!(DynamicModInt, DynamicModulus, DYNAMIC_MODULUS);
}

use crate::modint::*;
// type ModInt = ModInt998_244_353;
type ModInt = ModInt1_000_000_007;
// const_modulus!(ModInt, DefaultModulus, 1_000_000_009);
// type ModInt = DynamicModInt;

struct FactorMap {
    map: Vec<u32>
}
impl FactorMap {
    pub fn new(limit: usize) -> FactorMap {
        let limit = limit + 1;
        let mut map = vec![0; limit >> 1];
        for p in (3..limit).step_by(2) {
            if map[p >> 1] != 0 { continue; }
            let sq = p * p;
            if sq >= limit { break; }
            for i in (sq..limit).step_by(p*2) {
                if map[i >> 1] == 0 { map[i >> 1] = p as u32; }
            }
        }

        FactorMap { map }
    }

    pub fn least_prime_factor(&self, n: usize) -> usize {
        if n & 1 == 0 { return 2; }
        let p = self.map[n >> 1] as usize;
        if p == 0 { n } else { p }
    }

    pub fn factorize(&self, n: usize) -> FactorIterator {
        FactorIterator { fm: self, n }
    }

    pub fn is_prime(&self, n: usize) -> bool { n > 1 && self.least_prime_factor(n) == n }

    /// lists divisors, unsorted
    pub fn divisors(&self, mut n: usize) -> Vec<usize> {
        let mut res = vec![1];

        while n > 1 {
            let p = self.least_prime_factor(n);
            let mut x = 0;
            loop {
                n /= p;
                x += 1;
                if p != self.least_prime_factor(n) { break; }
            }
            for i in 0..res.len() {
                let mut a = res[i];
                for _ in 0..x {
                    a *= p;
                    res.push(a);
                }
            }
        }

        res
    }

    pub fn euler_totient(&self, mut n: usize) -> usize {
        let mut res = n;

        while n > 1 {
            let p = self.least_prime_factor(n);
            loop {
                n /= p;
                if p != self.least_prime_factor(n) { break; }
            }
            res = res / p * (p-1);
        }

        res
    }

    pub fn new_with_mobius(limit: usize) -> (FactorMap, Vec<i8>) {
        let fm = Self::new(limit);
        let mut mu = vec![1i8; limit + 1];
        mu[0] = 0;

        for i in 2..=limit {
            let p = fm.least_prime_factor(i);
            mu[i] = if p == fm.least_prime_factor(i/p) { 0 } else { -mu[i/p] };
        }

        (fm, mu)
    }
}
struct FactorIterator<'a> {
    fm: &'a FactorMap,
    n: usize
}
impl Iterator for FactorIterator<'_> {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        if self.n <= 1 { return None; }
        let p = self.fm.least_prime_factor(self.n);
        self.n /= p;
        Some(p)
    }

    fn size_hint(&self) -> (usize, Option<usize>) { (0, Some(32)) }
}

#[allow(non_snake_case, non_upper_case_globals)]
fn main() {
    let num_cases: usize = 1;//read();

    for _case_num in 1..=num_cases {
        let n = read!(usize);

        let mut ans = 0i128;
        let fm = FactorMap::new(n);
        for c in 1..=n-2 {
            for d in fm.divisors(n-c) { if d != n-c {
                let l = c / c.gcd(d) * d;
                ans += l as i128 * fm.euler_totient((n-c)/d) as i128;
            }}
        }

        ans %= 1_000_000_007;
        println!(ans);
    }

    out_flush();
}