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

use std::fmt::Debug;
use std::str::FromStr;

fn read_stdin() -> String {
    let mut s = String::new();
    std::io::stdin()
        .read_line(&mut s)
        .expect("cannot read stdin");
    s.trim().to_string()
}

fn read<T>() -> T
where
    T: FromStr,
    <T as FromStr>::Err: Debug,
{
    read_stdin().parse::<T>().unwrap()
}

fn read_usize() -> usize {
    read::<usize>()
}

fn read_2<A, B>() -> (A, B)
where
    A: FromStr,
    <A as FromStr>::Err: Debug,
    B: FromStr,
    <B as FromStr>::Err: Debug,
{
    let s = read_stdin();
    let mut s = s.split_whitespace();
    let a = s.next().unwrap().parse::<A>().unwrap();
    let b = s.next().unwrap().parse::<B>().unwrap();
    (a, b)
}

fn read_3<A, B, C>() -> (A, B, C)
where
    A: FromStr,
    <A as FromStr>::Err: Debug,
    B: FromStr,
    <B as FromStr>::Err: Debug,
    C: FromStr,
    <C as FromStr>::Err: Debug,
{
    let s = read_stdin();
    let mut s = s.split_whitespace();
    let a = s.next().unwrap().parse::<A>().unwrap();
    let b = s.next().unwrap().parse::<B>().unwrap();
    let c = s.next().unwrap().parse::<C>().unwrap();
    (a, b, c)
}

fn read_4<A, B, C, D>() -> (A, B, C, D)
where
    A: FromStr,
    <A as FromStr>::Err: Debug,
    B: FromStr,
    <B as FromStr>::Err: Debug,
    C: FromStr,
    <C as FromStr>::Err: Debug,
    D: FromStr,
    <D as FromStr>::Err: Debug,
{
    let s = read_stdin();
    let mut s = s.split_whitespace();
    let a = s.next().unwrap().parse::<A>().unwrap();
    let b = s.next().unwrap().parse::<B>().unwrap();
    let c = s.next().unwrap().parse::<C>().unwrap();
    let d = s.next().unwrap().parse::<D>().unwrap();
    (a, b, c, d)
}

fn read_multiple<T: FromStr>() -> Vec<T>
where
    <T as FromStr>::Err: Debug,
{
    read_stdin()
        .split_whitespace()
        .map(|x| x.parse::<T>().expect("cannot parse stdin"))
        .collect()
}

/// NOTE: sort iter beforehand if required
fn count<T>(iter: &mut impl Iterator<Item = T>) -> Vec<(T, usize)>
where
    T: std::cmp::Ord,
{
    let iter = iter.collect::<Vec<_>>();
    //iter.sort();
    let (mut v, o, c) =
        iter.into_iter()
            .fold((Vec::new(), None, 0), |(mut v, last, count), item| {
                if let Some(o) = last {
                    if item == o {
                        (v, Some(o), count + 1)
                    } else {
                        v.push((o, count));
                        (v, Some(item), 1)
                    }
                } else {
                    (v, Some(item), 1)
                }
            });
    if let Some(i) = o {
        v.push((i, c));
    }
    v
}

fn partial_sum<T>(v: impl Iterator<Item = T>) -> impl Iterator<Item = T>
where
    T: Default + std::ops::Add<Output = T> + Copy,
{
    v.scan(T::default(), |state, x| {
        *state = *state + x;
        Some(*state)
    })
}

fn partial_max<T>(v: impl Iterator<Item = T>) -> impl Iterator<Item = T>
where
    T: Default + Ord + Copy,
{
    v.scan(T::default(), |state, x| {
        *state = max(*state, x);
        Some(*state)
    })
}

fn partial_min(v: impl Iterator<Item = u64>) -> impl Iterator<Item = u64> {
    v.scan(std::u64::MAX, |state, x| {
        *state = min(*state, x);
        Some(*state)
    })
}

fn max_subarray(v: impl Iterator<Item = i64>) -> (i64, (usize, usize)) {
    //assert!(v.len() > 0);
    let mut best_sum = 0;
    let (mut best_start, mut best_end) = (0, 0);
    let mut current_sum = 0;
    let mut current_start = 0;
    for (end, val) in v.enumerate() {
        if current_sum <= 0 {
            current_start = end;
            current_sum = val;
        } else {
            current_sum += val;
        }
        if current_sum > best_sum {
            best_sum = current_sum;
            best_start = current_start;
            best_end = end + 1;
        }
    }
    (best_sum, (best_start, best_end))
}

