using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Globalization;

namespace FertiLib.Contest.C
{
	static class Program
	{
		public static void Solve(Scanner cin)
		{
			long n = cin.ReadLong();
			ModInt ans = 1;
			for (int i = 1; i <= n; i++)
			{
				ans *= i;
			}
			ans -= ModInt.Pow(2, n - 1);
			Console.WriteLine(ans);
		}

		public static void Main(string[] args)
		{
			var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
			Console.SetOut(sw);
			var cin = new Scanner();
			Solve(cin);
			Console.Out.Flush();
		}

		public static void YESNO(bool condition) => Console.WriteLine(condition ? "YES" : "NO");
		public static void YesNo(bool condition) => Console.WriteLine(condition ? "Yes" : "No");
		public static void yesno(bool condition) => Console.WriteLine(condition ? "yes" : "no");
	}
	public struct ModInt : IComparable<ModInt>, IEquatable<ModInt>
	{
		public static long MOD = 1000000007;
		public static bool isModPrime { get; set; }

		private readonly long num;

		public ModInt(long n) { num = n; isModPrime = true; }

		public override string ToString() => num.ToString();

		public static ModInt operator +(ModInt l, ModInt r)
		{
			long x = l.num + r.num;
			if (x >= MOD) x -= MOD;
			return new ModInt(x);
		}
		public static ModInt operator -(ModInt l, ModInt r)
		{
			long x = l.num - r.num;
			if (x < 0) x += MOD;
			return new ModInt(x);
		}
		public static ModInt operator *(ModInt l, ModInt r) => new ModInt((l.num * r.num) % MOD);
		public static ModInt operator /(ModInt l, ModInt r) => l * r.Inverse();

		public static ModInt operator ++(ModInt x)
		{
			var tmp = x + new ModInt(1);
			return tmp;
		}
		public static ModInt operator --(ModInt x)
		{
			var tmp = x - new ModInt(1);
			return tmp;
		}

		public static bool operator >(ModInt l, ModInt r) => l.CompareTo(r) > 0;
		public static bool operator <(ModInt l, ModInt r) => l.CompareTo(r) < 0;
		public static bool operator >=(ModInt l, ModInt r) => l.CompareTo(r) >= 0;
		public static bool operator <=(ModInt l, ModInt r) => l.CompareTo(r) <= 0;
		public static bool operator ==(ModInt l, ModInt r) => l.Equals(r);
		public static bool operator !=(ModInt l, ModInt r) => !l.Equals(r);

		public static implicit operator long(ModInt x) => x.num;
		public static implicit operator ModInt(long n)
		{
			n %= MOD;
			if (n < 0) n += MOD;
			return new ModInt(n);
		}

		public ModInt Inverse() => Inverse(this, MOD);
		public static ModInt Inverse(ModInt x) => Inverse(x.num, MOD);
		public static long Inverse(long x, long m)
		{
			if (x % m == 0) throw new DivideByZeroException();
			long a = x, b = m, u = 1, v = 0;
			while (b > 0)
			{
				long t = a / b;

				a -= t * b;
				long p = a; a = b; b = p;   // swap(a, b);

				u -= t * v;
				p = u; u = v; v = p;        // swap(u, v);
			}
			u %= m;
			if (u < 0) u += m;
			return u;
		}

		public static ModInt Pow(long x, long n)
		{
			long now = 1;
			if (isModPrime) n %= MOD - 1;
			for (; n > 0; n /= 2, x = x * x % MOD)
			{
				if (n % 2 == 1) now = now * x % MOD;
			}
			return new ModInt(now);
		}

		public int CompareTo(ModInt x)
		{
			if (num == x.num) return 0;
			if (num > x.num) return 1;
			return -1;
		}

		public bool Equals(ModInt x) => num == x.num;

		public override bool Equals(object obj) => obj is ModInt m && num == m.num;
	}

	static class Util
	{
		public static string Join<T>(this IEnumerable<T> x, string separator = "") => string.Join(separator, x);
	}

	class Printer : StreamWriter
	{
		public override IFormatProvider FormatProvider { get { return CultureInfo.InvariantCulture; } }
		public Printer(Stream stream) : base(stream, new UTF8Encoding(false, true)) { }
		public Printer(Stream stream, Encoding encoding) : base(stream, encoding) { }
	}

	class Scanner
	{
		string[] s;
		int i;

		char[] separator = new char[] { ' ' };

		public Scanner()
		{
			s = new string[0];
			i = 0;
		}

		public string Read() => ReadString();

		public string ReadString()
		{
			if (i < s.Length) return s[i++];
			string st = Console.ReadLine();
			while (st == "") st = Console.ReadLine();
			s = st.Split(separator, StringSplitOptions.RemoveEmptyEntries);
			if (s.Length == 0) return ReadString();
			i = 0;
			return s[i++];
		}

		public string[] ReadStringArray(int N)
		{
			string[] Array = new string[N];
			for (int i = 0; i < N; i++)
			{
				Array[i] = ReadString();
			}
			return Array;
		}

		public int ReadInt()
		{
			return int.Parse(ReadString());
		}

		public int[] ReadIntArray(int N, int add = 0)
		{
			int[] Array = new int[N];
			for (int i = 0; i < N; i++)
			{
				Array[i] = ReadInt() + add;
			}
			return Array;
		}

		public long ReadLong()
		{
			return long.Parse(ReadString());
		}

		public long[] ReadLongArray(int N, long add = 0)
		{
			long[] Array = new long[N];
			for (int i = 0; i < N; i++)
			{
				Array[i] = ReadLong() + add;
			}
			return Array;
		}

		public double ReadDouble()
		{
			return double.Parse(ReadString());
		}

		public double[] ReadDoubleArray(int N, double add = 0)
		{
			double[] Array = new double[N];
			for (int i = 0; i < N; i++)
			{
				Array[i] = ReadDouble() + add;
			}
			return Array;
		}

		public T1 ReadValue<T1>() => (T1)Convert.ChangeType(ReadString(), typeof(T1));

		public (T1, T2) ReadValue<T1, T2>()
		{
			var inputs = ReadStringArray(2);
			var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
			var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
			return (v1, v2);
		}

		public (T1, T2, T3) ReadValue<T1, T2, T3>()
		{
			var inputs = ReadStringArray(3);
			var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
			var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
			var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
			return (v1, v2, v3);
		}

		public (T1, T2, T3, T4) ReadValue<T1, T2, T3, T4>()
		{
			var inputs = ReadStringArray(4);
			var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
			var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
			var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
			var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
			return (v1, v2, v3, v4);
		}

