using System; using static System.Console; using System.Linq; using System.Collections.Generic; class Program { static int NN => int.Parse(ReadLine()); static int[] NList => ReadLine().Split().Select(int.Parse).ToArray(); static int[][] NArr(long n) => Enumerable.Repeat(0, (int)n).Select(_ => NList).ToArray(); public static void Main() { Solve(); } static void Solve() { var n = NN; var map = NArr(n); var dic = new Dictionary>(); var w = 2_000_000_001L; for (var i = 0; i < n; ++i) for (var j = i + 1; j < n; ++j) { var cx = map[i][0] + map[j][0]; var cy = map[i][1] + map[j][1]; var key = cx * w + cy; if (!dic.ContainsKey(key)) dic.Add(key, new Dictionary()); var f = new Fraction(map[j][1] - map[i][1], map[j][0] - map[i][0]); if (dic[key].ContainsKey(f)) ++dic[key][f]; else dic[key][f] = 1; } var ans = 0L; foreach (var kv in dic) { foreach (var fkv in kv.Value) { if (fkv.Key.Ch <= 0 && fkv.Key.Pa != 0) continue; var rev = new Fraction(- fkv.Key.Pa, fkv.Key.Ch); if (kv.Value.ContainsKey(rev)) ans += fkv.Value * kv.Value[rev]; } } WriteLine(ans); } class Fraction : IComparable { public static Fraction ERR = new Fraction(1, 0); public static Fraction BASE = new Fraction(0, 1); public long Ch; public long Pa; public Fraction(long ch) { Ch = ch; Pa = 1; } public Fraction(long ch, long pa) { var gcd = GCD(ch, pa); if (pa < 0) gcd = -gcd; Ch = ch / gcd; Pa = pa / gcd; } public Fraction Mul(Fraction b) { var g1 = GCD(Pa, b.Ch); var g2 = GCD(Ch, b.Pa); return new Fraction(Ch / g2 * b.Ch, Pa / g1 * b.Pa); } public Fraction Mul(long b) { return Mul(new Fraction(b, 1)); } public Fraction Div(Fraction b) { return Mul(b.Inv()); } public Fraction Inv() { return new Fraction(Pa, Ch); } public Fraction Add(Fraction b) { var gcd = GCD(Pa, b.Pa); var nc = Ch * (b.Pa / gcd) + b.Ch * (Pa / gcd); var np = Pa / gcd * b.Pa; return new Fraction(nc, np); } public Fraction Add(long b) { return Add(new Fraction(b, 1)); } public Fraction Sub(Fraction b) { return Add(b.Rev()); } public Fraction Rev() { return new Fraction(-Ch, Pa); } long GCD(long a, long b) { a = Math.Abs(a); b = Math.Abs(b); if (a < b) return GCD(b, a); if (b == 0) return a; if (a % b == 0) return b; return GCD(b, a % b); } public int CompareTo(Fraction b) { checked { var left = Ch * b.Pa; var right = Pa * b.Ch; return left.CompareTo(right); } } public override bool Equals(object obj) { var b = (Fraction)obj; return Ch == b.Ch && Pa == b.Pa; } public override int GetHashCode() { return (int)(Ch * 1_000_000_000L % 1_000_000_007 * Pa % 1_000_000_007); } public override string ToString() { return $"{Ch}/{Pa}"; } /// 2点を通る直線 y = ax + b を返す public static (Fraction a, Fraction b) Line(long ax, long ay, long bx, long by) { if (ax == bx) return (Fraction.ERR, new Fraction(- ax)); var s = new Fraction(by - ay, bx - ax); return (s, new Fraction(ay).Add(s.Mul(new Fraction(ax)).Rev())); } /// 2直線の交点を求める 存在しないor無限に存在する場合false public static (bool result, Fraction x, Fraction y) Cross(Fraction a1, Fraction b1, Fraction a2, Fraction b2) { if (a1.Equals(a2)) return (false, Fraction.BASE, Fraction.BASE); if (a1.Equals(Fraction.ERR)) return (true, b1.Rev(), b2); if (a2.Equals(Fraction.ERR)) return (true, b2.Rev(), b1); var x = b2.Sub(b1).Div(a1.Sub(a2)); return (true, x, a1.Mul(x).Add(b1)); } public static Fraction Length2(long ax, long ay, long bx, long by) { return Length2(new Fraction(ax), new Fraction(ay), new Fraction(bx), new Fraction(by)); } public static Fraction Length2(long ax, long ay, Fraction bx, Fraction by) { return Length2(new Fraction(ax), new Fraction(ay), bx, by); } public static Fraction Length2(Fraction ax, Fraction ay, Fraction bx, Fraction by) { var x = ax.Sub(bx); var y = ay.Sub(by); return x.Mul(x).Add(y.Mul(y)); } } }