fn gcd(mut a: u64, mut b: u64) -> u64 {
    while a != 0 {
        let old_m = a;
        a = b % a;
        b = old_m;
    }
    b
}

/// returns gcd, and pair (x, y), such that x * a + b * y == gcd
fn egcd(a: i64, b: i64) -> (i64, i64, i64) {
    if a == 0 {
        (b, 0, 1)
    } else {
        let (g, x, y) = egcd(b % a, a);
        (g, y - (b / a) * x, x)
    }
}

fn factorize(mut n: u64) -> Vec<u64> {
    if n <= 3 {
        return vec![n];
    }
    let mut v = Vec::new();
    while n % 2 == 0 {
        n /= 2;
        v.push(2);
    }
    while n % 3 == 0 {
        n /= 3;
        v.push(3);
    }
    let mut f = 6;
    while (f - 1) * (f - 1) <= n {
        while n % (f - 1) == 0 {
            n /= f - 1;
            v.push(f - 1);
        }
        while n % (f + 1) == 0 {
            n /= f + 1;
            v.push(f + 1);
        }
        f += 6;
    }
    if n > 1 {
        v.push(n);
    }
    v
}

fn compact_factors(n: u64) -> Vec<(u64, usize)> {
    count(&mut factorize(n).into_iter())
}

fn all_factors(n: u64) -> Vec<u64> {
    if n == 0 {
        return vec![0];
    } else if n == 1 {
        return vec![1];
    }
    let factors = compact_factors(n);
    let mut v = vec![1];
    for (fac, num) in factors {
        let ori = v.clone();
        for i in 1..num + 1 {
            v.append(
                &mut ori
                    .clone()
                    .into_iter()
                    .map(|f| f * fac.pow(i as u32))
                    .collect::<Vec<_>>(),
            )
        }
    }
    v.sort();
    v
}

fn abs_diff<T>(a: T, b: T) -> T
where
    T: PartialOrd + std::ops::Sub<Output = T>,
{
    if a > b {
        a - b
    } else {
        b - a
    }
}

struct Permutations<T> {
    inner: Vec<T>,
    state: Vec<usize>,
    i: usize,
    start: bool,
}

impl<T> Permutations<T> {
    fn new(inner: Vec<T>) -> Self {
        Self {
            state: vec![0; inner.len()],
            i: 0,
            start: true,
            inner,
        }
    }
}

/*impl<T, X> From<X> for Permutations<T>
where
    X: IntoIterator<Item = T>,
{
    fn from(f: X) -> Self {
        Self::new(f.into_iter().collect::<Vec<T>>())
    }
}*/

impl<T> Iterator for Permutations<T>
where
    T: Clone,
{
    type Item = Vec<T>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.start {
            self.start = false;
            return Some(self.inner.clone());
        }
        while self.i < self.inner.len() {
            if self.state[self.i] < self.i {
                if self.i % 2 == 0 {
                    self.inner.swap(0, self.i)
                } else {
                    self.inner.swap(self.state[self.i], self.i)
                }
                self.state[self.i] += 1;
                self.i = 0;
                return Some(self.inner.clone());
            } else {
                self.state[self.i] = 0;
                self.i += 1;
            }
        }
        None
    }
}

use std::cmp::{max, min, Ord, Ordering};
use std::collections::{BinaryHeap, VecDeque};
use std::mem::swap;

macro_rules! max_with {
    ($x: expr, $y: expr) => {
        $x = max($x, $y)
    };
}

macro_rules! min_with {
    ($x: expr, $y: expr) => {
        $x = max($x, $y)
    };
}

fn is_prime(n: u64) -> bool {
    factorize(n).len() == 1
}

fn combination(n: u64, k: u64, m: u64) -> u64 {
    if n == 0 {
        return 1;
    }
    if k == 0 || k == n {
        return 1;
    }
    let new_k = if n - k < k { n - k } else { k };
    let mut res = 1;
    for i in ((n - new_k) + 1)..=n {
        res *= i;
        res %= m;
    }
    let mut den = 1;
    for i in 1..=(new_k) {
        den *= i;
        den %= m;
    }
    let (_one, inverse, _c) = egcd(den as i64, m as i64);
    let inverse = if inverse < 0 {
        m as i64 + inverse
    } else {
        inverse
    } as u64;
    //println!("inv: {} {}", den, inverse);
    res *= inverse;
    res %= m;
    res
}