		public (T1, T2, T3, T4, T5) ReadValue<T1, T2, T3, T4, T5>()
		{
			var inputs = ReadStringArray(5);
			var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
			var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
			var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
			var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
			var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5));
			return (v1, v2, v3, v4, v5);
		}

		public (T1, T2, T3, T4, T5, T6) ReadValue<T1, T2, T3, T4, T5, T6>()
		{
			var inputs = ReadStringArray(6);
			var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
			var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
			var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
			var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
			var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5));
			var v6 = (T6)Convert.ChangeType(inputs[5], typeof(T6));
			return (v1, v2, v3, v4, v5, v6);
		}

		public (T1, T2, T3, T4, T5, T6, T7) ReadValue<T1, T2, T3, T4, T5, T6, T7>()
		{
			var inputs = ReadStringArray(7);
			var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
			var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
			var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
			var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
			var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5));
			var v6 = (T6)Convert.ChangeType(inputs[5], typeof(T6));
			var v7 = (T7)Convert.ChangeType(inputs[6], typeof(T7));
			return (v1, v2, v3, v4, v5, v6, v7);
		}

		public T1[] ReadValueArray<T1>(int N)
		{
			var v1 = new T1[N];
			for (int i = 0; i < N; i++)
			{
				v1[i] = ReadValue<T1>();
			}
			return v1;
		}

		public (T1[], T2[]) ReadValueArray<T1, T2>(int N)
		{
			var (v1, v2) = (new T1[N], new T2[N]);
			for (int i = 0; i < N; i++)
			{
				var (t1, t2) = ReadValue<T1, T2>();
				v1[i] = t1;
				v2[i] = t2;
			}
			return (v1, v2);
		}

		public (T1[], T2[], T3[]) ReadValueArray<T1, T2, T3>(int N)
		{
			var (v1, v2, v3) = (new T1[N], new T2[N], new T3[N]);
			for (int i = 0; i < N; i++)
			{
				var (t1, t2, t3) = ReadValue<T1, T2, T3>();
				v1[i] = t1;
				v2[i] = t2;
				v3[i] = t3;
			}
			return (v1, v2, v3);
		}

		public (T1[], T2[], T3[], T4[]) ReadValueArray<T1, T2, T3, T4>(int N)
		{
			var (v1, v2, v3, v4) = (new T1[N], new T2[N], new T3[N], new T4[N]);
			for (int i = 0; i < N; i++)
			{
				var (t1, t2, t3, t4) = ReadValue<T1, T2, T3, T4>();
				v1[i] = t1;
				v2[i] = t2;
				v3[i] = t3;
				v4[i] = t4;
			}
			return (v1, v2, v3, v4);
		}

		public (T1[], T2[], T3[], T4[], T5[]) ReadValueArray<T1, T2, T3, T4, T5>(int N)
		{
			var (v1, v2, v3, v4, v5) = (new T1[N], new T2[N], new T3[N], new T4[N], new T5[N]);
			for (int i = 0; i < N; i++)
			{
				var (t1, t2, t3, t4, t5) = ReadValue<T1, T2, T3, T4, T5>();
				v1[i] = t1;
				v2[i] = t2;
				v3[i] = t3;
				v4[i] = t4;
				v5[i] = t5;
			}
			return (v1, v2, v3, v4, v5);
		}

		public (T1[], T2[], T3[], T4[], T5[], T6[]) ReadValueArray<T1, T2, T3, T4, T5, T6>(int N)
		{
			var (v1, v2, v3, v4, v5, v6) = (new T1[N], new T2[N], new T3[N], new T4[N], new T5[N], new T6[N]);
			for (int i = 0; i < N; i++)
			{
				var (t1, t2, t3, t4, t5, t6) = ReadValue<T1, T2, T3, T4, T5, T6>();
				v1[i] = t1;
				v2[i] = t2;
				v3[i] = t3;
				v4[i] = t4;
				v5[i] = t5;
				v6[i] = t6;
			}
			return (v1, v2, v3, v4, v5, v6);
		}

		public (T1[], T2[], T3[], T4[], T5[], T6[], T7[]) ReadValueArray<T1, T2, T3, T4, T5, T6, T7>(int N)
		{
			var (v1, v2, v3, v4, v5, v6, v7) = (new T1[N], new T2[N], new T3[N], new T4[N], new T5[N], new T6[N], new T7[N]);
			for (int i = 0; i < N; i++)
			{
				var (t1, t2, t3, t4, t5, t6, t7) = ReadValue<T1, T2, T3, T4, T5, T6, T7>();
				v1[i] = t1;
				v2[i] = t2;
				v3[i] = t3;
				v4[i] = t4;
				v5[i] = t5;
				v6[i] = t6;
				v7[i] = t7;
			}
			return (v1, v2, v3, v4, v5, v6, v7);
		}
	}
}

using System;
using CompLib.Mathematics;
using CompLib.Util;

public class Program
{
    private int N;

    public void Solve()
    {
        var sc = new Scanner();
        N = sc.NextInt();

        // N-順列
        // p_iについて
        // j < i p_j > p_i を満たす最大のj
        // i < j           最小のj
        // に辺をつなぐ

        // 閉路があるグラフ
        // 順列の個数

        ModInt a = 1;

        for (int i = 1; i <= N; i++)
        {
            a *= i;
        }

        ModInt b = ModInt.Pow(2, N - 1);

        Console.WriteLine(a - b);
    }

    public static void Main(string[] args) => new Program().Solve();
}

// https://bitbucket.org/camypaper/complib
namespace CompLib.Mathematics
{
    #region ModInt

    /// <summary>
    /// [0,<see cref="Mod"/>) までの値を取るような数
    /// </summary>
    public struct ModInt
    {
        /// <summary>
        /// 剰余を取る値．
        /// </summary>
        public const long Mod = (int) 1e9 + 7;
        // public const long Mod = 998244353;

        /// <summary>
        /// 実際の数値．
        /// </summary>
        public long num;

        /// <summary>
        /// 値が <paramref name="n"/> であるようなインスタンスを構築します．
        /// </summary>
        /// <param name="n">インスタンスが持つ値</param>
        /// <remarks>パフォーマンスの問題上，コンストラクタ内では剰余を取りません．そのため，<paramref name="n"/> ∈ [0,<see cref="Mod"/>) を満たすような <paramref name="n"/> を渡してください．このコンストラクタは O(1) で実行されます．</remarks>
        public ModInt(long n)
        {
            num = n;
        }

        /// <summary>
        /// このインスタンスの数値を文字列に変換します．
        /// </summary>
        /// <returns>[0,<see cref="Mod"/>) の範囲内の整数を 10 進表記したもの．</returns>
        public override string ToString()
        {
            return num.ToString();
        }

        public static ModInt operator +(ModInt l, ModInt r)
        {
            l.num += r.num;
            if (l.num >= Mod) l.num -= Mod;
            return l;
        }

        public static ModInt operator -(ModInt l, ModInt r)
        {
            l.num -= r.num;
            if (l.num < 0) l.num += Mod;
            return l;
        }

        public static ModInt operator *(ModInt l, ModInt r)
        {
            return new ModInt(l.num * r.num % Mod);
        }

        public static implicit operator ModInt(long n)
        {
            n %= Mod;
            if (n < 0) n += Mod;
            return new ModInt(n);
        }

        /// <summary>
        /// 与えられた 2 つの数値からべき剰余を計算します．
        /// </summary>
        /// <param name="v">べき乗の底</param>
        /// <param name="k">べき指数</param>
        /// <returns>繰り返し二乗法により O(N log N) で実行されます．</returns>
        public static ModInt Pow(ModInt v, long k)
        {
            return Pow(v.num, k);
        }

        /// <summary>
        /// 与えられた 2 つの数値からべき剰余を計算します．
        /// </summary>
        /// <param name="v">べき乗の底</param>
        /// <param name="k">べき指数</param>
        /// <returns>繰り返し二乗法により O(N log N) で実行されます．</returns>
        public static ModInt Pow(long v, long k)
        {
            long ret = 1;
            for (k %= Mod - 1; k > 0; k >>= 1, v = v * v % Mod)
                if ((k & 1) == 1)
                    ret = ret * v % Mod;
            return new ModInt(ret);
        }

        /// <summary>
        /// 与えられた数の逆元を計算します．
        /// </summary>
        /// <param name="v">逆元を取る対象となる数</param>
        /// <returns>逆元となるような値</returns>
        /// <remarks>法が素数であることを仮定して，フェルマーの小定理に従って逆元を O(log N) で計算します．</remarks>
        public static ModInt Inverse(ModInt v)
        {
            return Pow(v, Mod - 2);
        }
    }

    #endregion

    #region Binomial Coefficient

    public class BinomialCoefficient
    {
        public ModInt[] fact, ifact;

        public BinomialCoefficient(int n)
        {
            fact = new ModInt[n + 1];
            ifact = new ModInt[n + 1];
            fact[0] = 1;
            for (int i = 1; i <= n; i++)
                fact[i] = fact[i - 1] * i;
            ifact[n] = ModInt.Inverse(fact[n]);
            for (int i = n - 1; i >= 0; i--)
                ifact[i] = ifact[i + 1] * (i + 1);
            ifact[0] = ifact[1];
        }

        public ModInt this[int n, int r]
        {
            get
            {
                if (n < 0 || n >= fact.Length || r < 0 || r > n) return 0;
                return fact[n] * ifact[n - r] * ifact[r];
            }
        }

        public ModInt RepeatedCombination(int n, int k)
        {
            if (k == 0) return 1;
            return this[n + k - 1, k];
        }
    }

    #endregion
}

namespace CompLib.Util
{
    using System;
    using System.Linq;

    class Scanner
    {
        private string[] _line;
        private int _index;
        private const char Separator = ' ';

        public Scanner()
        {
            _line = new string[0];
            _index = 0;
        }

        public string Next()
        {
            if (_index >= _line.Length)
            {
                string s;
                do
                {
                    s = Console.ReadLine();
                } while (s.Length == 0);

                _line = s.Split(Separator);
                _index = 0;
            }

            return _line[_index++];
        }

        public string ReadLine()
        {
            _index = _line.Length;
            return Console.ReadLine();
        }

        public int NextInt() => int.Parse(Next());
        public long NextLong() => long.Parse(Next());
        public double NextDouble() => double.Parse(Next());
        public decimal NextDecimal() => decimal.Parse(Next());
        public char NextChar() => Next()[0];
        public char[] NextCharArray() => Next().ToCharArray();

        public string[] Array()
        {
            string s = Console.ReadLine();
            _line = s.Length == 0 ? new string[0] : s.Split(Separator);
            _index = _line.Length;
            return _line;
        }

        public int[] IntArray() => Array().Select(int.Parse).ToArray();
        public long[] LongArray() => Array().Select(long.Parse).ToArray();
        public double[] DoubleArray() => Array().Select(double.Parse).ToArray();
        public decimal[] DecimalArray() => Array().Select(decimal.Parse).ToArray();
    }
}

using System;
using System.Runtime.InteropServices;

namespace Codeforces {
  class Program {
    static void Main(string[] args) {
      int T;
      T = int.Parse(Console.ReadLine());
      long res = 1;
      long mod = 1000000007;
      for (int i = 1; i <= T; ++i) {
        res *= i;
        if (res > mod) res %= mod;
      }
      long k2 = 1;
      for (int j = 1; j <= T - 1; ++j) {
        k2 *= 2;
        if (k2 > mod) k2 %= mod;
      }
      res -= k2;
      while (res <= 0) {
        res += mod;
      }
      Console.WriteLine(res);
      return;
    }
  }
}

using System;
using System.Runtime.InteropServices;

namespace Codeforces {
  class Program {
    static void Main(string[] args) {
      int T;
      T = int.Parse(Console.ReadLine());
      long res = 1;
      long mod = 1000000007;
      for(int i = 1; i <= T; ++i) {
        res *= i;
        if (res > mod) res %= mod;
      }
      long k2 = 1;
      for(int j = 1; j<= T-1; ++j) {
        k2 *= 2;
        if (k2 > mod) k2 %= mod;
      }
      res -= k2;
      while(res < 0) {
        res += mod;
      }
      Console.WriteLine(res);
      return;
    }
  }
}

using System;
using System.Collections.Generic;
class Program
{
	static void Main(string[] args)
	{
		long N = int.Parse(Console.ReadLine());
		long ans = 1;
		long mod = 1000000007;
		for(var i=1;i<=N;i++){
			ans = ans*i%mod;
		}
		long a2 = 1;
		for(var i=1;i<N;i++){
			a2 = a2 * 2 % mod;
		}
		Console.WriteLine((ans+mod-a2)%mod);
	}
}

using System;

namespace ACM
{
    class Program
    {
        static void Main(string[] args)
        {
            long n = long.Parse(Console.ReadLine());
            long m = (long)1e9 + 7;
            long pre = 2;
            long x = 6;
            for (long i = 4; i <= n; i++)
            {
                long now = pre * i % m + (x + m - pre) % m * ((i + m - 2) % m) % m;
                pre = now % m;
                x *= i;
                x %= m;
            }

            Console.WriteLine(pre);
        }
    }
}

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

class TEST{
	static void Main(){
		Sol mySol =new Sol();
		mySol.Solve();
	}
}

class Sol{
	public void Solve(){

		mlong all = 1;
		for(int i=1;i<=N;i++) all *= i;

		mlong ng = mlong.ModPow(2, N - 1);
		Console.WriteLine(all - ng);

	}
	int N;
	public Sol(){
		N = ri();
	}

	static String rs(){return Console.ReadLine();}
	static int ri(){return int.Parse(Console.ReadLine());}
	static long rl(){return long.Parse(Console.ReadLine());}
	static double rd(){return double.Parse(Console.ReadLine());}
	static String[] rsa(char sep=' '){return Console.ReadLine().Split(sep);}
	static int[] ria(char sep=' '){return Array.ConvertAll(Console.ReadLine().Split(sep),e=>int.Parse(e));}
	static long[] rla(char sep=' '){return Array.ConvertAll(Console.ReadLine().Split(sep),e=>long.Parse(e));}
	static double[] rda(char sep=' '){return Array.ConvertAll(Console.ReadLine().Split(sep),e=>double.Parse(e));}
}

struct mlong {

	const long mod = (long) 1e9 + 7;
	long V;

	public mlong(long _v = 0){
		V = _v;
	}

	public static mlong operator+(mlong a, mlong b){
		var v0 = a.V + b.V; if(v0 >= mod) v0 -= mod;
		return new mlong(v0);
	}
	public static mlong operator-(mlong a, mlong b){
		var v0 = mod + a.V - b.V; if(v0 >= mod) v0 -= mod;
		return new mlong(v0);
	}
	public static mlong operator-(mlong b){
		var v0 = mod - b.V; if(v0 >= mod) v0 -= mod;
		return new mlong(v0);
	}
	public static mlong operator*(mlong a, mlong b){
		var v0 = a.V * b.V; if(v0 >= mod) v0 %= mod;
		return new mlong(v0);
	}
	public static mlong operator/(mlong a, mlong b){
		var v0 = a.V * inv(b.V).V; if(v0 >= mod) v0 %= mod;
		return new mlong(v0);
	}

	public static mlong inv(long x){
		long a = 0, b = 0, c = 0;
		ExtGCD(x, mod, ref a, ref b, ref c);
		return (mlong)((a + mod) % mod);
	}

	public static void ExtGCD(long x, long y, ref long a, ref long b, ref long c){
		long r0 = x; long r1 = y;
		long a0 = 1; long a1 = 0;
		long b0 = 0; long b1 = 1;
		long q1, r2, a2, b2;
		while(r1 > 0){
			q1 = r0 / r1;
			r2 = r0 % r1;
			a2 = a0 - q1 * a1;
			b2 = b0 - q1 * b1;
			r0 = r1; r1 = r2;
			a0 = a1; a1 = a2;
			b0 = b1; b1 = b2;
		}
		c = r0;
		a = a0;
		b = b0;
	}