use std::collections::HashSet;
use std::iter::FromIterator;

fn n_to_vec(n: u64, l: usize) -> Vec<u8> {
    let mut res = vec![0; l];
    let mut n = n;
    for i in (0..l).rev() {
        if n % 2 == 1 {
            res[i] = 1;
        }
        n /= 2;
    }
    res
}

fn vec_to_n(v: Vec<u8>) -> u64 {
    let mut res = 0;
    for i in 0..v.len() {
        res *= 2;
        if v[i] == 1 {
            res += 1;
        }
    }
    res
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (a, b, c) = read_3::<u64, u64, u64>();
    let weeks = min(a / 3, min(b / 2, c / 2));
    let a = a - weeks * 3;
    let b = b - weeks * 2;
    let c = c - weeks * 2;
    let schedule = [1, 2, 3, 1, 3, 2, 1, 1, 2, 3, 1, 3, 2, 1];
    let mut max_additional = 0;
    for start in 0..7 {
        let mut p = start;
        let mut a_cop = a;
        let mut b_cop = b;
        let mut c_cop = c;
        let mut additional = 0;
        let mut flag = false;
        while !flag {
            if schedule[p] == 1 {
                if a_cop > 0 {
                    a_cop -= 1;
                    additional += 1;
                } else {
                    flag = true;
                }
            } else if schedule[p] == 2 {
                if b_cop > 0 {
                    b_cop -= 1;
                    additional += 1;
                } else {
                    flag = true;
                }
            } else {
                if c_cop > 0 {
                    c_cop -= 1;
                    additional += 1;
                } else {
                    flag = true;
                }
            }
            p += 1;
        }
        max_additional = max(max_additional, additional);
    }
    println!("{}", weeks * 7 + max_additional);
    Ok(())
}


use std::cmp::{max, min};
use std::io::stdin;

fn read_ints() -> Vec<u32> {
    let mut line = String::new();
    stdin().read_line(&mut line).unwrap();
    return line.trim().split(" ").map(|x| x.parse().unwrap()).collect();
}

fn main() {
    let mut rations = read_ints();
    let full_weeks = min(rations[0] / 3, min(rations[1] / 2, rations[2] / 2));
    rations[0] -= 3 * full_weeks;
    rations[1] -= 2 * full_weeks;
    rations[2] -= 2 * full_weeks;

    let mut max_more_days = 0;
    for start in 0..7 {
        let mut remain = rations.to_vec();
        for day in 0..7 {
            let idx = match (start + day) % 7 {
                0 | 3 | 6 => 0,
                1 | 5 => 1,
                _ => 2,
            };
            if remain[idx] == 0 {
                max_more_days = max(max_more_days, day);
                break;
            }
            remain[idx] -= 1;
        }
    }

    println!("{}", full_weeks * 7 + max_more_days);
}


#[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::prelude::BufRead;
#[allow(unused_imports)]
use std::io::{stdin, stdout, BufReader, BufWriter, Write};
#[allow(unused_imports)]
use std::mem::swap;
#[allow(unused_imports)]
use std::str::FromStr;

fn main() {
	let line = read_vector::<i64>();
	let (a, b, c) = (line[0], line[1], line[2]);
	let mut ans = 0;
	let arr = vec!['a', 'a', 'b', 'c', 'a', 'c', 'b'];
	for i in 0..7 {
		let (mut a, mut b, mut c) = (a, b, c);
		let week = min(a / 3, min(b / 2, c / 2));
		let mut day = week * 7;
		a -= week * 3;
		b -= week * 2;
		c -= week * 2;
		loop {
			if arr[(i + day as usize) % 7] == 'a' {
				if a == 0 {
					break;
				}
				a -= 1;
			} else if arr[(i + day as usize) % 7] == 'b' {
				if b == 0 {
					break;
				}
				b -= 1;
			} else {
				if c == 0 {
					break;
				}
				c -= 1;
			}
			day += 1;
		}
		ans = max(day, ans);
	}
	println!("{}", ans);
}

#[allow(dead_code)]
fn read<T>() -> T
where
    T: std::str::FromStr,
    T::Err: std::fmt::Debug,
{
    let mut buf = String::new();
    stdin().read_line(&mut buf).unwrap();
    return buf.trim().parse().unwrap();
}

#[allow(dead_code)]
fn read_vector<T>() -> Vec<T>
where
    T: std::str::FromStr,
    T::Err: std::fmt::Debug,
{
    let mut buf = String::with_capacity(100);
    stdin().read_line(&mut buf).unwrap();
    return buf.split_whitespace().map(|s| s.parse().unwrap()).collect();
}

#[allow(dead_code)]
fn read_matrix<T>() -> Vec<Vec<T>>
where
    T: std::str::FromStr,
    T::Err: std::fmt::Debug,
{
    use std::io::prelude::*;
    let stdin = stdin();
    let mut reader = BufReader::with_capacity(100 * 1024, stdin);
    let mut line = String::with_capacity(100);
    let mut matrix: Vec<Vec<T>> = Vec::new();

    while reader.read_line(&mut line).unwrap() > 0 {
        matrix.push(
            line.trim()
                .split_whitespace()
                .map(|s| s.parse().unwrap())
                .collect(),
        );
        line.clear();
    }

    return matrix;
}

#[allow(dead_code)]
fn read_chars() -> Vec<char> {
    let stdin = stdin();
    let mut buf = String::new();
    let _bytes = stdin.read_line(&mut buf).unwrap();
    return buf.trim().chars().collect();
}


#![allow(clippy::many_single_char_names, dead_code, unused_imports, unused_macros, unused_variables)]
#![recursion_limit = "1000"]
use std::{cmp::Reverse, collections::*, fmt::Binary, hash::Hash, io::{stdin, stdout, BufWriter, Read, StdinLock, StdoutLock, Write}, iter::FromIterator, mem::swap, ops::Rem};

macro_rules! parse {
    (check $n: expr, $t: ty) => { std::str::from_utf8_unchecked($n).parse::<$t>().unwrap() };
    ($n: expr, $t: ty) => {
        if cfg!(debug_assertions) {
            parse!(check $n, $t)
        } else {
            #[allow(unused_comparisons)] {
                if <$t>::default()-1 > 0 {
                    parse!(unsigned $n, $t)
                } else {
                    parse!(signed $n, $t)
                }
            }
        }
    };
    (unsigned $n: expr, $t: ty) => {{
        let mut num = 0;

        for d in $n {
            num = num*10 + (*d - b'0') as $t;
        }
        num
    }};
    (signed $n: expr, $t: ty) => {{
        if $n.get_unchecked(0) == &b'-' {
            let mut num = 0;

            for d in &$n[1..] {
                num = num*10 - (*d - b'0') as $t;
            }
            num
        } else {
            parse!(unsigned $n, $t)
        }
    }};
}

macro_rules! read {
    ($r: expr) => { $r.read() };
    ($r: expr, str) => { String::from_utf8_unchecked($r.read().into()) };
    ($r: expr, f32) => { read!(check $r, f32) };
    ($r: expr, f64) => { read!(check $r, f64) };
    (check $r: expr, $t: ty) => {{
        let n = $r.read();
        parse!(check n, $t)
    }};
    ($r: expr, $t: ty) => {{
        let n = $r.read();
        parse!(n, $t)
    }}
}

macro_rules! fill {
    (declare mut $r: expr, $t: ty, $($x: ident),+) => {
        $(
            let mut $x = read!($r, $t);
        )+
    };
    (declare $r: expr, $t: ty, $($x: ident),+) => {
        $(
            let $x = read!($r, $t);
        )+
    };
    ($r: expr, $t: ty, $($x: ident),+) => {
        $(
            $x = read!($r, $t);
        )+
    }
}