	public static mlong ModPow(mlong a, long k){
		if(k == 0) return (mlong) 1;
		if(a == 0) return (mlong) 0;
		mlong x = a;
		mlong ret = 1;
		while(k > 0){
			if(k % 2 == 1) ret *= x;
			x *= x;
			k >>= 1;
		}
		return ret;
	}

	public static bool operator == (mlong a, mlong b){
		 return a.Equals(b);
	}
	public static bool operator != (mlong a, mlong b){
		 return !(a == b);
	}

	public override bool Equals(System.Object obj){
		if(obj  ==  null) return false;
		mlong p  =  (mlong) obj;
		if((System.Object) p  ==  null) return false;
		return p.V  ==  V;
	}
	public override int GetHashCode(){
		return V.GetHashCode();
	}

	public static implicit operator mlong(long n){
		long v = n % mod; if(v < 0) v += mod;
		return new mlong(v);
	}
	public static implicit operator mlong(int n){
		long v = n % mod; if(v < 0) v += mod;
		return new mlong(v);
	}
	public static explicit operator long(mlong n){
		return n.V;
	}

	public override String ToString(){
		return V.ToString();
	}

}

namespace Csharp_Contest
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Diagnostics;

    static class Program
    {
        private const long Mod = (long) (1e9 + 7);
        static void Solve()
        {
            long n = NextLong();
            long factorial = n;
            long power = 1;
            for (long i = 1; i < n; i++)
            {
                factorial = (factorial * i) % Mod;
                power = (power * 2) % Mod;
            }

            long ans = factorial - power;
            while (ans < 0)
            {
                ans += Mod;
            }

            ans %= Mod;

            Console.WriteLine(ans);
        }

        public static void Main(string[] args)
        {
#if CLown1331
            for (int testCase = 0; testCase < 3; testCase++)
            {
                Solve();
            }
#else
            if (args.Length == 0)
            {
                Console.SetOut(new Printer(Console.OpenStandardOutput()));
            }

            Thread t = new Thread(Solve, 134217728);
            t.Start();
            t.Join();
            Console.Out.Flush();
#endif
#if CLown1331
            if (Debugger.IsAttached) Thread.Sleep(Timeout.Infinite);
#endif
        }

        static int NextInt() => int.Parse(Console_.NextString());
        static long NextLong() => long.Parse(Console_.NextString());
        static double NextDouble() => double.Parse(Console_.NextString());
        static string NextString() => Console_.NextString();
        static string NextLine() => Console.ReadLine();
        static IEnumerable<T> OrderByRand<T>(this IEnumerable<T> x) => x.OrderBy(_ => xorshift);
        static long Count<T>(this IEnumerable<T> x, Func<T, bool> pred) => Enumerable.Count(x, pred);
        static IEnumerable<T> Repeat<T>(T v, long n) => Enumerable.Repeat<T>(v, (int)n);
        static IEnumerable<int> Range(long s, long c) => Enumerable.Range((int)s, (int)c);
        static uint xorshift { get { _xsi.MoveNext(); return _xsi.Current; } }
        static IEnumerator<uint> _xsi = _xsc();
        static IEnumerator<uint> _xsc() { uint x = 123456789, y = 362436069, z = 521288629, w = (uint)(DateTime.Now.Ticks & 0xffffffff); while (true) { var t = x ^ (x << 11); x = y; y = z; z = w; w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); yield return w; } }

        static class Console_
        {
            static Queue<string> param = new Queue<string>();
            public static string NextString()
            {
                if (param.Count == 0)
                {
                    foreach (string item in NextLine().Split(' '))
                    {
                        param.Enqueue(item);
                    }
                }
                return param.Dequeue();
            }
        }
        class Printer : StreamWriter
        {
            public override IFormatProvider FormatProvider => CultureInfo.InvariantCulture;
            public Printer(Stream stream) : base(stream, new UTF8Encoding(false, true)) { base.AutoFlush = false; }
            public Printer(Stream stream, Encoding encoding) : base(stream, encoding) { base.AutoFlush = false; }
        }
    }
}

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;

// (づ°ω°)づﾐe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    const int MOD = 1000000007;

    public void Solve()
    {
        int n = ReadInt();
        long a = 1, b = 1;
        for (int i = 2; i <= n; i++)
        {
            a = a * i % MOD;
            b = b * 2 % MOD;
        }

        Write((a + MOD - b) % MOD);
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        //reader = new StreamReader(Console.OpenStandardInput());
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("input.txt");
        //writer = new StreamWriter("output.txt");
#endif
        try
        {
            //new Solver().Solve();
            var thread = new Thread(new Solver().Solve, 1024 * 1024 * 128);
            thread.Start();
            thread.Join();
        }
        catch (Exception ex)
        {
#if DEBUG
            Console.WriteLine(ex);
#else
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0) currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++) matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++) ret[i][j] = matrix[j][i]; }
        return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++) lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array) writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++) ret[i] = new T(); return ret; }
    #endregion
}

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using static System.Math;
using System.Text;
using System.Threading;
using System.Globalization;
using System.Runtime.CompilerServices;
using Library;

namespace Program
{
    public static class ProblemC
    {
        static bool SAIKI = false;
        static public int numberOfRandomCases = 0;
        static public void MakeTestCase(List<string> _input, List<string> _output, ref Func<string[], bool> _outputChecker)
        {
        }
        static public void Solve()
        {
            var n = NN;
            LIB_Mod ans = 0;
            for (var i = 3; i <= n; i++)
            {
                ans = ans * 2 + LIB_Mod.Perm(i - 1, i - 1) * (i - 2);
            }
            Console.WriteLine(ans);
        }
        class Printer : StreamWriter
        {
            public override IFormatProvider FormatProvider { get { return CultureInfo.InvariantCulture; } }
            public Printer(Stream stream) : base(stream, new UTF8Encoding(false, true)) { base.AutoFlush = false; }
            public Printer(Stream stream, Encoding encoding) : base(stream, encoding) { base.AutoFlush = false; }
        }
        static LIB_FastIO fastio = new LIB_FastIODebug();
        static public void Main(string[] args) { if (args.Length == 0) { fastio = new LIB_FastIO(); Console.SetOut(new Printer(Console.OpenStandardOutput())); } if (SAIKI) { var t = new Thread(Solve, 134217728); t.Start(); t.Join(); } else Solve(); Console.Out.Flush(); }
        static long NN => fastio.Long();
        static double ND => fastio.Double();
        static string NS => fastio.Scan();
        static long[] NNList(long N) => Repeat(0, N).Select(_ => NN).ToArray();
        static double[] NDList(long N) => Repeat(0, N).Select(_ => ND).ToArray();
        static string[] NSList(long N) => Repeat(0, N).Select(_ => NS).ToArray();
        static long Count<T>(this IEnumerable<T> x, Func<T, bool> pred) => Enumerable.Count(x, pred);
        static IEnumerable<T> Repeat<T>(T v, long n) => Enumerable.Repeat<T>(v, (int)n);
        static IEnumerable<int> Range(long s, long c) => Enumerable.Range((int)s, (int)c);
        static IOrderedEnumerable<T> OrderByRand<T>(this IEnumerable<T> x) => Enumerable.OrderBy(x, _ => xorshift);
        static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> x) => Enumerable.OrderBy(x.OrderByRand(), e => e);
        static IOrderedEnumerable<T1> OrderBy<T1, T2>(this IEnumerable<T1> x, Func<T1, T2> selector) => Enumerable.OrderBy(x.OrderByRand(), selector);
        static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> x) => Enumerable.OrderByDescending(x.OrderByRand(), e => e);
        static IOrderedEnumerable<T1> OrderByDescending<T1, T2>(this IEnumerable<T1> x, Func<T1, T2> selector) => Enumerable.OrderByDescending(x.OrderByRand(), selector);
        static IOrderedEnumerable<string> OrderBy(this IEnumerable<string> x) => x.OrderByRand().OrderBy(e => e, StringComparer.OrdinalIgnoreCase);
        static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> x, Func<T, string> selector) => x.OrderByRand().OrderBy(selector, StringComparer.OrdinalIgnoreCase);
        static IOrderedEnumerable<string> OrderByDescending(this IEnumerable<string> x) => x.OrderByRand().OrderByDescending(e => e, StringComparer.OrdinalIgnoreCase);
        static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> x, Func<T, string> selector) => x.OrderByRand().OrderByDescending(selector, StringComparer.OrdinalIgnoreCase);
        static string Join<T>(this IEnumerable<T> x, string separator = "") => string.Join(separator, x);
        static uint xorshift { get { _xsi.MoveNext(); return _xsi.Current; } }
        static IEnumerator<uint> _xsi = _xsc();
        static IEnumerator<uint> _xsc() { uint x = 123456789, y = 362436069, z = 521288629, w = (uint)(DateTime.Now.Ticks & 0xffffffff); while (true) { var t = x ^ (x << 11); x = y; y = z; z = w; w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); yield return w; } }
    }
}
namespace Library {
    partial struct LIB_Mod : IEquatable<LIB_Mod>, IEquatable<long>
    {
        static public long _mod = 1000000007; long v;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public LIB_Mod(long x)
        {
            if (x < _mod && x >= 0) v = x;
            else if ((v = x % _mod) < 0) v += _mod;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public implicit operator LIB_Mod(long x) => new LIB_Mod(x);
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public implicit operator long(LIB_Mod x) => x.v;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Add(LIB_Mod x) { if ((v += x.v) >= _mod) v -= _mod; }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Sub(LIB_Mod x) { if ((v -= x.v) < 0) v += _mod; }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Mul(LIB_Mod x) => v = (v * x.v) % _mod;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Div(LIB_Mod x) => v = (v * Inverse(x.v)) % _mod;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public LIB_Mod operator +(LIB_Mod x, LIB_Mod y) { var t = x.v + y.v; return t >= _mod ? new LIB_Mod { v = t - _mod } : new LIB_Mod { v = t }; }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public LIB_Mod operator -(LIB_Mod x, LIB_Mod y) { var t = x.v - y.v; return t < 0 ? new LIB_Mod { v = t + _mod } : new LIB_Mod { v = t }; }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public LIB_Mod operator *(LIB_Mod x, LIB_Mod y) => x.v * y.v;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public LIB_Mod operator /(LIB_Mod x, LIB_Mod y) => x.v * Inverse(y.v);
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public bool operator ==(LIB_Mod x, LIB_Mod y) => x.v == y.v;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public bool operator !=(LIB_Mod x, LIB_Mod y) => x.v != y.v;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public long Inverse(long x)
        {
            long b = _mod, r = 1, u = 0, t = 0;
            while (b > 0)
            {
                var q = x / b;
                t = u;
                u = r - q * u;
                r = t;
                t = b;
                b = x - q * b;
                x = t;
            }
            return r < 0 ? r + _mod : r;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool Equals(LIB_Mod x) => v == x.v;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool Equals(long x) => v == x;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override bool Equals(object x) => x == null ? false : Equals((LIB_Mod)x);
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override int GetHashCode() => v.GetHashCode();
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override string ToString() => v.ToString();
        static List<LIB_Mod> _fact = new List<LIB_Mod>() { 1 };
        static long _factm = _mod;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static void B(long n)
        {
            if (_factm != _mod) _fact = new List<LIB_Mod>() { 1 };
            if (n >= _fact.Count)
                for (int i = _fact.Count; i <= n; ++i)
                    _fact.Add(_fact[i - 1] * i);
            _factm = _mod;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public LIB_Mod Comb(long n, long k)
        {
            B(n);
            if (n == 0 && k == 0) return 1;
            if (n < k || n < 0) return 0;
            return _fact[(int)n] / _fact[(int)(n - k)] / _fact[(int)k];
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public LIB_Mod CombOK(long n, long k)
        {
            LIB_Mod ret = 1;
            for (var i = 0; i < k; i++) ret *= n - i;
            for (var i = 1; i <= k; i++) ret /= i;
            return ret;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public LIB_Mod Perm(long n, long k)
        {
            B(n);
            if (n == 0 && k == 0) return 1;
            if (n < k || n < 0) return 0;
            return _fact[(int)n] / _fact[(int)(n - k)];
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public LIB_Mod KanzenPerm(long n) => Enumerable.Range(0, (int)n + 1).Aggregate((LIB_Mod)0, (a, e) => a + (1 - ((e & 1) << 1)) * LIB_Mod.Comb(n, e) * LIB_Mod.Perm(n - e, n - e));
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public LIB_Mod Pow(LIB_Mod x, long y)
        {
            LIB_Mod a = 1;
            while (y != 0)
            {
                if ((y & 1) == 1) a.Mul(x);
                x.Mul(x);
                y >>= 1;
            }
            return a;
        }
    }
    class LIB_FastIO
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public LIB_FastIO() { str = Console.OpenStandardInput(); }
        readonly Stream str;
        readonly byte[] buf = new byte[1024];
        int len, ptr;
        public bool isEof = false;
        public bool IsEndOfStream
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get { return isEof; }
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        byte read()
        {
            if (isEof) throw new EndOfStreamException();
            if (ptr >= len)
            {
                ptr = 0;
                if ((len = str.Read(buf, 0, 1024)) <= 0)
                {
                    isEof = true;
                    return 0;
                }
            }
            return buf[ptr++];
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        char Char()
        {
            byte b = 0;
            do b = read();
            while (b < 33 || 126 < b);
            return (char)b;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        virtual public string Scan()
        {
            var sb = new StringBuilder();
            for (var b = Char(); b >= 33 && b <= 126; b = (char)read())
                sb.Append(b);
            return sb.ToString();
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        virtual public long Long()
        {
            long ret = 0; byte b = 0; var ng = false;
            do b = read();
            while (b != '-' && (b < '0' || '9' < b));
            if (b == '-') { ng = true; b = read(); }
            for (; true; b = read())
            {
                if (b < '0' || '9' < b)
                    return ng ? -ret : ret;
                else ret = ret * 10 + b - '0';
            }
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        virtual public double Double() { return double.Parse(Scan(), CultureInfo.InvariantCulture); }
    }
    class LIB_FastIODebug : LIB_FastIO
    {
        Queue<string> param = new Queue<string>();
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        string NextString() { if (param.Count == 0) foreach (var item in Console.ReadLine().Split(' ')) param.Enqueue(item); return param.Dequeue(); }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public LIB_FastIODebug() { }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override string Scan() => NextString();
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override long Long() => long.Parse(NextString());
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override double Double() => double.Parse(NextString());
    }
}

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using CodeforcesRound663Div2.Extensions;
using CodeforcesRound663Div2.Questions;

namespace CodeforcesRound663Div2.Questions
{
    public class QuestionC : AtCoderQuestionBase
    {
        public override IEnumerable<object> Solve(TextReader inputStream)
        {
            const int Mod = 1000000007;
            var n = inputStream.ReadInt();
            long result = 1;

            for (int i = 1; i <= n; i++)
            {
                result *= i;
                result %= Mod;
            }

            long subtract = 1;

            for (int i = 1; i <= n - 1; i++)
            {
                subtract *= 2;
                subtract %= Mod;
            }

            result = (result + Mod - subtract) % Mod;

            yield return result;
        }
    }
}

namespace CodeforcesRound663Div2
{
    class Program
    {
        static void Main(string[] args)
        {
            IAtCoderQuestion question = new QuestionC();
            var answers = question.Solve(Console.In);

            var writer = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
            Console.SetOut(writer);
            foreach (var answer in answers)
            {
                Console.WriteLine(answer);
            }
            Console.Out.Flush();
        }
    }
}

#region Base Class

namespace CodeforcesRound663Div2.Questions
{

    public interface IAtCoderQuestion
    {
        IEnumerable<object> Solve(string input);
        IEnumerable<object> Solve(TextReader inputStream);
    }

    public abstract class AtCoderQuestionBase : IAtCoderQuestion
    {
        public IEnumerable<object> Solve(string input)
        {
            var stream = new MemoryStream(Encoding.Unicode.GetBytes(input));
            var reader = new StreamReader(stream, Encoding.Unicode);

            return Solve(reader);
        }

        public abstract IEnumerable<object> Solve(TextReader inputStream);
    }
}

#endregion

#region Extensions

namespace CodeforcesRound663Div2.Extensions
{
    public static class StringExtensions
    {
        public static string Join<T>(this IEnumerable<T> source) => string.Concat(source);
        public static string Join<T>(this IEnumerable<T> source, string separator) => string.Join(separator, source);
    }

    public static class TextReaderExtensions
    {
        public static int ReadInt(this TextReader reader) => int.Parse(ReadString(reader));
        public static long ReadLong(this TextReader reader) => long.Parse(ReadString(reader));
        public static double ReadDouble(this TextReader reader) => double.Parse(ReadString(reader));
        public static string ReadString(this TextReader reader) => reader.ReadLine();

        public static int[] ReadIntArray(this TextReader reader, char separator = ' ') => ReadStringArray(reader, separator).Select(int.Parse).ToArray();
        public static long[] ReadLongArray(this TextReader reader, char separator = ' ') => ReadStringArray(reader, separator).Select(long.Parse).ToArray();
        public static double[] ReadDoubleArray(this TextReader reader, char separator = ' ') => ReadStringArray(reader, separator).Select(double.Parse).ToArray();
        public static string[] ReadStringArray(this TextReader reader, char separator = ' ') => reader.ReadLine().Split(separator);

        // Supports primitive type only.
        public static T1 ReadValue<T1>(this TextReader reader) => (T1)Convert.ChangeType(reader.ReadLine(), typeof(T1));

        public static (T1, T2) ReadValue<T1, T2>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            return (v1, v2);
        }

        public static (T1, T2, T3) ReadValue<T1, T2, T3>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            return (v1, v2, v3);
        }

        public static (T1, T2, T3, T4) ReadValue<T1, T2, T3, T4>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
            return (v1, v2, v3, v4);
        }

        public static (T1, T2, T3, T4, T5) ReadValue<T1, T2, T3, T4, T5>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
            var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5));
            return (v1, v2, v3, v4, v5);
        }

        public static (T1, T2, T3, T4, T5, T6) ReadValue<T1, T2, T3, T4, T5, T6>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
            var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5));
            var v6 = (T6)Convert.ChangeType(inputs[5], typeof(T6));
            return (v1, v2, v3, v4, v5, v6);
        }