macro_rules! read_vec {
    (const $r: expr, $t: ty, $n: expr) => {{
        let mut v = [0; $n];
        for x in &mut v {
            *x = read!($r, $t);
        }
        v
    }};
    (fill $r: expr, $t: ty, $v: expr, $n: expr) => {
        for x in &mut $v[..$n] {
            *x = read!($r, $t);
        }
    };
    ($r: expr, str, $n: expr) => {{
        let mut v = Vec::with_capacity($n);
        for _ in 0..$n {
            v.push(read!($r, str));
            // v.push(String::from_utf8_unchecked(read!($r).into()));
        }
        v
    }};
    ($r: expr, $t: ty, $n: expr) => {{
        let mut v = Vec::with_capacity($n);
        for _ in 0..$n {
            v.push(read!($r, $t));
        }
        v
    }};
    ($r: expr, str) => {{
        let mut v = Vec::with_capacity(10_000);
        loop {
            let (tmp, b) = $r.read_with_lf_check();
            v.push(String::from_utf8_unchecked(tmp.into()));
            if b {
                break v;
            }
        }
    }};
    ($r: expr, $t: ty) => {{
        let mut v = Vec::with_capacity(10_000);
        loop {
            let (tmp, b) = $r.read_with_lf_check();
            v.push(read!($r, $t));
            if b {
                break v;
            }
        }
    }};
    ($r: expr) => { read_vec!($r, str) };
    ($r: expr, $n: expr) => { read_vec!($r, str, $n) };
}

macro_rules! w {
    ($w: expr $(, $args: expr)*) => {
        write!($w $(, $args)*).unwrap();
    };
}

macro_rules! wl {
    ($w: expr $(, $args: expr)*) => {
        writeln!($w $(, $args)*).unwrap();
    };
}

macro_rules! void {
    ($r: expr) => { void!($r, 2); };
    ($r: expr, 1) => {
        $r.cursor += 1;
        loop {
            if $r.buf.get_unchecked($r.cursor) <= &b' ' {
                if $r.cursor >= $r.buf_len {
                    $r.buf_len = $r.stdin.read(&mut $r.buf).unwrap();
                    $r.cursor = 0;
                } else {
                    $r.cursor += 1;
                    $r.reset();
                    break;
                }
            } else {
                $r.cursor += 1;
            }
        }
    };
    ($r: expr, $n: expr) => {
        let mut acc = 0;
        $r.cursor += 1;
        loop {
            if $r.buf.get_unchecked($r.cursor) <= &b' ' {
                if $r.cursor >= $r.buf_len {
                    $r.buf_len = $r.stdin.read(&mut $r.buf).unwrap();
                    $r.cursor = 0;
                } else {
                    acc += 1;
                    $r.cursor += 1;
                    $r.reset();
                    if acc == $n {
                        break;
                    }
                }
            } else {
                $r.cursor += 1;
            }
        }
    };
}

struct Reader<'a>/*'*/ {
    stdin: StdinLock<'a>/*'*/,
    cursor: usize,
    buf_len: usize,
    buf: [u8; BUF_LEN],
    temp_end: usize,
    temp: [u8; 10_000],
}

impl Reader<'_>/*'*/ {
    #[inline]
    unsafe fn read(&mut self) -> &[u8] {
        let init = self.cursor;
        loop {
            if self.buf.get_unchecked(self.cursor) <= &b' ' {
                if self.cursor >= self.buf_len {
                    let s = self.buf_len.saturating_sub(init);

                    let src = self.buf.as_ptr().add(init);
                    let dest = self.temp.as_mut_ptr().add(self.temp_end);
                    std::ptr::copy_nonoverlapping(src, dest, s);

                    self.buf_len = self.stdin.read(&mut self.buf).unwrap();
                    self.temp_end += s;

                    if self.buf_len == 0 {
                        *self.temp.get_unchecked_mut(self.temp_end) = b'\n';
                        return &self.temp[..self.temp_end];
                    }

                    self.cursor = 0;

                    if s == 0 { self.reset(); }
                    return self.read();
                }

                if self.temp_end != 0 {
                    let s = self.cursor - init;
                    let n = self.temp_end + s;

                    let src = self.buf.as_ptr().add(init);
                    let dest = self.temp.as_mut_ptr().add(self.temp_end);
                    std::ptr::copy_nonoverlapping(src, dest, s);
                    *dest.add(s) = b'\n';

                    self.cursor += 1;
                    self.reset();
                    self.temp_end = 0;

                    return &self.temp[..n];
                }

                let t = self.cursor;
                self.cursor += 1;
                self.reset();
                return &self.buf[init..t];
            }
            self.cursor += 1;
        }
    }
    #[inline(always)]
    unsafe fn reset(&mut self) {
        while self.buf.get_unchecked(self.cursor) <= &b' ' {
            self.cursor += 1;
        }
    }
    #[inline(always)]
    unsafe fn read_with_lf_check(&mut self) -> (&[u8], bool) {
        let t = self.read();
        (t, *t.as_ptr().add(t.len()) < b' ')
    }
}