        public static (T1, T2, T3, T4, T5, T6, T7) ReadValue<T1, T2, T3, T4, T5, T6, T7>(this TextReader reader, char separator = ' ')
        {
            var inputs = ReadStringArray(reader, separator);
            var v1 = (T1)Convert.ChangeType(inputs[0], typeof(T1));
            var v2 = (T2)Convert.ChangeType(inputs[1], typeof(T2));
            var v3 = (T3)Convert.ChangeType(inputs[2], typeof(T3));
            var v4 = (T4)Convert.ChangeType(inputs[3], typeof(T4));
            var v5 = (T5)Convert.ChangeType(inputs[4], typeof(T5));
            var v6 = (T6)Convert.ChangeType(inputs[5], typeof(T6));
            var v7 = (T7)Convert.ChangeType(inputs[6], typeof(T7));
            return (v1, v2, v3, v4, v5, v6, v7);
        }
    }
}

#endregion

using System;
using System.Collections.Generic;
using System.Linq;

namespace ContestTemplateStartUp
{
    class ProgramA_
    {
        public class Heap<TK, TV> where TK : IComparable<TK>
        {
            public bool Any()
            {
                return _list.Any();
            }

            public int Count
            {
                get { return _list.Count; }
            }

            private readonly List<KeyValuePair<TK, TV>> _list = new List<KeyValuePair<TK, TV>>();
            private int GetParentIndex(int index)
            {
                return ((index + 1) / 2) - 1;
            }

            private int? GetLeftChildIndex(int index)
            {
                int result = 2 * (index + 1) - 1;
                return result < _list.Count ? result : (int?)null;
            }

            private int? GetRightChildIndex(int index)
            {
                int result = 2 * (index + 1);
                return result < _list.Count ? result : (int?)null; ;
            }

            public void Insert(TK newValue, TV value)
            {
                _list.Add(new KeyValuePair<TK, TV>(newValue, value));
                SiftUp(_list.Count - 1);
            }
            private void SiftDown(int index)
            {
                var leftChildIndex = GetLeftChildIndex(index);
                var rightChildIndex = GetRightChildIndex(index);

                var leftChild = leftChildIndex.HasValue ? (KeyValuePair<TK, TV>?)_list[leftChildIndex.Value] : null;

                var rightChild = rightChildIndex.HasValue ? (KeyValuePair<TK, TV>?)_list[rightChildIndex.Value] : null;

                var curr = _list[index];

                if (leftChild != null)
                {
                    if (rightChild != null)
                    {
                        if (leftChild.Value.Key.CompareTo(curr.Key) > 0 && leftChild.Value.Key.CompareTo(rightChild.Value.Key) >= 0)
                        {
                            _list[index] = leftChild.Value;
                            _list[leftChildIndex.Value] = curr;
                            SiftDown(leftChildIndex.Value);
                        }
                        else if (rightChild.Value.Key.CompareTo(curr.Key) > 0 && rightChild.Value.Key.CompareTo(leftChild.Value.Key) >= 0)
                        {
                            _list[index] = rightChild.Value;
                            _list[rightChildIndex.Value] = curr;
                            SiftDown(rightChildIndex.Value);
                        }
                    }
                    else
                    {
                        if (leftChild.Value.Key.CompareTo(curr.Key) > 0)
                        {
                            _list[index] = leftChild.Value;
                            _list[leftChildIndex.Value] = curr;
                        }
                    }
                }

            }
            private void SiftUp(int index)
            {
                if (index == 0) return;
                var element = _list[index];
                var parentIndex = GetParentIndex(index);
                var parent = _list[parentIndex];
                if (parent.Key.CompareTo(element.Key) < 0)
                {
                    _list[index] = parent;
                    _list[parentIndex] = element;
                    SiftUp(parentIndex);
                }
            }

            public KeyValuePair<TK, TV> ExtractMax()
            {
                if (_list.Count <= 0) throw new InvalidOperationException();
                var last = GetLast();
                var max = _list[0];
                _list[0] = last;
                _list.RemoveAt(_list.Count - 1);
                if (_list.Any())
                {
                    SiftDown(0);
                }
                return max;
            }