// const BUF_LEN: usize = 1_000_000;
const BUF_LEN: usize = 100_000;
fn main() {
    let stdin = stdin();
    let stdin = stdin.lock();
    let stdout = stdout();
    let stdout = stdout.lock();

    unsafe {
        solve(
            &mut Reader {
                stdin,
                cursor: 0,
                buf_len: 0,
                buf: [0; BUF_LEN],
                temp_end: 0,
                temp: [0; 10_000]
            },
            &mut BufWriter::with_capacity(100_000, stdout),
        );
    }
}

const M: usize = std::usize::MAX;
const REM: usize = 1_000_000_007;

fn bin_pow_rem(mut a: u128, mut b: u128, rem: u128) -> u128 {
    a %= rem;
    let mut res = 1;

    while b != 0 {
        if b&1 == 1 {
            res = res*a%rem;
        }
        a = a*a%rem;
        b >>= 1;
    }
    res
}

#[inline]
unsafe fn solve(r: &mut Reader, w: &mut BufWriter<StdoutLock>) {
    let n = read!(r, u128);
    wl!(w, "{}", bin_pow_rem(4, (1 << n) -2, REM as u128)*6 % REM as u128);
}


#![allow(clippy::many_single_char_names, dead_code, unused_imports, unused_macros, unused_variables)]
#![recursion_limit = "1000"]
use std::{cmp::Reverse, collections::*, fmt::Binary, hash::Hash, io::{stdin, stdout, BufWriter, Read, StdinLock, StdoutLock, Write}, iter::FromIterator, mem::swap, ops::Rem};

macro_rules! parse {
    (check $n: expr, $t: ty) => { std::str::from_utf8_unchecked($n).parse::<$t>().unwrap() };
    ($n: expr, $t: ty) => {
        if cfg!(debug_assertions) {
            parse!(check $n, $t)
        } else {
            #[allow(unused_comparisons)] {
                if <$t>::default()-1 > 0 {
                    parse!(unsigned $n, $t)
                } else {
                    parse!(signed $n, $t)
                }
            }
        }
    };
    (unsigned $n: expr, $t: ty) => {{
        let mut num = 0;

        for d in $n {
            num = num*10 + (*d - b'0') as $t;
        }
        num
    }};
    (signed $n: expr, $t: ty) => {{
        if $n.get_unchecked(0) == &b'-' {
            let mut num = 0;

            for d in &$n[1..] {
                num = num*10 - (*d - b'0') as $t;
            }
            num
        } else {
            parse!(unsigned $n, $t)
        }
    }};
}

macro_rules! read {
    ($r: expr) => { $r.read() };
    ($r: expr, str) => { String::from_utf8_unchecked($r.read().into()) };
    ($r: expr, f32) => { read!(check $r, f32) };
    ($r: expr, f64) => { read!(check $r, f64) };
    (check $r: expr, $t: ty) => {{
        let n = $r.read();
        parse!(check n, $t)
    }};
    ($r: expr, $t: ty) => {{
        let n = $r.read();
        parse!(n, $t)
    }}
}

macro_rules! fill {
    (declare mut $r: expr, $t: ty, $($x: ident),+) => {
        $(
            let mut $x = read!($r, $t);
        )+
    };
    (declare $r: expr, $t: ty, $($x: ident),+) => {
        $(
            let $x = read!($r, $t);
        )+
    };
    ($r: expr, $t: ty, $($x: ident),+) => {
        $(
            $x = read!($r, $t);
        )+
    }
}

macro_rules! read_vec {
    (const $r: expr, $t: ty, $n: expr) => {{
        let mut v = [0; $n];
        for x in &mut v {
            *x = read!($r, $t);
        }
        v
    }};
    (fill $r: expr, $t: ty, $v: expr, $n: expr) => {
        for x in &mut $v[..$n] {
            *x = read!($r, $t);
        }
    };
    ($r: expr, str, $n: expr) => {{
        let mut v = Vec::with_capacity($n);
        for _ in 0..$n {
            v.push(read!($r, str));
            // v.push(String::from_utf8_unchecked(read!($r).into()));
        }
        v
    }};
    ($r: expr, $t: ty, $n: expr) => {{
        let mut v = Vec::with_capacity($n);
        for _ in 0..$n {
            v.push(read!($r, $t));
        }
        v
    }};
    ($r: expr, str) => {{
        let mut v = Vec::with_capacity(10_000);
        loop {
            let (tmp, b) = $r.read_with_lf_check();
            v.push(String::from_utf8_unchecked(tmp.into()));
            if b {
                break v;
            }
        }
    }};
    ($r: expr, $t: ty) => {{
        let mut v = Vec::with_capacity(10_000);
        loop {
            let (tmp, b) = $r.read_with_lf_check();
            v.push(read!($r, $t));
            if b {
                break v;
            }
        }
    }};
    ($r: expr) => { read_vec!($r, str) };
    ($r: expr, $n: expr) => { read_vec!($r, str, $n) };
}

macro_rules! w {
    ($w: expr $(, $args: expr)*) => {
        write!($w $(, $args)*).unwrap();
    };
}

macro_rules! wl {
    ($w: expr $(, $args: expr)*) => {
        writeln!($w $(, $args)*).unwrap();
    };
}

macro_rules! void {
    ($r: expr) => { void!($r, 2); };
    ($r: expr, 1) => {
        $r.cursor += 1;
        loop {
            if $r.buf.get_unchecked($r.cursor) <= &b' ' {
                if $r.cursor >= $r.buf_len {
                    $r.buf_len = $r.stdin.read(&mut $r.buf).unwrap();
                    $r.cursor = 0;
                } else {
                    $r.cursor += 1;
                    $r.reset();
                    break;
                }
            } else {
                $r.cursor += 1;
            }
        }
    };
    ($r: expr, $n: expr) => {
        let mut acc = 0;
        $r.cursor += 1;
        loop {
            if $r.buf.get_unchecked($r.cursor) <= &b' ' {
                if $r.cursor >= $r.buf_len {
                    $r.buf_len = $r.stdin.read(&mut $r.buf).unwrap();
                    $r.cursor = 0;
                } else {
                    acc += 1;
                    $r.cursor += 1;
                    $r.reset();
                    if acc == $n {
                        break;
                    }
                }
            } else {
                $r.cursor += 1;
            }
        }
    };
}

struct Reader<'a>/*'*/ {
    stdin: StdinLock<'a>/*'*/,
    cursor: usize,
    buf_len: usize,
    buf: [u8; BUF_LEN],
    temp_end: usize,
    temp: [u8; 10_000],
}

impl Reader<'_>/*'*/ {
    #[inline]
    unsafe fn read(&mut self) -> &[u8] {
        let init = self.cursor;
        loop {
            if self.buf.get_unchecked(self.cursor) <= &b' ' {
                if self.cursor >= self.buf_len {
                    let s = self.buf_len.saturating_sub(init);

                    let src = self.buf.as_ptr().add(init);
                    let dest = self.temp.as_mut_ptr().add(self.temp_end);
                    std::ptr::copy_nonoverlapping(src, dest, s);

                    self.buf_len = self.stdin.read(&mut self.buf).unwrap();
                    self.temp_end += s;

                    if self.buf_len == 0 {
                        *self.temp.get_unchecked_mut(self.temp_end) = b'\n';
                        return &self.temp[..self.temp_end];
                    }

                    self.cursor = 0;

                    if s == 0 { self.reset(); }
                    return self.read();
                }

                if self.temp_end != 0 {
                    let s = self.cursor - init;
                    let n = self.temp_end + s;

                    let src = self.buf.as_ptr().add(init);
                    let dest = self.temp.as_mut_ptr().add(self.temp_end);
                    std::ptr::copy_nonoverlapping(src, dest, s);
                    *dest.add(s) = b'\n';

                    self.cursor += 1;
                    self.reset();
                    self.temp_end = 0;

                    return &self.temp[..n];
                }

                let t = self.cursor;
                self.cursor += 1;
                self.reset();
                return &self.buf[init..t];
            }
            self.cursor += 1;
        }
    }
    #[inline(always)]
    unsafe fn reset(&mut self) {
        while self.buf.get_unchecked(self.cursor) <= &b' ' {
            self.cursor += 1;
        }
    }
    #[inline(always)]
    unsafe fn read_with_lf_check(&mut self) -> (&[u8], bool) {
        let t = self.read();
        (t, *t.as_ptr().add(t.len()) < b' ')
    }
}