            private KeyValuePair<TK, TV> GetLast()
            {
                return _list[_list.Count - 1];
            }

            public KeyValuePair<TK, TV> GetMax()
            {
                if (_list.Count <= 0) throw new InvalidOperationException();
                var last = GetLast();
                var max = _list[0];
                return max;
            }
        }
        static void Main(string[] args)
        {
            //var results = new List<int>();
            //foreach (var test in Enumerable.Range(0, GetIntFromReadLine()))
            {
                var n = GetInt();
                var nonCyclic = GetPower(2, n - 1);
                var factorial = GetFactorial(n);
                var diff = ((factorial - nonCyclic) + Modulo) % Modulo;

                Console.WriteLine(diff);
                //    Console.WriteLine(result);
                //results.Add(count);
            }

            //foreach (var result in results)
            //{
            //    Console.WriteLine(result);
            //}
        }

        static int dfs(int v, bool[] used, List<int>[] graph, Dictionary<KeyValuePair<int, int>, int> leavesCounts)
        {
            used[v] = true;
            var isLeave = true;
            var sum = 0;
            if (graph[v] != null)
            foreach (var u in graph[v])
            {
                if (!used[u])
                {
                    var leavesCount = dfs(u, used, graph, leavesCounts);
                    sum += leavesCount;
                    leavesCounts[new KeyValuePair<int, int>(v, u)] = leavesCount;
                    isLeave = false;
                }
            }
            if (isLeave)
            {
                return 1;
            }
            else
            {
                return sum;
            }
        }

        private static int Exchange(int[] a, int count, HashSet<int> newSet, HashSet<int> oldSet, int index)
        {
            if (oldSet.Any())
            {
                var subSeqNum = oldSet.First();
                oldSet.Remove(subSeqNum);
                a[index + 1] = subSeqNum;
                newSet.Add(subSeqNum);
            }
            else
            {
                count++;
                var subSeqNum = count;
                a[index + 1] = subSeqNum;
                newSet.Add(subSeqNum);
            }
            return count;
        }

        static void Remove(Dictionary<int, int> stat, int x)
        {
            if (stat[x] == 1)
            {
                stat.Remove(x);
            }
            else
            {
                stat[x] -= 1;
            }
        }

        //static void Main(string[] args)
        //{
        //    var results = new List<long>();
        //    foreach (var test in Enumerable.Range(0, GetIntFromReadLine()))
        //    {
        //        var n = (long)GetInt();
        //        var r = (long)GetInt();
        //        var min = (long)Math.Min(r, n - 1);
        //        var sum = min * (min + 1) / 2L;
        //        if (r >= n)
        //        {
        //            sum += +1;
        //        }
        //        results.Add(sum);
        //    }

        //    foreach (var result in results)
        //    {
        //        Console.WriteLine(result);
        //    }
        //}

        //static void Main(string[] args)
        //{
        //    var results = new List<long>();
        //    foreach (var test in Enumerable.Range(0, GetIntFromReadLine()))
        //    {
        //        var n = GetInt();
        //        results.Add(n - (n/2));
        //    }

        //    foreach (var result in results)
        //    {
        //        Console.WriteLine(result);
        //    }
        //}

        static long lower_bound(int h, int c, int t)
        {
            long l = 1;
            long r = int.MaxValue;
            while (l + 1 < r)
            {
                long mid = (r + l) / 2;
                if (mid * h + (mid - 1) * c >= t * (2 * mid - 1))
                {
                    l = mid;
                }
                else
                {
                    r = mid;
                }
            }
            return r;
        }

        private static int[] GetPrimes(int n)
        {
            var list = new List<int>();
            while (true)
            {
                var del = GetMinDel(n);
                if (del == 1)
                {
                    break;
                }
                list.Add(del);
                n = n / del;
            }
            return list.ToArray();
        }

        private static int GetMinDel(int n)
        {
            for (long index = 2; index * index <= n; ++index)
            {
                if (n % index == 0)
                {
                    return (int)index;
                }
            }
            return n;
        }

        public static bool Success(int[] chet, int[] nechet)
        {
            foreach (var ch in chet)
                foreach (var nch in nechet)
                {
                    if (Math.Abs(ch - nch) == 1)
                    {
                        return true;
                    }
                }
            return false;
        }

        static int GetInt()
        {
            int integer = 0;
            int n = Console.Read();
            while (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1)
                n = Console.Read();
            while (n >= '0' && n <= '9')
            {
                integer = integer * 10 + n - '0';
                n = Console.Read();
            }
            return integer;
        }
        static long GetLong()
        {
            long integer = 0;
            int n = Console.Read();
            while (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1)
                n = Console.Read();
            while (n >= '0' && n <= '9')
            {
                integer = integer * 10 + n - '0';
                n = Console.Read();
            }
            return integer;
        }

        static int[] ReadArray(int count)
        {
            int[] arr = new int[count];
            for (var index = 0; index < count; ++index)
            {
                arr[index] = GetInt();
            }
            return arr;

        }

        static int[] ReadArrayFromReadLine()
        {
            return Console.ReadLine().Split().Select(int.Parse).ToArray();
        }

        static int GetIntFromReadLine()
        {
            return int.Parse(Console.ReadLine());
        }

        public static int GetPower_(int num, int power)
        {
            if (power == 0) return 1;
            if (power == 1) return num;
            var prev = GetPower_(num, power / 2);
            var prev2 = ((long)prev * prev);
            if (power % 2 != 0) return (int)((prev2 * num));
            return (int)prev2;
        }

        public static int Modulo = 1000000007;
        public static int GetPower(int num, int power)
        {
            if (power == 0) return 1;
            if (power == 1) return num % Modulo;
            var prev = GetPower(num, power / 2);
            var prev2 = ((long)prev * prev) % Modulo;
            if (power % 2 != 0) return (int)((prev2 * num) % Modulo);
            return (int)prev2;
        }
        public static long GetFactorial(int num)
        {
            if (num == 0) return 1;
            var res = 1L;
            for (var index = 1; index <= num; ++index)
            {
                res = (res * index) % Modulo;
            }

            return res;
        }

    }
}

//using MetadataExtractor;
//using MetadataExtractor.Formats.Exif;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace CodeForces
{
    public static class MainClass
    {

        static int ReadIntLine()
        {
            return int.Parse(Console.ReadLine());
        }

        static void ReadInt(ref int a)
        {
            a = ReadIntArrayLine()[0];
        }

        static void ReadInts(ref int a, ref int b)
        {
            var x = ReadIntArrayLine();
            a = x[0]; b = x[1];
        }

        static void ReadInts(ref int a, ref int b, ref int c)
        {
            var x = ReadIntArrayLine();
            a = x[0]; b = x[1]; c = x[2];
        }

        static void ReadInts(ref int a, ref int b, ref int c, ref int d)
        {
            var x = ReadIntArrayLine();
            a = x[0]; b = x[1]; c = x[2]; d = x[3];
        }

        static void ReadInts(ref int a, ref int b, ref int c, ref int d, ref int e)
        {
            var x = ReadIntArrayLine();
            a = x[0]; b = x[1]; c = x[2]; d = x[3]; e = x[4];
        }

        static void ReadInts(ref int a, ref int b, ref int c, ref int d, ref int e, ref int f)
        {
            var x = ReadIntArrayLine();
            a = x[0]; b = x[1]; c = x[2]; d = x[3]; e = x[4]; f = x[5];
        }

        static int[] ReadIntArrayLine()
        {
            char[] sep = { ' ' };
            return Console.ReadLine().Split(sep, StringSplitOptions.RemoveEmptyEntries).Select(x => int.Parse(x)).ToArray();
        }

        static void PrintLn(object obj)
        {
            Console.WriteLine(obj.ToString());
        }

        /*public static string Reverse(string s)
        {
            char[] charArray = s.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }*/

        public static void PrintLnCollection<T>(IEnumerable<T> col)
        {
            PrintLn(string.Join(" ", col));
        }

        public static void PrintLn(params object[] v)
        {
            PrintLnCollection(v);
        }

        public static string ReadLine()
        {
            return Console.ReadLine();
        }

        public static string MySubstring(this string str, int start, int finish)
        {
            if (start > finish) return "";
            return str.Substring(start, finish - start + 1);
        }

        public static string Reverse(this string str)
        {
            if (str == null) return null;

            return new string(str.ToArray().Reverse().ToArray());
        }
        public static bool IsInRange(this int a, int lb, int ub)
        {
            return (a >= lb) && (a <= ub);
        }

        private static void mergeDS(int i, int j, int[] a)
        {
            int t = a[j];
            for (int ii = 0; ii < a.Length; ii++)
            {
                if (a[ii] == t)
                    a[ii] = a[i];
            }
        }

        private static T MyMax<T>(params T[] a)
        {
            return a.Max();
        }

        private static T MyMin<T>(params T[] a)
        {
            return a.Min();
        }

        private static int[] GetPrimesLessThan(int x)
        {
            if (x < 2)
                return new int[0];

            int[] a = new int[x];

            a[0] = 1; a[1] = 1;

            for (int i = 0; i < a.Length; i++)
            {
                if (a[i] == 0)
                    for (int j = 2 * i; j < a.Length; j += i)
                    {
                        a[j] = 1;
                    }
            }

            var abc = new List<int>(x);

            for (int i = 0; i < a.Length; i++)
            {
                if (a[i] == 0)
                    abc.Add(i);
            }

            return abc.ToArray();
        }

        private static int FindNearestLEQElementInTheArray(int[] a, int startIndex, int endIndex, int target)
        {
            if (startIndex == endIndex)
            {
                if (a[startIndex] <= target)
                    return startIndex;
                else
                    return -1;
            }

            if (startIndex + 1 == endIndex)
            {
                if (a[endIndex] <= target)
                    return endIndex;
                else if (a[startIndex] <= target)
                    return startIndex;
                else
                    return -1;
            }

            int mid = (startIndex + endIndex) / 2;
            if (target == a[mid])
                return mid;
            else if (target < a[mid])
                return FindNearestLEQElementInTheArray(a, startIndex, mid - 1, target);
            else
                return FindNearestLEQElementInTheArray(a, mid, endIndex, target);
        }

        private static int FindNearestLEQElementInTheArray(int[] a, int target)
        {
            return FindNearestLEQElementInTheArray(a, 0, a.Length - 1, target);
        }

        private static int FindRightMostLEQElementInTheArray(int[] a, int startIndex, int endIndex, int target)
        {
            if (startIndex == endIndex)
            {
                if (a[startIndex] <= target)
                    return startIndex;
                else
                    return -1;
            }

            if (startIndex + 1 == endIndex)
            {
                if (a[endIndex] <= target)
                    return endIndex;
                else if (a[startIndex] <= target)
                    return startIndex;
                else
                    return -1;
            }

            int mid = (startIndex + endIndex) / 2;
            if (target < a[mid])
                return FindRightMostLEQElementInTheArray(a, startIndex, mid - 1, target);
            else
                return FindRightMostLEQElementInTheArray(a, mid, endIndex, target);
        }

        private static int FindRightMostLEQElementInTheArray(int[] a, int target)
        {
            return FindRightMostLEQElementInTheArray(a, 0, a.Length - 1, target);
        }

        private static int gcd(int a, int b)
        {
            int r = a % b;
            while (r != 0)
            {
                a = b;
                b = r;
                r = a % b;
            }
            return b;
        }

        //----------------------------------------------------------------------------

        static string GetSha1(string filePath)
        {
            using (FileStream fs = new FileStream(filePath, FileMode.Open))
            using (BufferedStream bs = new BufferedStream(fs))
            {
                using (SHA1Managed sha1 = new SHA1Managed())
                {
                    byte[] hash = sha1.ComputeHash(bs);
                    StringBuilder formatted = new StringBuilder(2 * hash.Length);
                    foreach (byte b in hash)
                    {
                        formatted.AppendFormat("{0:X2}", b);
                    }

                    return formatted.ToString();
                }
            }
        }

        static bool canFit(int a1, int b1, int a2, int b2)
        {
            int[] r1 = { a1, b1 };
            int[] r2 = { a2, b2 };

            Array.Sort(r1);
            Array.Sort(r2);

            bool ans = (r1[0] <= r2[0]) && (r1[1] <= r2[1]);

            return ans;

        }

        class Pair
        {
            public int first { get; set; }
            public int second { get; set; }
        }

        class Coord
        {
            public int x;
            public int y;
            public double d;
        }

        public static double dist(int x1, int y1, int x2, int y2)
        {
            int dx = x2 - x1;
            int dy = y2 - y1;

            return Math.Sqrt(dx * dx + dy * dy);

        }
        static void Main(string[] args)
        {
            int n = ReadIntLine();

            long pt = 1;
            long P = 1000000000 + 7;
            for (int i = 0; i < n-1; i++)
            {
                pt = (pt * 2) % P;
            }

            long f = 1;
            for (int i = 1; i <= n; i++)
            {
                f = (f * i) % P;
            }

            PrintLn((f - pt + P) % P);

        } //main

    }

}

using System;
using System.Runtime.InteropServices;

namespace Codeforces {

  class Program {
    static void Main(string[] args) {
      //Solution so = new Solution();
      int T;
      T = int.Parse(Console.ReadLine());

      long res = 1;
      long mod = 1000_000_000 + 7;

      for(int i = 1; i <= T; ++i) {
        res *= i;
        if (res > mod) res %= mod;
      }

      long k2 = 1;
      for(int j = 1; j<= T-1; ++j) {
        k2 *= 2;
        if (k2 > mod) k2 %= mod;
      }

      res -= k2;

      while(res <= 0) {
        res += mod;
      }

      Console.WriteLine(res);

      return;
    }
  }
}

using System;
using System.Runtime.InteropServices;

namespace Codeforces {

  class Program {
    static void Main(string[] args) {
      //Solution so = new Solution();
      int T;
      T = int.Parse(Console.ReadLine());

      long res = 1;
      long mod = 1000_000_000 + 7;

      for (int i = 1; i <= T; ++i) {
        res *= i;
        if (res > mod) res %= mod;
      }

      long k2 = 1;
      for (int j = 1; j <= T - 1; ++j) {
        k2 *= 2;
        if (k2 > mod) k2 %= mod;
      }

      res -= k2;

      while (res <= 0) {
        res += mod;
      }

      Console.WriteLine(res);

      return;
    }
  }
}

using System;

namespace Codeforces {
  class Program {
    static void Main(string[] args) {
      int T;
      T = int.Parse(Console.ReadLine());
      long res = 1;
      long mod = 1000_000_007;
      for (int i = 1; i <= T; ++i) {
        res *= i;
        if (res > mod) res %= mod;
      }
      long k2 = 1;
      for (int j = 1; j <= T - 1; ++j) {
        k2 *= 2;
        if (k2 > mod) k2 %= mod;
      }
      res -= k2;
      while (res <= 0) {
        res += mod;
      }
      Console.WriteLine(res);
      Console.WriteLine(mod);
      return;
    }
  }
}