const BUF_LEN: usize = 1_000_000;
fn main() {
    let stdin = stdin();
    let stdin = stdin.lock();
    let stdout = stdout();
    let stdout = stdout.lock();

    unsafe {
        solve(
            &mut Reader {
                stdin,
                cursor: 0,
                buf_len: 0,
                buf: [0; BUF_LEN],
                temp_end: 0,
                temp: [0; 10_000]
            },
            &mut BufWriter::with_capacity(100_000, stdout),
        );
    }
}

const M: usize = std::usize::MAX;
const REM: usize = 1_000_000_007;

fn bin_pow_rem(mut a: u64, mut b: u64, rem: u64) -> u64 {
    a %= rem;
    let mut res = 1;

    while b != 0 {
        if b&1 == 1 {
            res = res*a%rem;
        }
        a = a*a%rem;
        b >>= 1;
    }
    res
}

#[inline]
unsafe fn solve(r: &mut Reader, w: &mut BufWriter<StdoutLock>) {
    let n = read!(r, u64);
    wl!(w, "{}", bin_pow_rem(4, (1 << n) -2, REM as u64)*6 % REM as u64);
}


use std::io::stdin;

fn log2(mut input: u128) -> i32 {
    let mut count = -1;
    while input != 0 {
        input = input >> 1;
        count += 1;
    }
    return count
}
fn main() {
    let stdin = stdin();
    let mut string = String::new();

    stdin.read_line(&mut string).unwrap();

    let n = string.trim().parse::<usize>().unwrap();

    let mut nodes = 2u128.pow(n as u32) - 2;
    let mut re = 1;
    loop {
        let mut inner_re = 4;
        if nodes == 0 {
            break;
        }

        let times = log2(nodes) as u32;
        for _ in 0..times {
            inner_re = inner_re * inner_re;
            if inner_re > (1e9 as u128 + 7) {
                inner_re = inner_re % (1e9 as u128 + 7)
            }
        }

        re = re * inner_re % (1e9 as u128 + 7);
        nodes = nodes - 2u128.pow(times);
    }
    println!("{}", re * 6 % (1e9 as u128 + 7))
}


#![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}};

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;
}

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; while a != 0 { swap(&mut a, &mut b); a %= b; }
                    b
                }
                #[inline] fn highest_one(self) -> Self {
                    if self == 0 { 0 } else { const ONE: $ux = 1; ONE.rotate_right(1) >> self.leading_zeros() }
                }
                #[inline] fn lowest_one(self) -> Self { self & self.wrapping_neg() }
            }

            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, mut b: Self) -> Self {
                    let mut a = self; while a != 0 { swap(&mut a, &mut b); a %= b; }
                    b.abs()
                }
                #[inline] fn highest_one(self) -> Self { (self as $ux).highest_one() as _ }
                #[inline] fn lowest_one(self) -> Self { self & self.wrapping_neg() }
            }
        )*
    }
}
impl_common_num_ext!(i8 = u8, i16 = u16, i32 = u32, i64 = u64, i128 = u128, isize = usize);

trait ChMaxMin<T> {
    fn set_max(&mut self, v: T) -> bool;
    fn set_min(&mut self, v: T) -> bool;
}
impl<T: PartialOrd> ChMaxMin<T> for T {
    fn set_max(&mut self, v: T) -> bool { if v > *self { *self = v; true } else { false } }
    fn set_min(&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 { r.wrapping_add(m) }
    }
    #[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;
    }

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

    #[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(mul_mod_u32(self.val, rhs.into().val, Self::modulus()))
        }
    }
    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 }
            }
            pub type $mint = ModIntBase<$name>;
        }
    }

    macro_rules! dynamic_modulus {
        ($mint: ident, $name: ident, $modulus: ident) => {
            static $modulus: crate::Unsync<Cell<u32>> = crate::Unsync(Cell::new(0));
            #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
            pub enum $name {}
            impl Modulus for $name {
                fn get_modulus() -> u32 { $modulus.0.get() }
            }
            impl $name {
                pub fn set_modulus(val: u32) { $modulus.0.set(val) }
            }
            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;

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

    for _case_num in 1..=num_cases {
        let k = read!(u32);

        let n = (1u64 << k) - 1;
        let ans = mi(4).pow(n-1) * 6;
        println!(ans);
    }

    out_flush();
}