import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.io.OutputStreamWriter;
import java.util.NoSuchElementException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author aryssoncf
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            try {
                int n = in.readInt();
                int[] X1 = new int[n], Y1 = new int[n], X2 = new int[n], Y2 = new int[n];
                in.readIntArrays(X1, Y1, X2, Y2);
                normalize(X1, X2);
                normalize(Y1, Y2);
                int nx = ArrayUtils.compress(X1, X2).length;
                int ny = ArrayUtils.compress(Y1, Y2).length;
                int[] order = ArrayUtils.order(X1);
                ArrayUtils.orderBy(ArrayUtils.reversePermutation(order), X1, Y1, X2, Y2);
                long res = 0;
                FenwickTree ft = new FenwickTree(ny);
                IntList[] rem = new IntList[nx];
                for (int i = 0; i < n; i++) {
                    if (X1[i] == X2[i]) {
                        Arrays.setAll(rem, j -> new IntArrayList());
                        for (int j = 0; j < n; j++) {
                            if (Y1[j] == Y2[j] && X1[i] >= X1[j] && X1[i] <= X2[j] && Y1[j] >= Y1[i] && Y1[j] <= Y2[i]) {
                                ft.add(Y1[j], 1);
                                rem[X2[j]].add(Y1[j]);
                            }
                        }
                        int pos = 0;
                        for (int j = i + 1; j < n; j++) {
                            if (X1[j] == X2[j]) {
                                while (pos < X1[j]) {
                                    for (int k : rem[pos]) {
                                        ft.add(k, -1);
                                    }
                                    pos++;
                                }
                                long c = ft.get(Y1[j], Y2[j]);
                                res += c * (c - 1) / 2;
                            }
                        }
                        while (pos < nx) {
                            for (int k : rem[pos]) {
                                ft.add(k, -1);
                            }
                            pos++;
                        }
                    }
                }
                out.printLine(res);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        void normalize(int[] A, int[] B) {
            for (int i = 0; i < A.length; i++) {
                if (A[i] > B[i]) {
                    int tmp = A[i];
                    A[i] = B[i];
                    B[i] = tmp;
                }
            }
        }

    }

    static class IntArrayList extends IntAbstractStream implements IntList {
        private int size;
        private int[] data;

        public IntArrayList() {
            this(3);
        }

        public IntArrayList(int capacity) {
            data = new int[capacity];
        }

        public IntArrayList(IntCollection c) {
            this(c.size());
            addAll(c);
        }

        public IntArrayList(IntStream c) {
            this();
            if (c instanceof IntCollection) {
                ensureCapacity(((IntCollection) c).size());
            }
            addAll(c);
        }

        public IntArrayList(IntArrayList c) {
            size = c.size();
            data = c.data.clone();
        }

        public IntArrayList(int[] arr) {
            size = arr.length;
            data = arr.clone();
        }

        public int size() {
            return size;
        }

        public int get(int at) {
            if (at >= size) {
                throw new IndexOutOfBoundsException("at = " + at + ", size = " + size);
            }
            return data[at];
        }

        private void ensureCapacity(int capacity) {
            if (data.length >= capacity) {
                return;
            }
            capacity = Math.max(2 * data.length, capacity);
            data = Arrays.copyOf(data, capacity);
        }

        public void addAt(int index, int value) {
            ensureCapacity(size + 1);
            if (index > size || index < 0) {
                throw new IndexOutOfBoundsException("at = " + index + ", size = " + size);
            }
            if (index != size) {
                System.arraycopy(data, index, data, index + 1, size - index);
            }
            data[index] = value;
            size++;
        }

        public void removeAt(int index) {
            if (index >= size || index < 0) {
                throw new IndexOutOfBoundsException("at = " + index + ", size = " + size);
            }
            if (index != size - 1) {
                System.arraycopy(data, index + 1, data, index, size - index - 1);
            }
            size--;
        }

        public void set(int index, int value) {
            if (index >= size) {
                throw new IndexOutOfBoundsException("at = " + index + ", size = " + size);
            }
            data[index] = value;
        }

        public int[] toArray() {
            return Arrays.copyOf(data, size);
        }

    }

    static class IntArray extends IntAbstractStream implements IntList {
        private int[] data;

        public IntArray(int[] arr) {
            data = arr;
        }

        public int size() {
            return data.length;
        }

        public int get(int at) {
            return data[at];
        }

        public void addAt(int index, int value) {
            throw new UnsupportedOperationException();
        }

        public void removeAt(int index) {
            throw new UnsupportedOperationException();
        }

        public void set(int index, int value) {
            data[index] = value;
        }

    }

    static class Sorter {
        private static final int INSERTION_THRESHOLD = 16;

        private Sorter() {
        }

        public static void sort(IntList list, IntComparator comparator) {
            quickSort(list, 0, list.size() - 1, (Integer.bitCount(Integer.highestOneBit(list.size()) - 1) * 5) >> 1,
                    comparator);
        }

        private static void quickSort(IntList list, int from, int to, int remaining, IntComparator comparator) {
            if (to - from < INSERTION_THRESHOLD) {
                insertionSort(list, from, to, comparator);
                return;
            }
            if (remaining == 0) {
                heapSort(list, from, to, comparator);
                return;
            }
            remaining--;
            int pivotIndex = (from + to) >> 1;
            int pivot = list.get(pivotIndex);
            list.swap(pivotIndex, to);
            int storeIndex = from;
            int equalIndex = to;
            for (int i = from; i < equalIndex; i++) {
                int value = comparator.compare(list.get(i), pivot);
                if (value < 0) {
                    list.swap(storeIndex++, i);
                } else if (value == 0) {
                    list.swap(--equalIndex, i--);
                }
            }
            quickSort(list, from, storeIndex - 1, remaining, comparator);
            for (int i = equalIndex; i <= to; i++) {
                list.swap(storeIndex++, i);
            }
            quickSort(list, storeIndex, to, remaining, comparator);
        }

        private static void heapSort(IntList list, int from, int to, IntComparator comparator) {
            for (int i = (to + from - 1) >> 1; i >= from; i--) {
                siftDown(list, i, to, comparator, from);
            }
            for (int i = to; i > from; i--) {
                list.swap(from, i);
                siftDown(list, from, i - 1, comparator, from);
            }
        }

        private static void siftDown(IntList list, int start, int end, IntComparator comparator, int delta) {
            int value = list.get(start);
            while (true) {
                int child = ((start - delta) << 1) + 1 + delta;
                if (child > end) {
                    return;
                }
                int childValue = list.get(child);
                if (child + 1 <= end) {
                    int otherValue = list.get(child + 1);
                    if (comparator.compare(otherValue, childValue) > 0) {
                        child++;
                        childValue = otherValue;
                    }
                }
                if (comparator.compare(value, childValue) >= 0) {
                    return;
                }
                list.swap(start, child);
                start = child;
            }
        }

        private static void insertionSort(IntList list, int from, int to, IntComparator comparator) {
            for (int i = from + 1; i <= to; i++) {
                int value = list.get(i);
                for (int j = i - 1; j >= from; j--) {
                    if (comparator.compare(list.get(j), value) <= 0) {
                        break;
                    }
                    list.swap(j, j + 1);
                }
            }
        }

    }

    static interface IntComparator {
        IntComparator DEFAULT = Integer::compare;

        int compare(int first, int second);

    }

    static interface IntCollection extends IntStream {
        public int size();

        default public void add(int value) {
            throw new UnsupportedOperationException();
        }

        default public int[] toArray() {
            int size = size();
            int[] array = new int[size];
            int i = 0;
            for (IntIterator it = intIterator(); it.isValid(); it.advance()) {
                array[i++] = it.value();
            }
            return array;
        }

        default public IntCollection addAll(IntStream values) {
            for (IntIterator it = values.intIterator(); it.isValid(); it.advance()) {
                add(it.value());
            }
            return this;
        }

    }

    static abstract class IntAbstractStream implements IntStream {
        public String toString() {
            StringBuilder builder = new StringBuilder();
            boolean first = true;
            for (IntIterator it = intIterator(); it.isValid(); it.advance()) {
                if (first) {
                    first = false;
                } else {
                    builder.append(' ');
                }
                builder.append(it.value());
            }
            return builder.toString();
        }

        public boolean equals(Object o) {
            if (!(o instanceof IntStream)) {
                return false;
            }
            IntStream c = (IntStream) o;
            IntIterator it = intIterator();
            IntIterator jt = c.intIterator();
            while (it.isValid() && jt.isValid()) {
                if (it.value() != jt.value()) {
                    return false;
                }
                it.advance();
                jt.advance();
            }
            return !it.isValid() && !jt.isValid();
        }

        public int hashCode() {
            int result = 0;
            for (IntIterator it = intIterator(); it.isValid(); it.advance()) {
                result *= 31;
                result += it.value();
            }
            return result;
        }

    }

    static class ArrayUtils {
        public static int[] range(int from, int to) {
            return Range.range(from, to).toArray();
        }

        public static int[] createOrder(int size) {
            return range(0, size);
        }

        public static int[] sort(int[] array, IntComparator comparator) {
            return sort(array, 0, array.length, comparator);
        }

        public static int[] sort(int[] array, int from, int to, IntComparator comparator) {
            if (from == 0 && to == array.length) {
                new IntArray(array).sort(comparator);
            } else {
                new IntArray(array).subList(from, to).sort(comparator);
            }
            return array;
        }

        public static int[] order(final int[] array) {
            return sort(createOrder(array.length), (first, second) -> Integer.compare(array[first], array[second]));
        }

        public static int[] unique(int[] array) {
            return new IntArray(array).unique().toArray();
        }

        public static int[] reversePermutation(int[] permutation) {
            int[] result = new int[permutation.length];
            for (int i = 0; i < permutation.length; i++) {
                result[permutation[i]] = i;
            }
            return result;
        }

        public static int[] compress(int[]... arrays) {
            int totalLength = 0;
            for (int[] array : arrays) {
                totalLength += array.length;
            }
            int[] all = new int[totalLength];
            int delta = 0;
            for (int[] array : arrays) {
                System.arraycopy(array, 0, all, delta, array.length);
                delta += array.length;
            }
            sort(all, IntComparator.DEFAULT);
            all = unique(all);
            for (int[] array : arrays) {
                for (int i = 0; i < array.length; i++) {
                    array[i] = Arrays.binarySearch(all, array[i]);
                }
            }
            return all;
        }

        public static void orderBy(int[] base, int[]... arrays) {
            int[] order = ArrayUtils.order(base);
            order(order, base);
            for (int[] array : arrays) {
                order(order, array);
            }
        }

        public static void order(int[] order, int[] array) {
            int[] tempInt = new int[order.length];
            for (int i = 0; i < order.length; i++) {
                tempInt[i] = array[order[i]];
            }
            System.arraycopy(tempInt, 0, array, 0, array.length);
        }

    }

    static interface IntStream extends Iterable<Integer>, Comparable<IntStream> {
        IntIterator intIterator();

        default Iterator<Integer> iterator() {
            return new Iterator<Integer>() {
                private IntIterator it = intIterator();

                public boolean hasNext() {
                    return it.isValid();
                }

                public Integer next() {
                    int result = it.value();
                    it.advance();
                    return result;
                }
            };
        }

        default int compareTo(IntStream c) {
            IntIterator it = intIterator();
            IntIterator jt = c.intIterator();
            while (it.isValid() && jt.isValid()) {
                int i = it.value();
                int j = jt.value();
                if (i < j) {
                    return -1;
                } else if (i > j) {
                    return 1;
                }
                it.advance();
                jt.advance();
            }
            if (it.isValid()) {
                return 1;
            }
            if (jt.isValid()) {
                return -1;
            }
            return 0;
        }

    }

    static interface IntReversableCollection extends IntCollection {
    }

    static class FenwickTree {
        private final long[] value;

        public FenwickTree(int size) {
            value = new long[size];
        }

        public FenwickTree(long[] value) {
            this.value = value.clone();
            init();
        }

        void init() {
            for (int i = 0; i < value.length; i++) {
                int j = i | (i + 1);
                if (j < value.length) {
                    value[j] += value[i];
                }
            }
        }

        public long get(int from, int to) {
            if (from > to) {
                return 0;
            }
            return get(to) - get(from - 1);
        }

        private long get(int to) {
            to = Math.min(to, value.length - 1);
            long result = 0;
            while (to >= 0) {
                result += value[to];
                to = (to & (to + 1)) - 1;
            }
            return result;
        }

        public void add(int at, long value) {
            while (at < this.value.length) {
                this.value[at] += value;
                at = at | (at + 1);
            }
        }

    }

    static interface IntIterator {
        public int value() throws NoSuchElementException;

        public boolean advance();

        public boolean isValid();

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void printLine(long i) {
            writer.println(i);
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public void readIntArrays(int[]... arrays) {
            for (int i = 0; i < arrays[0].length; i++) {
                for (int j = 0; j < arrays.length; j++) {
                    arrays[j][i] = readInt();
                }
            }
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            boolean isSpaceChar(int ch);

        }

    }

    static class Range {
        public static IntList range(int from, int to) {
            int[] result = new int[Math.abs(from - to)];
            int current = from;
            if (from <= to) {
                for (int i = 0; i < result.length; i++) {
                    result[i] = current++;
                }
            } else {
                for (int i = 0; i < result.length; i++) {
                    result[i] = current--;
                }
            }
            return new IntArray(result);
        }

    }

    static interface IntList extends IntReversableCollection {
        public abstract int get(int index);

        public abstract void set(int index, int value);

        public abstract void addAt(int index, int value);

        public abstract void removeAt(int index);

        default public void swap(int first, int second) {
            if (first == second) {
                return;
            }
            int temp = get(first);
            set(first, get(second));
            set(second, temp);
        }

        default public IntIterator intIterator() {
            return new IntIterator() {
                private int at;
                private boolean removed;

                public int value() {
                    if (removed) {
                        throw new IllegalStateException();
                    }
                    return get(at);
                }

                public boolean advance() {
                    at++;
                    removed = false;
                    return isValid();
                }

                public boolean isValid() {
                    return !removed && at < size();
                }

                public void remove() {
                    removeAt(at);
                    at--;
                    removed = true;
                }
            };
        }

        default public void add(int value) {
            addAt(size(), value);
        }

        default public IntList sort(IntComparator comparator) {
            Sorter.sort(this, comparator);
            return this;
        }

        default IntList unique() {
            int last = Integer.MIN_VALUE;
            IntList result = new IntArrayList();
            int size = size();
            for (int i = 0; i < size; i++) {
                int current = get(i);
                if (current != last) {
                    result.add(current);
                    last = current;
                }
            }
            return result;
        }

        default public IntList subList(final int from, final int to) {
            return new IntList() {
                private final int shift;
                private final int size;

                {
                    if (from < 0 || from > to || to > IntList.this.size()) {
                        throw new IndexOutOfBoundsException("from = " + from + ", to = " + to + ", size = " + size());
                    }
                    shift = from;
                    size = to - from;
                }

                public int size() {
                    return size;
                }

                public int get(int at) {
                    if (at < 0 || at >= size) {
                        throw new IndexOutOfBoundsException("at = " + at + ", size = " + size());
                    }
                    return IntList.this.get(at + shift);
                }

                public void addAt(int index, int value) {
                    throw new UnsupportedOperationException();
                }

                public void removeAt(int index) {
                    throw new UnsupportedOperationException();
                }

                public void set(int at, int value) {
                    if (at < 0 || at >= size) {
                        throw new IndexOutOfBoundsException("at = " + at + ", size = " + size());
                    }
                    IntList.this.set(at + shift, value);
                }

                public IntList compute() {
                    return new IntArrayList(this);
                }
            };
        }

    }
}


#include<iostream>
#include<cstdio>
#include<algorithm>
//#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>

#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
//const db pi = acos(-1.0);

int n;
struct node{
    int l,r;
    int x;
    node(){}
    node(int a,int b,int c):l(a),r(b),x(c){}
};
vector<node>vt[maxn],hr[maxn];
vector<int>tmp[maxn];
int tree[maxn];
int lowbit(int x){
    return x&-x;
}
void add(int x,int C){
    for(int i=x;i<maxn;i+=lowbit(i)){
        tree[i]+=C;
    }
}
int sum(int x){
    int ans=0;
    for(int i=x;i;i-=lowbit(i)){
        ans+=tree[i];
    }
    return ans;
}
int vis[maxn];
bool cmp(node a, node b){
    return a.x<b.x;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        int x1,y1,x2,y2;
        scanf("%d %d %d %d" ,&x1, &y1, &x2, &y2);
        x1+=5000;x2+=5000;
        y1+=5000;y2+=5000;
        if(x1==x2){
            vt[x1].pb(node(min(y1,y2),max(y1,y2),x1));
        }
        else{
            hr[y1].pb(node(min(x1,x2),max(x1,x2),y1));
            //printf("===%d\n",y1-5000);
        }
    }
    ll ans = 0;
    for(int y = 0; y < maxn; y++){
        for(int i = 0; i < hr[y].size(); i++){
            //for(int j = 0; j < maxn; j++)tmp[j].clear();
            //mem(tree,0);

            node lne = hr[y][i];
            int l = lne.l, r = lne.r;
            for(int x = l; x <= r; x++){
                for(int j = 0; j < (int)vt[x].size(); j++){
                    if(vt[x][j].l<=y&&vt[x][j].r>=y+1){
                        add(x,1);
                        tmp[vt[x][j].r].pb(x);
                    }

                }
            }
            for(int yy = y+1; yy < maxn; yy++){
                for(int j = 0; j < (int)hr[yy].size(); j++){
                    ll res = sum(hr[yy][j].r)-sum(hr[yy][j].l-1);
                    ans+=res*(res-1)/2;
                }
                for(int j = 0; j < (int)tmp[yy].size(); j++){
                    add(tmp[yy][j],-1);
                }
                tmp[yy].clear();
            }

        }
    }
    printf("%lld",ans);
    return 0;
}
/*

 */


#include<iostream>
#include<cstdio>
#include<algorithm>
//#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>

#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e4+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
//const db pi = acos(-1.0);

int n;
struct node{
    int l,r;
    int x;
    node(){}
    node(int a,int b,int c):l(a),r(b),x(c){}
};
vector<node>vt[maxn],hr[maxn];
vector<int>tmp[maxn];
int tree[maxn];
int lowbit(int x){
    return x&-x;
}
void add(int x,int C){
    for(int i=x;i<maxn;i+=lowbit(i)){
        tree[i]+=C;
    }
}
int sum(int x){
    int ans=0;
    for(int i=x;i;i-=lowbit(i)){
        ans+=tree[i];
    }
    return ans;
}
int vis[maxn];
bool cmp(node a, node b){
    return a.x<b.x;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        int x1,y1,x2,y2;
        scanf("%d %d %d %d" ,&x1, &y1, &x2, &y2);
        x1+=5000;x2+=5000;
        y1+=5000;y2+=5000;
        if(x1==x2){
            vt[x1].pb(node(min(y1,y2),max(y1,y2),x1));
        }
        else{
            hr[y1].pb(node(min(x1,x2),max(x1,x2),y1));
            //printf("===%d\n",y1-5000);
        }
    }
    ll ans = 0;
    for(int y = 0; y < maxn; y++){
        for(int i = 0; i < hr[y].size(); i++){
            //for(int j = 0; j < maxn; j++)tmp[j].clear();
            //mem(tree,0);

            node lne = hr[y][i];
            int l = lne.l, r = lne.r;
            for(int x = l; x <= r; x++){
                for(int j = 0; j < (int)vt[x].size(); j++){
                    if(vt[x][j].l<=y&&vt[x][j].r>=y+1){
                        add(x,1);
                        tmp[vt[x][j].r].pb(x);
                    }

                }
            }
            for(int yy = y+1; yy < maxn; yy++){
                for(int j = 0; j < (int)hr[yy].size(); j++){
                    ll res = sum(hr[yy][j].r)-sum(hr[yy][j].l-1);
                    ans+=res*(res-1)/2;
                }
                for(int j = 0; j < (int)tmp[yy].size(); j++){
                    add(tmp[yy][j],-1);
                }
                tmp[yy].clear();
            }

        }
    }
    printf("%lld",ans);
    return 0;
}
/*

 */


#include<iostream>
#include<cstdio>
#include<algorithm>
//#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>

#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e4+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
//const db pi = acos(-1.0);

int n;
struct node{
    int l,r;
    int x;
    node(){}
    node(int a,int b,int c):l(a),r(b),x(c){}
};
vector<node>vt[maxn],hr[maxn];
vector<int>tmp[maxn];
int tree[maxn*10];
int lowbit(int x){
    return x&-x;
}
void add(int x,int C){
    for(int i=x;i<maxn-20;i+=lowbit(i)){
        tree[i]+=C;
    }
}
int sum(int x){
    int ans=0;
    for(int i=x;i;i-=lowbit(i)){
        ans+=tree[i];
    }
    return ans;
}
int vis[maxn];
bool cmp(node a, node b){
    return a.x<b.x;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        int x1,y1,x2,y2;
        scanf("%d %d %d %d" ,&x1, &y1, &x2, &y2);
        x1+=5000;x2+=5000;
        y1+=5000;y2+=5000;
        if(x1==x2){
            vt[x1].pb(node(min(y1,y2),max(y1,y2),x1));
        }
        else{
            hr[y1].pb(node(min(x1,x2),max(x1,x2),y1));
            //printf("===%d\n",y1-5000);
        }
    }
    ll ans = 0;
    for(int y = 0; y < maxn; y++){
        for(int i = 0; i < hr[y].size(); i++){
            //for(int j = 0; j < maxn; j++)tmp[j].clear();
            //mem(tree,0);

            node lne = hr[y][i];
            int l = lne.l, r = lne.r;
            for(int x = l; x <= r; x++){
                for(int j = 0; j < (int)vt[x].size(); j++){
                    if(vt[x][j].l<=y&&vt[x][j].r>=y+1){
                        add(x,1);
                        tmp[vt[x][j].r].pb(x);
                    }

                }
            }
            for(int yy = y+1; yy < maxn; yy++){
                for(int j = 0; j < (int)hr[yy].size(); j++){
                    ll res = sum(hr[yy][j].r)-sum(hr[yy][j].l-1);
                    ans+=res*(res-1)/2;
                }
                for(int j = 0; j < (int)tmp[yy].size(); j++){
                    add(tmp[yy][j],-1);
                }
                tmp[yy].clear();
            }

        }
    }
    printf("%lld",ans);
    return 0;
}
/*

 */


#include <bits/stdc++.h>

using namespace std;

#define mp make_pair

const int N = 10009;
const int INF = 1000000009;

int n;
vector <pair<int, int> > vs[N], hs[N];
int f[N];
vector <int> d[N];

void upd(int pos, int x){
	for(; pos < N; pos |= pos + 1)
		f[pos] += x;
}

int get(int pos){
	int res = 0;
	for(; pos >= 0; pos = (pos & (pos + 1)) - 1)
		res += f[pos];
	return res;
}

int get(int l, int r){
	return get(r) - get(l - 1);
}

const int D = 5000;

int main() {
	cin >> n;
	for(int i = 0; i < n; ++i){
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		x1 += D, y1 += D, x2 += D, y2 += D;
		if(y1 == y2)
			hs[y1].push_back( mp(min(x1, x2), max(x1, x2)) );
		else
			vs[x1].push_back( mp(min(y1, y2), max(y1, y2)) );
	}

	long long res = 0;
	for(int y = 0; y < N; ++y) for(auto s : hs[y]){
		for(int i = 0; i < N; ++i) d[i].clear();

		int l = s.first, r = s.second;
		for(int x = l; x <= r; ++x) for(auto s2 : vs[x])
			if(s2.first <= y && s2.second > y) {
				d[s2.second].push_back(x);
				upd(x, 1);
			}

		for(int y2 = y + 1; y2 < N; ++y2){
			for(auto s2 : hs[y2]){
				int cur = get(s2.first, s2.second);
				res += cur * (cur - 1) / 2;
			}
			for(auto x : d[y2]) upd(x, -1);
		}
	}

	cout << res << endl;
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
//#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>

#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e4+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
//const db pi = acos(-1.0);

int n;
struct node{
    int l,r;
    int x;
    node(){}
    node(int a,int b,int c):l(a),r(b),x(c){}
};
vector<node>vt[maxn],hr[maxn];
vector<int>tmp[maxn];
int tree[maxn*10];
int lowbit(int x){
    return x&-x;
}
void add(int x,int C){
    for(int i=x;i<maxn-20;i+=lowbit(i)){
        tree[i]+=C;
    }
}
int sum(int x){
    int ans=0;
    for(int i=x;i;i-=lowbit(i)){
        ans+=tree[i];
    }
    return ans;
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        int x1,y1,x2,y2;
        scanf("%d %d %d %d" ,&x1, &y1, &x2, &y2);
        x1+=5001;x2+=5001;
        y1+=5001;y2+=5001;
        if(x1==x2){
            vt[x1].pb(node(min(y1,y2),max(y1,y2),x1));
        }
        else{
            hr[y1].pb(node(min(x1,x2),max(x1,x2),y1));
            //printf("===%d\n",y1-5000);
        }
    }
    ll ans = 0;
    for(int y = 0; y < maxn-10; y++){
        for(int i = 0; i < hr[y].size(); i++){
            //for(int j = 0; j < maxn-10; j++)tmp[j].clear();
            //mem(tree,0);

            node lne = hr[y][i];
            int l = lne.l, r = lne.r;
            for(int x = l; x <= r; x++){
                for(int j = 0; j < (int)vt[x].size(); j++){
                    if(vt[x][j].l<=y&&vt[x][j].r>=y+1){
                        add(x,1);
                        tmp[vt[x][j].r].pb(x);
                    }

                }
            }
            for(int yy = y+1; yy < maxn-10; yy++){
                for(int j = 0; j < (int)hr[yy].size(); j++){
                    ll res = sum(hr[yy][j].r)-sum(hr[yy][j].l-1);
                    ans+=res*(res-1)/2;
                }
                for(int j = 0; j < (int)tmp[yy].size(); j++){
                    add(tmp[yy][j],-1);
                }
                tmp[yy].clear();
            }

        }
    }
    printf("%lld",ans);
    return 0;
}
/*

 */


#include<iostream>
#include<cstdio>
#include<algorithm>
//#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>

#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e4+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
//const db pi = acos(-1.0);

int n;
struct node{
    int l,r;
    int x;
    node(){}
    node(int a,int b,int c):l(a),r(b),x(c){}
};
vector<node>vt[maxn],hr[maxn];
vector<int>tmp[maxn];
int tree[maxn*10];
int lowbit(int x){
    return x&-x;
}
void add(int x,int C){
    for(int i=x;i<maxn-20;i+=lowbit(i)){
        tree[i]+=C;
    }
}
int sum(int x){
    int ans=0;
    for(int i=x;i;i-=lowbit(i)){
        ans+=tree[i];
    }
    return ans;
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        int x1,y1,x2,y2;
        scanf("%d %d %d %d" ,&x1, &y1, &x2, &y2);
        x1+=5001;x2+=5001;
        y1+=5001;y2+=5001;
        if(x1==x2){
            vt[x1].pb(node(min(y1,y2),max(y1,y2),x1));
        }
        else{
            hr[y1].pb(node(min(x1,x2),max(x1,x2),y1));
            //printf("===%d\n",y1-5000);
        }
    }
    ll ans = 0;
    for(int y = 0; y < maxn-10; y++){
        for(int i = 0; i < hr[y].size(); i++){
            //for(int j = 0; j < maxn-10; j++)tmp[j].clear();
            mem(tree,0);

            node lne = hr[y][i];
            int l = lne.l, r = lne.r;
            for(int x = l; x <= r; x++){
                for(int j = 0; j < (int)vt[x].size(); j++){
                    if(vt[x][j].l<=y&&vt[x][j].r>=y+1){
                        add(x,1);
                        tmp[vt[x][j].r].pb(x);
                    }

                }
            }
            for(int yy = y+1; yy < maxn-10; yy++){
                for(int j = 0; j < (int)hr[yy].size(); j++){
                    ll res = sum(hr[yy][j].r)-sum(hr[yy][j].l-1);
                    ans+=res*(res-1)/2;
                }
                for(int j = 0; j < (int)tmp[yy].size(); j++){
                    add(tmp[yy][j],-1);
                }
                tmp[yy].clear();
            }

        }
    }
    printf("%lld",ans);
    return 0;
}
/*

 */


#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct event
{
	int t,y, x1,x2;

	event() =default;
	event(int _t,int _y,int _x1,int _x2):
		t(_t), y(_y),x1(_x1),x2(_x2)
	{
		if(x1>x2)swap(x1,x2);
	}

	bool operator < (const event& that)const
	{
		return y==that.y ? t<that.t : y<that.y;
	}
};
#ifndef FENWICK_H
#define FENWICK_H

/*
	Binary indexed tree, Fenwick's.
	Point update, range query

	Eduardo Quintana Miranda
	26-04-2019

	todo:

	recommended problems:
	- 1096F - at codeforces
	- 1167F - at codeforces,
	- 1185F. "Geometers Anonymous Club" at Codeforces
*/

/*
	Keep in mind that Fenwick Tree's range covers [1,N]
*/
template<class T>
class fenwick_tree
{
	const int N;
	std::vector<T> data;
	public:

	fenwick_tree(int n): N(n), data(N+1,0){}

	T query(int i) // i \in [0,N], query(0)=0
	{
		T s=0;
		for(;i>0;i-= i&-i)
			s+=data[i];
		return s;
	}
	void update(int i,T v)
	{
		for(;i<=N and i>0;i+= i&-i)
			data[i]+=v;
	}
	T query(int L,int R)// range covers [L,R)
	{
		return query(R-1)-query(L-1);
	}
};

#endif

int main(){
	__fast_io__;

	int n;cin>>n;

	vector<event> V,H;
	for(int i=0;i<n;++i)
	{
		int  x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;
		if(x1==x2)
			V.push_back({0,x1,y1,y2});
		else
			H.push_back({0,y1,x1,x2});

	}

	sort(V.begin(),V.end());
	sort(H.begin(),H.end());

	const int NX = 5005;
	ll sum=0;
	for(int i=0;i<V.size();++i)
	{
		debug(i,V[i].y,V[i].x1,V[i].x2);
		vector<event> VE;
		fenwick_tree<int> T(2*NX);

		for(int j=i+1;j<V.size();++j)
			VE.push_back({1,V[j].y,V[j].x1,V[j].x2});

		for(int j=0;j<H.size();++j)if(
			V[i].x1<=H[j].y and V[i].x2>=H[j].y and
			H[j].x1<=V[i].y and H[j].x2>=V[i].y )

				VE.push_back({0,H[j].x1,H[j].y,H[j].y}),
				VE.push_back({2,H[j].x2,H[j].y,H[j].y});

		sort(VE.begin(),VE.end());

		for(int j=0;j<VE.size();++j)
		{
			int c=0;
			if(VE[j].t==1)
				c = T.query(VE[j].x1+NX,VE[j].x2+NX+1);
			else if(VE[j].t == 0)
				T.update(VE[j].x1+NX,1);
			else if(VE[j].t == 2)
				T.update(VE[j].x1+NX,-1);

			debug(c);

			sum += (c*(c-1))/2;
		}

	}
	cout << sum << '\n';
	return 0;
}


#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct segment
{
	int x1,x2,y;

	segment() = default;

	segment(int a,int b,int c):
		x1(a),x2(b),y(c)
	{
		if(x1>x2)swap(x1,x2);
	}

	bool operator < (const segment& that)const
	{
		return y<that.y;
	}
};

int main(){
	__fast_io__;

	int n;cin>>n;
	vector<segment> V,H;

	for(int i=0;i<n;++i)
	{
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;

		if(x1==x2)
		{
			//vertical
			V.push_back(segment(y1,y2,x1));

		}
		else
		{
			//horizontal
			H.push_back(segment(x1,x2,y1));
		}
	}

	sort(V.begin(),V.end());
	sort(H.begin(),H.end());

	vector< bitset<5000> > adj(V.size());

	for(int i=0;i<V.size();++i)
	{
		// seek H neighbors of V[i]
		for(int j=0;j<H.size();++j)
			adj[i][j] =
				V[i].x1 <= H[j].y and V[i].x2>=H[j].y and
				H[j].x1 <= V[i].y and H[j].x2>=V[i].y;
	}

	ll sum=0;

	for(int i=0;i<V.size();++i)
	for(int j=i+1;j<V.size();++j)
	{
		int k  = ( adj[i] & adj[j]).count();

		sum += (k*(k-1))/2;
	}

	cout << sum << '\n';

	return 0;
}


#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct event
{
	int t,y, x1,x2;

	event() =default;
	event(int _t,int _y,int _x1,int _x2):
		t(_t), y(_y),x1(_x1),x2(_x2)
	{
		if(x1>x2)swap(x1,x2);
	}

	bool operator < (const event& that)const
	{
		return t==that.t ? y<that.y : t<that.t;
	}
};
#ifndef FENWICK_H
#define FENWICK_H

/*
	Binary indexed tree, Fenwick's.
	Point update, range query

	Eduardo Quintana Miranda
	26-04-2019

	todo:

	recommended problems:
	- 1096F - at codeforces
	- 1167F - at codeforces,
	- 1185F. "Geometers Anonymous Club" at Codeforces
*/

/*
	Keep in mind that Fenwick Tree's range covers [1,N]
*/
template<class T>
class fenwick_tree
{
	const int N;
	std::vector<T> data;
	public:

	fenwick_tree(int n): N(n), data(N+1,0){}

	T query(int i) // i \in [0,N], query(0)=0
	{
		T s=0;
		for(;i>0;i-= i&-i)
			s+=data[i];
		return s;
	}
	void update(int i,T v)
	{
		for(;i<=N and i>0;i+= i&-i)
			data[i]+=v;
	}
	T query(int L,int R)// range covers [L,R)
	{
		return query(R-1)-query(L-1);
	}
};

#endif

int main(){
	__fast_io__;

	int n;cin>>n;

	vector<event> V,H;
	for(int i=0;i<n;++i)
	{
		int  x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;
		if(x1==x2)
			V.push_back({0,x1,y1,y2});
		else
			H.push_back({0,y1,x1,x2});

	}

	sort(V.begin(),V.end());
	sort(H.begin(),H.end());

	const int NX = 5005;
	ll sum=0;
	for(int i=0;i<V.size();++i)
	{
		debug(i,V[i].y,V[i].x1,V[i].x2);
		vector<event> VE;
		fenwick_tree<int> T(2*NX);

		for(int j=i+1;j<V.size();++j)
			VE.push_back({1,V[j].y,V[j].x1,V[j].x2});

		for(int j=0;j<H.size();++j)if(
			V[i].x1<=H[j].y and V[i].x2>=H[j].y and
			H[j].x1<=V[i].y and H[j].x2>=V[i].y )

				VE.push_back({0,H[j].x1,H[j].y,H[j].y}),
				VE.push_back({2,H[j].x2,H[j].y,H[j].y});

		sort(VE.begin(),VE.end());

		for(int j=0;j<VE.size();++j)
		{
			int c=0;
			if(VE[j].t==1)
				c = T.query(VE[j].x1+NX,VE[j].x2+NX+1);
			else if(VE[j].t == 0)
				T.update(VE[j].x1+NX,1);
			else if(VE[j].t == 2)
				T.update(VE[j].x1+NX,-1);

			debug(c);

			sum += (c*(c-1))/2;
		}

	}
	cout << sum << '\n';
	return 0;
}


#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct segment
{
	int x1,x2,y;

	segment() = default;

	segment(int a,int b,int c):
		x1(a),x2(b),y(c)
	{
		if(x1>x2)swap(x1,x2);
	}

	bool operator < (const segment& that)const
	{
		return y<that.y;
	}
};

const int NB=79;
struct bs
{
	array<unsigned long long,NB> data;
	bs()
	{
		fill(data.begin(),data.end(),0);
	}

	bs operator & (const bs& that)const
	{
		bs t;
		for(int i=0;i<NB;++i)
			t.data[i]=data[i]&that.data[i];
		return t;
	}

	void set(int i,bool t)
	{
		int j=i/64; i%=64;
		if (t) data[j] |= (1ULL<<i);
		else data[j] &= ~(1ULL<<i);
	}

	int count()
	{
		int r=0;
		for(auto l: data) r+=__builtin_popcountll(l);
		return r;
	}
};

int and_count(const bs& a,const bs& b)
{
	int r=0;
	unsigned long long t;
	for(int i=0;i<NB;++i)
	{
		r+=__builtin_popcountll(a.data[i]&b.data[i]);
	}
	return r;
}

int main(){
	__fast_io__;

	int n;cin>>n;
	vector<segment> V,H;

	for(int i=0;i<n;++i)
	{
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;

		if(x1==x2)
		{
			//vertical
			V.push_back(segment(y1,y2,x1));

		}
		else
		{
			//horizontal
			H.push_back(segment(x1,x2,y1));
		}
	}

	sort(V.begin(),V.end());
	sort(H.begin(),H.end());

	vector< bs > adj(V.size());

	for(int i=0;i<V.size();++i)
	{
		// seek H neighbors of V[i]
		for(int j=0;j<H.size();++j)
			adj[i].set( j,
				V[i].x1 <= H[j].y and V[i].x2>=H[j].y and
				H[j].x1 <= V[i].y and H[j].x2>=V[i].y );
	}

	ll sum=0;

	for(int i=0;i<V.size();++i)
	for(int j=i+1;j<V.size();++j)
	{
		int k  = and_count(adj[i],adj[j]);

		sum += (k*(k-1))/2;
	}

	cout << sum << '\n';

	return 0;
}


#pragma GCC optimize("O3", "unroll-loops")
#pragma GCC target("avx2")
#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct segment
{
	int x1,x2,y;

	segment() = default;

	segment(int a,int b,int c):
		x1(a),x2(b),y(c)
	{
		if(x1>x2)swap(x1,x2);
	}

	bool operator < (const segment& that)const
	{
		return y<that.y;
	}
};

int main(){
	__fast_io__;

	int n;cin>>n;
	vector<segment> V,H;

	for(int i=0;i<n;++i)
	{
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;

		if(x1==x2)
		{
			//vertical
			V.push_back(segment(y1,y2,x1));

		}
		else
		{
			//horizontal
			H.push_back(segment(x1,x2,y1));
		}
	}

	vector< bitset<5000> > adj(V.size());

	for(int i=0;i<V.size();++i)
	{
		// seek H neighbors of V[i]
		for(int j=0;j<H.size();++j)
			adj[i][j] =
				V[i].x1 <= H[j].y and V[i].x2>=H[j].y and
				H[j].x1 <= V[i].y and H[j].x2>=V[i].y;
	}

	ll sum=0;

	for(int i=0;i<V.size();++i)
	for(int j=i+1;j<V.size();++j)
	{
		int k  = ( adj[i] & adj[j]).count();

		sum += (k*(k-1))/2;
	}

	cout << sum << '\n';

	return 0;
}


#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct segment
{
	int x1,x2,y;

	segment() = default;

	segment(int a,int b,int c):
		x1(a),x2(b),y(c)
	{
		if(x1>x2)swap(x1,x2);
	}

	bool operator < (const segment& that)const
	{
		return y<that.y;
	}
};

const int NB=79;
struct bs
{
	array<unsigned long long,NB> data;
	bs()
	{
		fill(data.begin(),data.end(),0);
	}

	bs operator & (const bs& that)const
	{
		bs t;
		for(int i=0;i<NB;++i)
			t.data[i]=data[i]&that.data[i];
		return t;
	}

	void set(int i,bool t)
	{
		int j=i/64; i%=64;
		if (t) data[j] |= (1ULL<<i);
		else data[j] &= ~(1ULL<<i);
	}

	int count()
	{
		int r=0;
		for(auto l: data) r+=__builtin_popcountll(l);
		return r;
	}
};

int main(){
	__fast_io__;

	int n;cin>>n;
	vector<segment> V,H;

	for(int i=0;i<n;++i)
	{
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;

		if(x1==x2)
		{
			//vertical
			V.push_back(segment(y1,y2,x1));

		}
		else
		{
			//horizontal
			H.push_back(segment(x1,x2,y1));
		}
	}

	sort(V.begin(),V.end());
	sort(H.begin(),H.end());

	vector< bs > adj(V.size());

	for(int i=0;i<V.size();++i)
	{
		// seek H neighbors of V[i]
		for(int j=0;j<H.size();++j)
			adj[i].set( j,
				V[i].x1 <= H[j].y and V[i].x2>=H[j].y and
				H[j].x1 <= V[i].y and H[j].x2>=V[i].y );
	}

	ll sum=0;

	for(int i=0;i<V.size();++i)
	for(int j=i+1;j<V.size();++j)
	{
		int k  = ( adj[i] & adj[j]).count();

		sum += (k*(k-1))/2;
	}

	cout << sum << '\n';

	return 0;
}


#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct segment
{
	int x1,x2,y;

	segment() = default;

	segment(int a,int b,int c):
		x1(a),x2(b),y(c)
	{
		if(x1>x2)swap(x1,x2);
	}

};

int main(){
	__fast_io__;

	int n;cin>>n;
	vector<segment> V,H;

	for(int i=0;i<n;++i)
	{
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;

		if(x1==x2)
		{
			//vertical
			V.push_back(segment(y1,y2,x1));

		}
		else
		{
			//horizontal
			H.push_back(segment(x1,x2,y1));
		}
	}

	vector< bitset<5000> > adj(V.size());

	for(int i=0;i<V.size();++i)
	{
		// seek H neighbors of V[i]
		for(int j=0;j<H.size();++j)
			adj[i][j] =
				V[i].x1 <= H[j].y and V[i].x2>=H[j].y and
				H[j].x1 <= V[i].y and H[j].x2>=V[i].y;
	}

	ll sum=0;

	for(int i=0;i<V.size();++i)
	for(int j=i+1;j<V.size();++j)
	{
		int k  = ( adj[i] & adj[j]).count();

		sum += (k*(k-1))/2;
	}

	cout << sum << '\n';

	return 0;
}


#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct segment
{
	int x1,x2,y;

	segment() = default;

	segment(int a,int b,int c):
		x1(a),x2(b),y(c)
	{
		if(x1>x2)swap(x1,x2);
	}

	bool operator < (const segment& that)const
	{
		return y<that.y;
	}
};

int main(){
	__fast_io__;

	int n;cin>>n;
	vector<segment> V,H;

	for(int i=0;i<n;++i)
	{
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;

		if(x1==x2)
		{
			//vertical
			V.push_back(segment(y1,y2,x1));

		}
		else
		{
			//horizontal
			H.push_back(segment(x1,x2,y1));
		}
	}

	//sort(V.begin(),V.end());
	//sort(H.begin(),H.end());

	vector< bitset<5000> > adj(V.size());

	for(int i=0;i<V.size();++i)
	{
		// seek H neighbors of V[i]
		for(int j=0;j<H.size();++j)
			adj[i][j] =
				V[i].x1 <= H[j].y and V[i].x2>=H[j].y and
				H[j].x1 <= V[i].y and H[j].x2>=V[i].y;
	}

	ll sum=0;

	for(int i=0;i<V.size();++i)
	for(int j=i+1;j<V.size();++j)
	{
		int k  = ( adj[i] & adj[j]).count();

		sum += (k*(k-1))/2;
	}

	cout << sum << '\n';

	return 0;
}


#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct segment
{
	int x1,x2,y;

	segment() = default;

	segment(int a,int b,int c):
		x1(a),x2(b),y(c)
	{
		if(x1>x2)swap(x1,x2);
	}

	bool operator < (const segment& that)const
	{
		return y<that.y;
	}
};

int main(){
	__fast_io__;

	int n;cin>>n;
	vector<segment> V,H;

	for(int i=0;i<n;++i)
	{
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;

		if(x1==x2)
		{
			//vertical
			V.push_back(segment(y1,y2,x1));

		}
		else
		{
			//horizontal
			H.push_back(segment(x1,x2,y1));
		}
	}

	vector< bitset<5000> > adj(V.size());

	for(int i=0;i<V.size();++i)
	{
		// seek H neighbors of V[i]
		for(int j=0;j<H.size();++j)
			adj[i][j] =
				V[i].x1 <= H[j].y and V[i].x2>=H[j].y and
				H[j].x1 <= V[i].y and H[j].x2>=V[i].y;
	}

	int nv=V.size();
	ll sum=0;

	for(int i=0;i<nv;++i)
	for(int j=i+1;j<nv;++j)
	{
		int k  = ( adj[i] & adj[j]).count();

		sum += (k*(k-1))/2;
	}

	cout << sum << '\n';

	return 0;
}


#include<bits/stdc++.h>

#ifdef lagrang3_DEBUG
#include "../include/debug.h"
#else
#define debug(...)
#endif

#define __fast_io__ \
	std::ios_base::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

#define get_max(a,b) a=std::max(a,b)
#define get_min(a,b) a=std::min(a,b)

template<class T> T read(std::istream& is){T x; return is>>x,x;}
template<class T> T read(){T x; return std::cin>>x,x;}

typedef long long ll;
typedef long double ld;

const int oo=0x7fffffff;
const ll  OO=0x7fffffffffffffff;

using namespace std;

struct segment
{
	int x1,x2,y;

	segment() = default;

	segment(int a,int b,int c):
		x1(a),x2(b),y(c)
	{
		if(x1>x2)swap(x1,x2);
	}

	bool operator < (const segment& that)const
	{
		return y<that.y;
	}
};

const int NB=79;
struct bs
{
	array<unsigned long long,NB> data;
	bs()
	{
		fill(data.begin(),data.end(),0);
	}

	bs operator & (const bs& that)const
	{
		bs t;
		for(int i=0;i<NB;++i)
			t.data[i]=data[i]&that.data[i];
		return t;
	}

	void set(int i,bool t)
	{
		int j=i/64; i%=64;
		if (t) data[j] |= (1ULL<<i);
		else data[j] &= ~(1ULL<<i);
	}

	int count()
	{
		int r=0;
		for(auto l: data) r+=__builtin_popcountll(l);
		return r;
	}
};

int and_count(const bs& a,const bs& b)
{
	int r=0;
	unsigned long long t;
	for(int i=0;i<NB;++i)
	{
		r+=__builtin_popcountll(a.data[i]&b.data[i]);
	}
	return r;
}

int main(){
	__fast_io__;

	int n;cin>>n;
	vector<segment> V,H;

	for(int i=0;i<n;++i)
	{
		int x1,x2,y1,y2;
		cin>>x1>>y1>>x2>>y2;

		if(x1==x2)
		{
			//vertical
			V.push_back(segment(y1,y2,x1));

		}
		else
		{
			//horizontal
			H.push_back(segment(x1,x2,y1));
		}
	}

	sort(V.begin(),V.end());
	sort(H.begin(),H.end());

	vector< bs > adj(V.size());

	for(int i=0;i<V.size();++i)
	{
		// seek H neighbors of V[i]
		for(int j=0;j<H.size();++j)
			adj[i].set( j,
				V[i].x1 <= H[j].y and V[i].x2>=H[j].y and
				H[j].x1 <= V[i].y and H[j].x2>=V[i].y );
	}

	ll sum=0;

	for(int i=0;i<V.size();++i)
	for(int j=i+1;j<V.size();++j)
	{
		int k  = 0;
		for(int b=0;b<NB;++b)
			k += __builtin_popcountll(adj[i].data[b] & adj[j].data[b]);
		sum += (k*(k-1))/2;
	}

	cout << sum << '\n';

	return 0;
}


#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#define INF 0x3f3f3f3f
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;

const int mod = 1e9 + 7;
const int maxn = 5e3 + 5;

struct Horizontal {
    int y, x1, x2;
    Horizontal(){}
    Horizontal(int p, int x1, int x2) : y(p), x1(x1), x2(x2){}
    bool operator < (const Horizontal &b) const {
        return y < b.y;
    }
};
struct Vertical {
    int x, y1, y2;
    Vertical(){}
    Vertical(int p, int y1, int y2) : x(p), y1(y1), y2(y2) {}
    bool operator < (const Vertical &b) const {
        return y2 < b.y2;
    }
};
int ch, cv;
Horizontal h[maxn];
Vertical v[maxn];
int temp[maxn * 2], cnt = 1, m;

ll tree[maxn * 2];
void add(int x, int in) {
    while(x <= m) {
        tree[x] += in;
        x += x & -x;
    }
}
ll query(int x) {
    ll re = 1;
    while(x > 0) {
        re += tree[x];
        x -= x & -x;
    }
    return re;
}

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        int x1, x2, y1, y2;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        if(x1 == x2) {
            v[cv++] = Vertical(x1, min(y1, y2), max(y1, y2));
        } else if(y1 == y2) {
            h[ch++] = Horizontal(y1, min(x1, x2), max(x1, x2));
        }
        temp[cnt++] = x1, temp[cnt++] = x2;
    }
    sort(temp + 1, temp + cnt);
    m = unique(temp + 1, temp + cnt) - temp;

    for(int i = 0; i < ch; ++i) {
        h[i].x1 = lower_bound(temp + 1, temp + m, h[i].x1) - temp;
        h[i].x2 = lower_bound(temp + 1, temp + m, h[i].x2) - temp;
    }
    for(int i = 0; i < cv; ++i) {
        v[i].x = lower_bound(temp + 1, temp + m, v[i].x) - temp;
    }

    ll ans = 0;
    sort(h, h + ch);
    sort(v, v + cv);
    for(int i = 0; i < ch; ++i) {
        memset(tree, 0, sizeof(tree));
        int c = cv - 1;
        for(; c >= 0; --c) {
            if(h[i].y <= v[c].y2 && h[i].y >= v[c].y1) {
                add(v[c].x, 1);
            }
            if(h[c].y > v[c].y2)
                break;
        }
        if(c < 0)
            c = 0;

        for(int j = i + 1; j < ch; ++j) {
            if(h[i].y == h[j].y)
                continue;
            while(c < cv && v[c].y2 < h[j].y) {
                add(v[c].x, -1);
                ++c;
            }
            int l, r;
            l = max(h[i].x1, h[j].x1);
            r = min(h[i].x2, h[j].x2);
            ll add = query(r) - query(l - 1);
            ans += add * (add - 1) / 2;
        }
    }
    printf("%lld\n", ans);
}


#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#define INF 0x3f3f3f3f
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;

const int mod = 1e9 + 7;
const int maxn = 5e3 + 5;

struct Horizontal {
    int y, x1, x2;
    Horizontal(){}
    Horizontal(int p, int x1, int x2) : y(p), x1(x1), x2(x2){}
    bool operator < (const Horizontal &b) const {
        return y < b.y;
    }
};
struct Vertical {
    int x, y1, y2;
    Vertical(){}
    Vertical(int p, int y1, int y2) : x(p), y1(y1), y2(y2) {}
    bool operator < (const Vertical &b) const {
        return y2 < b.y2;
    }
};
int ch, cv;
Horizontal h[maxn];
Vertical v[maxn];
bool vis[maxn];
int temp[maxn * 2], cnt = 1, m;

ll tree[maxn * 2];
void add(int x, int in) {
    while(x <= m) {
        tree[x] += in;
        x += x & -x;
    }
}
ll query(int x) {
    ll re = 1;
    while(x > 0) {
        re += tree[x];
        x -= x & -x;
    }
    return re;
}

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        int x1, x2, y1, y2;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        if(x1 == x2) {
            v[cv++] = Vertical(x1, min(y1, y2), max(y1, y2));
        } else if(y1 == y2) {
            h[ch++] = Horizontal(y1, min(x1, x2), max(x1, x2));
        }
        temp[cnt++] = x1, temp[cnt++] = x2;
    }
    sort(temp + 1, temp + cnt);
    m = unique(temp + 1, temp + cnt) - temp;

    for(int i = 0; i < ch; ++i) {
        h[i].x1 = lower_bound(temp + 1, temp + m, h[i].x1) - temp;
        h[i].x2 = lower_bound(temp + 1, temp + m, h[i].x2) - temp;
    }
    for(int i = 0; i < cv; ++i) {
        v[i].x = lower_bound(temp + 1, temp + m, v[i].x) - temp;
    }

    ll ans = 0;
    sort(h, h + ch);
    sort(v, v + cv);
    for(int i = 0; i < ch; ++i) {
        memset(tree, 0, sizeof(tree));
        memset(vis, 0, sizeof(vis));
        int c = cv - 1;
        for(; c >= 0; --c) {
            if(h[i].y <= v[c].y2 && h[i].y >= v[c].y1) {
                add(v[c].x, 1);
                vis[c] = 1;
            }
            if(h[c].y > v[c].y2)
                break;
        }
        if(c < 0)
            c = 0;

        for(int j = i + 1; j < ch; ++j) {
            if(h[i].y == h[j].y)
                continue;
            while(c < cv && v[c].y2 < h[j].y) {
                if(vis[c]) {
                    add(v[c].x, -1);
                    vis[c] = 0;
                }
                ++c;
            }
            int l, r;
            l = max(h[i].x1, h[j].x1);
            r = min(h[i].x2, h[j].x2);
            ll add = query(r) - query(l - 1);
            ans += add * (add - 1) / 2;
        }
    }
    printf("%lld\n", ans);
}


#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#define INF 0x3f3f3f3f
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;

const int mod = 1e9 + 7;
const int maxn = 5e3 + 5;

struct Horizontal {
    int y, x1, x2;
    Horizontal(){}
    Horizontal(int p, int x1, int x2) : y(p), x1(x1), x2(x2){}
    bool operator < (const Horizontal &b) const {
        return y < b.y;
    }
};
struct Vertical {
    int x, y1, y2;
    Vertical(){}
    Vertical(int p, int y1, int y2) : x(p), y1(y1), y2(y2) {}
    bool operator < (const Vertical &b) const {
        return y2 < b.y2;
    }
};
int ch, cv;
Horizontal h[maxn];
int qu[maxn], b, f;
Vertical v[maxn];

int temp[maxn * 2], cnt = 1, m;

ll tree[maxn * 2];
void add(int x, int in) {
    while(x <= m) {
        tree[x] += in;
        x += x & -x;
    }
}
ll query(int x) {
    ll re = 1;
    while(x > 0) {
        re += tree[x];
        x -= x & -x;
    }
    return re;
}

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        int x1, x2, y1, y2;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        if(x1 == x2) {
            v[cv++] = Vertical(x1, min(y1, y2), max(y1, y2));
        } else if(y1 == y2) {
            h[ch++] = Horizontal(y1, min(x1, x2), max(x1, x2));
        }
        temp[cnt++] = x1, temp[cnt++] = x2;
    }
    sort(temp + 1, temp + cnt);
    m = unique(temp + 1, temp + cnt) - temp;

    for(int i = 0; i < ch; ++i) {
        h[i].x1 = lower_bound(temp + 1, temp + m, h[i].x1) - temp;
        h[i].x2 = lower_bound(temp + 1, temp + m, h[i].x2) - temp;
    }
    for(int i = 0; i < cv; ++i) {
        v[i].x = lower_bound(temp + 1, temp + m, v[i].x) - temp;
    }

    ll ans = 0;
    sort(h, h + ch);
    sort(v, v + cv);

    for(int i = 0; i < ch; ++i) {
        memset(tree, 0, sizeof(tree));
        b = 0; f = 1;
        for(int c = 0; c < cv; ++c) {
            if(h[i].y <= v[c].y2 && h[i].y >= v[c].y1) {
                add(v[c].x, 1);
                qu[++b] = c;
            }
        }

        for(int j = i + 1; j < ch; ++j) {
            if(h[i].y == h[j].y)
                continue;
            while(f <= b && v[qu[f]].y2 < h[j].y) {
                add(v[qu[f]].x, -1);
                ++f;
            }
            int l, r;
            l = max(h[i].x1, h[j].x1);
            r = min(h[i].x2, h[j].x2);
            if(l >= r)
                continue;
            ll add = query(r) - query(l - 1);
            ans += add * (add - 1) / 2;
        }
    }
    printf("%lld\n", ans);
}


#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#define INF 0x3f3f3f3f
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;

const int mod = 1e9 + 7;
const int maxn = 5e3 + 5;

struct Horizontal {
    int y, x1, x2;
    Horizontal(){}
    Horizontal(int p, int x1, int x2) : y(p), x1(x1), x2(x2){}
    bool operator < (const Horizontal &b) const {
        return y < b.y;
    }
};
struct Vertical {
    int x, y1, y2;
    Vertical(){}
    Vertical(int p, int y1, int y2) : x(p), y1(y1), y2(y2) {}
    bool operator < (const Vertical &b) const {
        return y2 < b.y2;
    }
};
int ch, cv;
Horizontal h[maxn];
Vertical v[maxn];
bool vis[maxn];
int temp[maxn * 2], cnt = 1, m;

ll tree[maxn * 2];
void add(int x, int in) {
    while(x <= m) {
        tree[x] += in;
        x += x & -x;
    }
}
ll query(int x) {
    ll re = 1;
    while(x > 0) {
        re += tree[x];
        x -= x & -x;
    }
    return re;
}

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        int x1, x2, y1, y2;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        if(x1 == x2) {
            v[cv++] = Vertical(x1, min(y1, y2), max(y1, y2));
        } else if(y1 == y2) {
            h[ch++] = Horizontal(y1, min(x1, x2), max(x1, x2));
        }
        temp[cnt++] = x1, temp[cnt++] = x2;
    }
    sort(temp + 1, temp + cnt);
    m = unique(temp + 1, temp + cnt) - temp;

    for(int i = 0; i < ch; ++i) {
        h[i].x1 = lower_bound(temp + 1, temp + m, h[i].x1) - temp;
        h[i].x2 = lower_bound(temp + 1, temp + m, h[i].x2) - temp;
    }
    for(int i = 0; i < cv; ++i) {
        v[i].x = lower_bound(temp + 1, temp + m, v[i].x) - temp;
    }

    ll ans = 0;
    sort(h, h + ch);
    sort(v, v + cv);
    for(int i = 0; i < ch; ++i) {
        memset(tree, 0, sizeof(tree));
        memset(vis, 0, sizeof(vis));
        int c = cv - 1;
        for(; c >= 0; --c) {
            if(h[i].y <= v[c].y2 && h[i].y >= v[c].y1) {
                add(v[c].x, 1);
                vis[c] = 1;
            }
            if(h[c].y > v[c].y2)
                break;
        }
        if(c < 0)
            c = 0;

        for(int j = i + 1; j < ch; ++j) {
            if(h[i].y == h[j].y)
                continue;
            while(c < cv && v[c].y2 < h[j].y && vis[c]) {
                add(v[c].x, -1);
                vis[c] = 0;
                ++c;
            }
            int l, r;
            l = max(h[i].x1, h[j].x1);
            r = min(h[i].x2, h[j].x2);
            ll add = query(r) - query(l - 1);
            ans += add * (add - 1) / 2;
        }
    }
    printf("%lld\n", ans);
}


#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#define INF 0x3f3f3f3f
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;

const int mod = 1e9 + 7;
const int maxn = 5e3 + 5;

struct Horizontal {
    int y, x1, x2;
    Horizontal(){}
    Horizontal(int p, int x1, int x2) : y(p), x1(x1), x2(x2){}
    bool operator < (const Horizontal &b) const {
        return y < b.y;
    }
};
struct Vertical {
    int x, y1, y2;
    Vertical(){}
    Vertical(int p, int y1, int y2) : x(p), y1(y1), y2(y2) {}
    bool operator < (const Vertical &b) const {
        return y2 < b.y2;
    }
};
int ch, cv;
Horizontal h[maxn];
Vertical v[maxn];
bool vis[maxn];
int temp[maxn * 2], cnt = 1, m;

ll tree[maxn * 2];
void add(int x, int in) {
    while(x <= m) {
        tree[x] += in;
        x += x & -x;
    }
}
ll query(int x) {
    ll re = 1;
    while(x > 0) {
        re += tree[x];
        x -= x & -x;
    }
    return re;
}

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        int x1, x2, y1, y2;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        if(x1 == x2) {
            v[cv++] = Vertical(x1, min(y1, y2), max(y1, y2));
        } else if(y1 == y2) {
            h[ch++] = Horizontal(y1, min(x1, x2), max(x1, x2));
        }
        temp[cnt++] = x1, temp[cnt++] = x2;
    }
    sort(temp + 1, temp + cnt);
    m = unique(temp + 1, temp + cnt) - temp;

    for(int i = 0; i < ch; ++i) {
        h[i].x1 = lower_bound(temp + 1, temp + m, h[i].x1) - temp;
        h[i].x2 = lower_bound(temp + 1, temp + m, h[i].x2) - temp;
    }
    for(int i = 0; i < cv; ++i) {
        v[i].x = lower_bound(temp + 1, temp + m, v[i].x) - temp;
    }

    ll ans = 0;
    sort(h, h + ch);
    sort(v, v + cv);
    for(int i = 0; i < ch; ++i) {
        memset(tree, 0, sizeof(tree));
        memset(vis, 0, sizeof(vis));
        int c = cv - 1;
        for(; c >= 0; --c) {
            if(h[i].y <= v[c].y2 && h[i].y >= v[c].y1) {
                add(v[c].x, 1);
                vis[c] = 1;
            }
            if(h[c].y > v[c].y2)
                break;
        }
        if(c < 0)
            c = 0;

        for(int j = i + 1; j < ch; ++j) {
            if(h[i].y == h[j].y)
                continue;
            while(c < cv && v[c].y2 < h[j].y) {
                if(vis[c]) {
                    add(v[c].x, -1);
                    vis[c] = 0;
                }
                ++c;
            }
            int l, r;
            l = max(h[i].x1, h[j].x1);
            r = min(h[i].x2, h[j].x2);
            if(l >= r)
                continue;
            ll add = query(r) - query(l - 1);
            ans += add * (add - 1) / 2;
        }
    }
    printf("%lld\n", ans);
}


#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#define INF 0x3f3f3f3f
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;

const int mod = 1e9 + 7;
const int maxn = 5e4 + 5;

struct Horizontal {
    int y, x1, x2;
    Horizontal(){}
    Horizontal(int p, int x1, int x2) : y(p), x1(x1), x2(x2){}
    bool operator < (const Horizontal &b) const {
        return y < b.y;
    }
};
struct Vertical {
    int x, y1, y2;
    Vertical(){}
    Vertical(int p, int y1, int y2) : x(p), y1(y1), y2(y2) {}
    bool operator < (const Vertical &b) const {
        return y2 < b.y2;
    }
};
int ch, cv;
Horizontal h[maxn];
Vertical v[maxn];
int temp[maxn * 2], cnt = 1, m;

ll tree[maxn * 2];
void add(int x, int in) {
    while(x <= m) {
        tree[x] += in;
        x += x & -x;
    }
}
ll query(int x) {
    ll re = 1;
    while(x > 0) {
        re += tree[x];
        x -= x & -x;
    }
    return re;
}

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        int x1, x2, y1, y2;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        if(x1 == x2) {
            v[cv++] = Vertical(x1, min(y1, y2), max(y1, y2));
        } else if(y1 == y2) {
            h[ch++] = Horizontal(y1, min(x1, x2), max(x1, x2));
        }
        temp[cnt++] = x1, temp[cnt++] = x2;
    }
    sort(temp + 1, temp + cnt);
    m = unique(temp + 1, temp + cnt) - temp;

    for(int i = 0; i < ch; ++i) {
        h[i].x1 = lower_bound(temp + 1, temp + 1 + m, h[i].x1) - temp;
        h[i].x2 = lower_bound(temp + 1, temp + 1 + m, h[i].x2) - temp;
    }
    for(int i = 0; i < cv; ++i) {
        v[i].x = lower_bound(temp + 1, temp + 1 + m, v[i].x) - temp;
    }

    ll ans = 0;
    sort(h, h + ch);
    sort(v, v + cv);
    for(int i = 0; i < ch; ++i) {
        memset(tree, 0, sizeof(tree));
        int c = cv - 1;
        for(; c >= 0; --c) {
            if(h[i].y <= v[c].y2 && h[i].y >= v[c].y1) {
                add(v[c].x, 1);
            }
            if(h[c].y > v[c].y2)
                break;
        }
        if(c < 0)
            c = 0;

        for(int j = i + 1; j < ch; ++j) {
            if(h[i].y == h[j].y)
                continue;
            while(c < cv && v[c].y2 < h[j].y) {
                add(v[c].x, -1);
                ++c;
            }
            int l, r;
            l = max(h[i].x1, h[j].x1);
            r = min(h[i].x2, h[j].x2);
            ll add = query(r) - query(l - 1);
            ans += add * (add - 1) / 2;
        }
    }
    printf("%lld\n", ans);
}


#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ordered_set tree<int,null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_set_pair tree<pair<int,int>,null_type,less<pair<int,int>>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_set_mutiset tree<int,null_type,less_equal<int>, rb_tree_tag,tree_order_statistics_node_update>
typedef long long int ll;
typedef long double ld;
typedef unsigned long long int ull;
typedef pair<int,int> pi;
#define PI 3.1415926535897932384
#define FOR(i,vv,n) for(int i=vv;i<n;i++)
#define FORR(i,n,vv) for(int i=n-1;i>=vv;i--)
#define ve vector
#define maxind(v) (max_element(v.begin(),v.end())-v.begin())
#define minind(v) (min_element(v.begin(),v.end())-v.begin())
#define maxe(v) *max_element(v.begin(),v.end())
#define mine(v) *min_element(v.begin(),v.end())
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define FAST ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mp make_pair
#define M 1000000007ll
#define INF 1000000000000000000ll
#define PRECISE cout.precision(18);
#define BS(v,n) binary_search(v.begin(),v.end(),n)
#define srt(v) sort(v.begin(),v.end())
#define rsrt(v) sort(v.begin(),v.end(),greater <ll>())
#define uni(v) v.resize(unique(v.begin(),v.end())-v.begin())
#define F first
#define S second
#define GET(i,p) get<p>(i)

ve <ve <pair <ll,ll>> > horiz(10001+1);
ve <ve <pair <ll,ll>> > ver(10001+1);

 ll bit[10001+1]; // declare bit as a map if necessary.
const ll n=10001; // will be taken as input in main
// take care of i,use idx not i.
void add(ll idx,ll v){
for(ll i=idx;idx<=n;idx+=(idx&-idx))
	bit[idx]+=v;
}
void update(ll l,ll v){     // for range update(we have 2,for point use 1)
	add(l,v);
}

ll sum1(ll idx){
	ll sum=0;
	for(ll i=idx;idx>0;idx-=(idx&-idx))
		sum+=bit[idx];
	return sum;
}

ll query(ll idx1,ll idx2){                // point query,for range query (sub 2 point query etc.)
idx1--;
ll a1=sum1(idx1);
ll a2=sum1(idx2);
return a2-a1;
}

int main(){
	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
	 #endif
    FAST
//	PRECISE

ll m;
cin>>m;
FOR(i,0,m){
	ll x1,y1,x2,y2;
	cin>>x1>>y1>>x2>>y2;
	x1+=5001;x2+=5001;y1+=5001;y2+=5001;
	if(x1==x2){
		ver[x1].pb({min(y1,y2),max(y1,y2)});
	}
	else{
		horiz[y1].pb({min(x1,x2),max(x1,x2)});
	}
}
deque <pair <ll,ll> > dummy;
ll ans=0;
ll maxn=10002;
FOR(i,1,maxn){
	dummy.clear();
	memset(bit,0,sizeof(bit));
for(auto i1:horiz[i]){
	ll x1=i1.F;
	ll x2=i1.S;
	FOR(j,x1,x2+1){
		for(auto k:ver[j]){
			ll z1=k.F;
			ll z2=k.S;
			if(z1<=i&&z2>=i)
				dummy.pb({z2,j}),update(j,1);
		}
	}
}
 srt(dummy);
FOR(i1,i+1,maxn){
while(!dummy.empty()&&dummy.front().F==i1-1)
	update(dummy.front().S,-1),dummy.ppf();
for(auto i2:horiz[i1]){
	ll c=query(i2.F,i2.S);
	ans+=c*(c-1)/2;
}
}
}
cout<<ans;
cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";

return 0;
 }


#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ordered_set tree<int,null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_set_pair tree<pair<int,int>,null_type,less<pair<int,int>>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_set_mutiset tree<int,null_type,less_equal<int>, rb_tree_tag,tree_order_statistics_node_update>
typedef long long int ll;
typedef long double ld;
typedef unsigned long long int ull;
typedef pair<int,int> pi;
#define PI 3.1415926535897932384
#define FOR(i,vv,n) for(int i=vv;i<n;i++)
#define FORR(i,n,vv) for(int i=n-1;i>=vv;i--)
#define ve vector
#define maxind(v) (max_element(v.begin(),v.end())-v.begin())
#define minind(v) (min_element(v.begin(),v.end())-v.begin())
#define maxe(v) *max_element(v.begin(),v.end())
#define mine(v) *min_element(v.begin(),v.end())
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define FAST ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mp make_pair
#define M 1000000007ll
#define INF 1000000000000000000ll
#define PRECISE cout.precision(18);
#define BS(v,n) binary_search(v.begin(),v.end(),n)
#define srt(v) sort(v.begin(),v.end())
#define rsrt(v) sort(v.begin(),v.end(),greater <ll>())
#define uni(v) v.resize(unique(v.begin(),v.end())-v.begin())
#define F first
#define S second
#define GET(i,p) get<p>(i)

ve <ve <pair <ll,ll>> > horiz(10001+1);
ve <ve <pair <ll,ll>> > ver(10001+1);

 ll bit[10001+1]; // declare bit as a map if necessary.
const ll n=10001; // will be taken as input in main
// take care of i,use idx not i.
void add(ll idx,ll v){
for(ll i=idx;idx<=n;idx+=(idx&-idx))
	bit[idx]+=v;
}
void update(ll l,ll v){     // for range update(we have 2,for point use 1)
	add(l,v);
}

ll sum1(ll idx){
	ll sum=0;
	for(ll i=idx;idx>0;idx-=(idx&-idx))
		sum+=bit[idx];
	return sum;
}

ll query(ll idx1,ll idx2){                // point query,for range query (sub 2 point query etc.)
idx1--;
ll a1=sum1(idx1);
ll a2=sum1(idx2);
return a2-a1;
}

int main(){
	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
	 #endif
    FAST
//	PRECISE

ll m;
cin>>m;
FOR(i,0,m){
	ll x1,y1,x2,y2;
	cin>>x1>>y1>>x2>>y2;
	x1+=5001;x2+=5001;y1+=5001;y2+=5001;
	if(x1==x2){
		ver[x1].pb({min(y1,y2),max(y1,y2)});
	}
	else{
		horiz[y1].pb({min(x1,x2),max(x1,x2)});
	}
}
deque <pair <ll,ll> > dummy;
ll ans=0;
ll maxn=10002;
FOR(i,1,maxn){
	dummy.clear();
	memset(bit,0,sizeof(bit));
for(auto i1:horiz[i]){
	ll x1=i1.F;
	ll x2=i1.S;
	FOR(j,x1,x2+1){
		for(auto k:ver[j]){
			ll z1=k.F;
			ll z2=k.S;
			if(z1<=i&&z2>=i)
				dummy.pb({z2,j}),update(j,1);
		}
	}
}
 srt(dummy);
FOR(i1,i+1,maxn){
while(dummy.size()!=0&&dummy.front().F==i1-1)
	update(dummy.front().S,-1),dummy.ppf();
for(auto i2:horiz[i1]){
	ll c=query(i2.F,i2.S);
	ans+=c*(c-1)/2;
}
}
}
cout<<ans;
cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";

return 0;
 }


#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ordered_set tree<int,null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_set_pair tree<pair<int,int>,null_type,less<pair<int,int>>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_set_mutiset tree<int,null_type,less_equal<int>, rb_tree_tag,tree_order_statistics_node_update>
typedef long long int ll;
typedef long double ld;
typedef unsigned long long int ull;
typedef pair<int,int> pi;
#define PI 3.1415926535897932384
#define FOR(i,vv,n) for(int i=vv;i<n;i++)
#define FORR(i,n,vv) for(int i=n-1;i>=vv;i--)
#define ve vector
#define maxind(v) (max_element(v.begin(),v.end())-v.begin())
#define minind(v) (min_element(v.begin(),v.end())-v.begin())
#define maxe(v) *max_element(v.begin(),v.end())
#define mine(v) *min_element(v.begin(),v.end())
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define FAST ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mp make_pair
#define M 1000000007ll
#define INF 1000000000000000000ll
#define PRECISE cout.precision(18);
#define BS(v,n) binary_search(v.begin(),v.end(),n)
#define srt(v) sort(v.begin(),v.end())
#define rsrt(v) sort(v.begin(),v.end(),greater <ll>())
#define uni(v) v.resize(unique(v.begin(),v.end())-v.begin())
#define F first
#define S second
#define GET(i,p) get<p>(i)

ve <ve <pair <ll,ll>> > horiz(10001+1);
ve <ve <pair <ll,ll>> > ver(10001+1);

 ll bit[10001+1]; // declare bit as a map if necessary.
const ll n=10001; // will be taken as input in main
// take care of i,use idx not i.
void add(ll idx,ll v){
for(ll i=idx;idx<=n;idx+=(idx&-idx))
	bit[idx]+=v;
}
void update(ll l,ll v){     // for range update(we have 2,for point use 1)
	add(l,v);
}

ll sum1(ll idx){
	ll sum=0;
	for(ll i=idx;idx>0;idx-=(idx&-idx))
		sum+=bit[idx];
	return sum;
}

ll query(ll idx1,ll idx2){                // point query,for range query (sub 2 point query etc.)
idx1--;
ll a1=sum1(idx1);
ll a2=sum1(idx2);
return a2-a1;
}

int main(){
	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
	 #endif
    FAST
//	PRECISE

ll m;
cin>>m;
FOR(i,0,m){
	ll x1,y1,x2,y2;
	cin>>x1>>y1>>x2>>y2;
	x1+=5001;x2+=5001;y1+=5001;y2+=5001;
	if(x1==x2){
		ver[x1].pb({min(y1,y2),max(y1,y2)});
	}
	else{
		horiz[y1].pb({min(x1,x2),max(x1,x2)});
	}
}
deque <pair <ll,ll> > dummy;
ll ans=0;
ll maxn=10002;
FOR(i,1,maxn){

	memset(bit,0,sizeof(bit));
for(auto i1:horiz[i]){
		dummy.clear();
	ll x1=i1.F;
	ll x2=i1.S;
	FOR(j,x1,x2+1){
		for(auto k:ver[j]){
			ll z1=k.F;
			ll z2=k.S;
			if(z1<=i&&z2>=i)
				dummy.pb({z2,j}),update(j,1);
		}
	}

 srt(dummy);
FOR(i2,i+1,maxn){
while(!dummy.empty()&&dummy.front().F==i2-1)
	update(dummy.front().S,-1),dummy.ppf();
for(auto i3:horiz[i2]){
	ll c=query(max(i3.F,x1),min(i3.S,x2));
	ans+=c*(c-1)/2;
}
}

}
}
cout<<ans;
cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";

return 0;
 }


#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ordered_set tree<int,null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_set_pair tree<pair<int,int>,null_type,less<pair<int,int>>, rb_tree_tag,tree_order_statistics_node_update>
#define ordered_set_mutiset tree<int,null_type,less_equal<int>, rb_tree_tag,tree_order_statistics_node_update>
typedef long long int ll;
typedef long double ld;
typedef unsigned long long int ull;
typedef pair<int,int> pi;
#define PI 3.1415926535897932384
#define FOR(i,vv,n) for(int i=vv;i<n;i++)
#define FORR(i,n,vv) for(int i=n-1;i>=vv;i--)
#define ve vector
#define maxind(v) (max_element(v.begin(),v.end())-v.begin())
#define minind(v) (min_element(v.begin(),v.end())-v.begin())
#define maxe(v) *max_element(v.begin(),v.end())
#define mine(v) *min_element(v.begin(),v.end())
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define FAST ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mp make_pair
#define M 1000000007ll
#define INF 1000000000000000000ll
#define PRECISE cout.precision(18);
#define BS(v,n) binary_search(v.begin(),v.end(),n)
#define srt(v) sort(v.begin(),v.end())
#define rsrt(v) sort(v.begin(),v.end(),greater <ll>())
#define uni(v) v.resize(unique(v.begin(),v.end())-v.begin())
#define F first
#define S second
#define GET(i,p) get<p>(i)

ve <ve <pair <ll,ll>> > horiz(10001+1);
ve <ve <pair <ll,ll>> > ver(10001+1);

 ll bit[10001+1]; // declare bit as a map if necessary.
const ll n=10001; // will be taken as input in main
// take care of i,use idx not i.
void add(ll idx,ll v){
for(ll i=idx;idx<=n;idx+=(idx&-idx))
	bit[idx]+=v;
}
void update(ll l,ll v){     // for range update(we have 2,for point use 1)
	add(l,v);
}

ll sum1(ll idx){
	ll sum=0;
	for(ll i=idx;idx>0;idx-=(idx&-idx))
		sum+=bit[idx];
	return sum;
}

ll query(ll idx1,ll idx2){                // point query,for range query (sub 2 point query etc.)
idx1--;
ll a1=sum1(idx1);
ll a2=sum1(idx2);
if(a1>=a2)
return 0;
return a2-a1;
}

int main(){
	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
	 #endif
    FAST
//	PRECISE

ll m;
cin>>m;
FOR(i,0,m){
	ll x1,y1,x2,y2;
	cin>>x1>>y1>>x2>>y2;
	x1+=5001;x2+=5001;y1+=5001;y2+=5001;
	if(x1==x2){
		ver[x1].pb({min(y1,y2),max(y1,y2)});
	}
	else{
		horiz[y1].pb({min(x1,x2),max(x1,x2)});
	}
}
deque <pair <ll,ll> > dummy;
ll ans=0;
ll maxn=10002;
FOR(i,1,maxn){

	memset(bit,0,sizeof(bit));
for(auto i1:horiz[i]){
		dummy.clear();
	ll x1=i1.F;
	ll x2=i1.S;
	FOR(j,x1,x2+1){
		for(auto k:ver[j]){
			ll z1=k.F;
			ll z2=k.S;
			if(z1<=i&&z2>=i)
				dummy.pb({z2,j}),update(j,1);
		}
	}

 srt(dummy);
FOR(i2,i+1,maxn){
while(!dummy.empty()&&dummy.front().F==i2-1)
	update(dummy.front().S,-1),dummy.ppf();
for(auto i3:horiz[i2]){
	ll c=query(max(i3.F,x1),min(i3.S,x2));
	ans+=c*(c-1)/2;
}
}

}
}
cout<<ans;
cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";

return 0;
 }


 #include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define int long long
#define ll long long
#define mp make_pair
#define ss second
#define pb push_back
#define ff first
#define um unordered_map
#define us unordered_set
#define pll pair<ll,ll>
#define large 100005
const int mod = 1e9+7;
#define PI 3.1415926535
ll powmod(ll base,ll exp,ll MOD){ll res=1;while(exp>0){if(exp%2==1) res=(res*base)%MOD;base=(base*base)%MOD;exp/=2;}return (res%MOD);}
int n;
const int d = 5000;
const int N = 10005;
int bit[N];

void upd(int x,int val){

	for(int i=x;i<N;i+=(i&(-i)))
	   bit[i]+=val;

}

int query(int x){

    int q = 0;

	for(int i=x;i>0;i-=(i&-i))
  	   q+=bit[i];

  	return q;

}

int query(int l,int r){
	return query(r)-query(l-1);
}

vector<pii> ver[N],hor[N];
vector<int> D[N];

int32_t main() {

    ios_base::sync_with_stdio(0);
	cin.tie(0);
    cout.tie(0);

    cin>>n;

    for(int i=0;i<n;i++){

    	int x1,y1,x2,y2;
    	cin>>x1>>y1>>x2>>y2;

    	x1+=d,x2+=d,y1+=d,y2+=d;

    	if(y1==y2)
    	  hor[y1].pb(mp(min(x1,x2) , max(x1,x2)));
    	else
		  ver[x1].pb(mp(min(y1,y2) , max(y1,y2)));

	}

	ll ans = 0;

	for(int i=0;i<N;i++){

	   for(auto pp1:hor[i]){

	      memset(bit, 0, sizeof bit);

	      for(int x=pp1.ff;x<=pp1.ss;x++){

			for(auto pp2:ver[x])
		     if(pp2.ff<=i && pp2.ss>i){
	      	  upd(x,1);
			  D[pp2.ss].pb(x);
	         }

		  }

	   for(int j=i+1;j<N;j++){

	   	 for(auto pp:hor[j]){

		  int curr = query(pp.ff,pp.ss);

	   	  ans += curr * (curr-1) / 2;

	     }

	   	 for(auto x:D[j])
	   	   upd(x,-1);

	   }

	  }

	}

	cout<<ans;

    return 0;

}


 #include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define int long long
#define ll long long
#define mp make_pair
#define ss second
#define pb push_back
#define ff first
#define um unordered_map
#define us unordered_set
#define pll pair<ll,ll>
#define large 100005
const int mod = 1e9+7;
#define PI 3.1415926535
ll powmod(ll base,ll exp,ll MOD){ll res=1;while(exp>0){if(exp%2==1) res=(res*base)%MOD;base=(base*base)%MOD;exp/=2;}return (res%MOD);}
int n;
const int d = 5000;
const int N = 10005;
int bit[N];

void upd(int pos,int val){

	for(; pos < N; pos |= pos + 1)
		bit[pos] += val;

}

int query(int pos){

    int res = 0;
	for(; pos >= 0; pos = (pos & (pos + 1)) - 1)
		res += bit[pos];
	return res;

}

int query(int l,int r){
	return query(r)-query(l-1);
}

vector<pii> ver[N],hor[N];
vector<int> D[N];

int32_t main() {

    ios_base::sync_with_stdio(0);
	cin.tie(0);
    cout.tie(0);

    cin>>n;

    for(int i=0;i<n;i++){

    	int x1,y1,x2,y2;
    	cin>>x1>>y1>>x2>>y2;

    	x1+=d,x2+=d,y1+=d,y2+=d;

    	if(y1==y2)
    	  hor[y1].pb(mp(min(x1,x2) , max(x1,x2)));
    	else
		  ver[x1].pb(mp(min(y1,y2) , max(y1,y2)));

	}

	ll ans = 0;

	for(int i=0;i<N;i++)
	   for(auto pp1:hor[i]){

	      memset(bit, 0, sizeof bit);

	      for(int x=pp1.ff;x<=pp1.ss;x++){

			for(auto pp2:ver[x])
		     if(pp2.ff<=i && pp2.ss>i){
	      	  upd(x,1);
			  D[pp2.ss].pb(x);
	         }

		  }

	   for(int j=i+1;j<N;j++){

	   	 for(auto pp:hor[j]){

		  int curr = query(pp.ff,pp.ss);

	   	  ans += curr * (curr-1) / 2;

	     }

	   	 for(auto x:D[j])
	   	   upd(x,-1);

	   }

	  }

	cout<<ans;

    return 0;

}


 #include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define int long long
#define ll long long
#define mp make_pair
#define ss second
#define pb push_back
#define ff first
#define um unordered_map
#define us unordered_set
#define pll pair<ll,ll>
#define large 100005
const int mod = 1e9+7;
#define PI 3.1415926535
ll powmod(ll base,ll exp,ll MOD){ll res=1;while(exp>0){if(exp%2==1) res=(res*base)%MOD;base=(base*base)%MOD;exp/=2;}return (res%MOD);}
int n;
const int d = 5000;
const int N = 10005;
int bit[N];

void upd(int x,int val){

	for(int i=x;i<N;i+=(i&(-i)))
	   bit[i]+=val;

}

int query(int x){

    int q = 0;

	for(int i=x;i>0;i-=(i&-i))
  	   q+=bit[i];

  	return q;

}

int query(int l,int r){
	return query(r)-query(l-1);
}

vector<pii> ver[N],hor[N];
vector<int> D[N];

int32_t main() {

    ios_base::sync_with_stdio(0);
	cin.tie(0);
    cout.tie(0);

    cin>>n;

    for(int i=0;i<n;i++){

    	int x1,y1,x2,y2;
    	cin>>x1>>y1>>x2>>y2;

    	x1+=d,x2+=d,y1+=d,y2+=d;

    	if(y1==y2)
    	  hor[y1].pb(mp(min(x1,x2) , max(x1,x2)));
    	else
		  ver[x1].pb(mp(min(y1,y2) , max(y1,y2)));

	}

	ll ans = 0;

	for(int i=0;i<N;i++){

	   for(auto pp1:hor[i]){

	      for(int x=pp1.ff;x<=pp1.ss;x++){

			for(auto pp2:ver[x])
		     if(pp2.ff<=i && pp2.ss>i){
	      	  upd(x,1);
			  D[pp2.ss].pb(x);
	         }

		  }

	   for(int j=i+1;j<N;j++){

	   	 for(auto pp:hor[j]){

		  int curr = query(pp.ff,pp.ss);

	   	  ans += curr * (curr-1) / 2;

	     }

	   	 for(auto x:D[j])
	   	   upd(x,-1);

	   }

	  }

	}

	cout<<ans;

    return 0;

}


#include <bits/stdc++.h>

using namespace std;

#define mp make_pair

const int N = 10009;
const int INF = 1000000009;

int n;
vector <pair<int, int> > vs[N], hs[N];
int f[N];
vector <int> d[N];

void upd(int pos, int x){
	for(; pos < N; pos |= pos + 1)
		f[pos] += x;
}

int get(int pos){
	int res = 0;
	for(; pos >= 0; pos = (pos & (pos + 1)) - 1)
		res += f[pos];
	return res;
}

int get(int l, int r){
	return get(r) - get(l - 1);
}

const int D = 5000;

int main() {

	cin >> n;

	for(int i = 0; i < n; ++i){

		int x1, y1, x2, y2;

		cin >> x1 >> y1 >> x2 >> y2;

		x1 += D, y1 += D, x2 += D, y2 += D;

		if(y1 == y2)
			hs[y1].push_back( mp(min(x1, x2),max(x1, x2)) );
		else
			vs[x1].push_back( mp(min(y1, y2),max(y1, y2)) );

	}

	long long res = 0;

	for(int y = 0; y < N; ++y) for(auto s : hs[y]){

		for(int i = 0; i < N; ++i) d[i].clear();

		memset(f, 0, sizeof f);

		int l = s.first, r = s.second;

		for(int x = l; x <= r; ++x) for(auto s2 : vs[x])
			if(s2.first <= y && s2.second > y) {
				d[s2.second].push_back(x);
				upd(x, 1);
			}

		for(int y2 = y + 1; y2 < N; ++y2){

			for(auto s2 : hs[y2]){
				int cur = get(s2.first, s2.second);
				res += cur * (cur - 1) / 2;
			}

		for(auto x : d[y2]) upd(x, -1);

		}

	}

	cout << res << endl;

	return 0;

}


#include <bits/stdc++.h>

using namespace std;

#define mp make_pair

const int N = 10009;
const int INF = 1000000009;

int n;
vector <pair<int, int> > vs[N], hs[N];
int f[N];
vector <int> d[N];

void upd(int pos, int x){
    for(int i=pos;i<N;i+=(i&(-i)))
	   f[i]+=x;
}

int get(int pos){
int q = 0;

	for(int i=pos;i>0;i-=(i&(-i)))
  	   q+=f[i];

  	return q;
}

int get(int l, int r){
	return get(r) - get(l - 1);
}

const int D = 5000;

int main() {

	cin >> n;

	for(int i = 0; i < n; ++i){

		int x1, y1, x2, y2;

		cin >> x1 >> y1 >> x2 >> y2;

		x1 += D, y1 += D, x2 += D, y2 += D;

		if(y1 == y2)
			hs[y1].push_back( mp(min(x1, x2),max(x1, x2)) );
		else
			vs[x1].push_back( mp(min(y1, y2),max(y1, y2)) );

	}

	long long res = 0;

	for(int y = 0; y < N; ++y) for(auto s : hs[y]){

		for(int i = 0; i < N; ++i) d[i].clear();

		memset(f, 0, sizeof f);

		int l = s.first, r = s.second;

		for(int x = l; x <= r; ++x)
		 for(auto s2 : vs[x])
			if(s2.first <= y && s2.second > y) {
				d[s2.second].push_back(x);
				upd(x, 1);
			}

		for(int y2 = y + 1; y2 < N; ++y2){

			for(auto s2 : hs[y2]){
				int cur = get(s2.first, s2.second);
				res += cur * (cur - 1) / 2;
			}

		    for(auto x : d[y2]) upd(x, -1);

		}

	}

	cout << res << endl;

	return 0;

}


#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
int n;
const int d = 5000;
const int N = 10005;
int bit[N];

void upd(int pos,int val){

	for(; pos < N; pos |= pos + 1)
		bit[pos] += val;

}

int query(int pos){

    int res = 0;
	for(; pos >= 0; pos = (pos & (pos + 1)) - 1)
		res += bit[pos];
	return res;

}

int query(int l,int r){
	return query(r)-query(l-1);
}

vector<pair<int,int> > ver[N],hor[N];
vector<int> D[N];

int32_t main() {

    ios_base::sync_with_stdio(0);
	cin.tie(0);
    cout.tie(0);

    cin>>n;

    for(int i=0;i<n;i++){

    	int x1,y1,x2,y2;
    	cin>>x1>>y1>>x2>>y2;

    	x1+=d,x2+=d,y1+=d,y2+=d;

    	if(y1==y2)
    	  hor[y1].push_back(make_pair(min(x1,x2) , max(x1,x2)));
    	else
		  ver[x1].push_back(make_pair(min(y1,y2) , max(y1,y2)));

	}

	long long ans = 0;

	for(int i=0;i<N;i++)
	   for(auto pp1:hor[i]){

	      memset(bit, 0, sizeof bit);

	      for(int x=pp1.first;x<=pp1.second;x++){

			for(auto pp2:ver[x])
		     if(pp2.first<=i && pp2.second>i){
	      	  upd(x,1);
			  D[pp2.second].push_back(x);
	         }

		  }

	   for(int j=i+1;j<N;j++){

	   	 for(auto pp:hor[j]){

		  int curr = query(pp.first,pp.second);

	   	  ans += curr * (curr-1) / 2;

	     }

	   	 for(auto x:D[j])
	   	   upd(x,-1);

	   }

	  }

	cout<<ans;

    return 0;

}


#include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define int long long
#define ll int
#define mp make_pair
#define ss second
#define pb push_back
#define ff first
#define um unordered_map
#define us unordered_set
#define pll pair<ll,ll>
#define large 100005
const int mod = 1e9+7;
#define PI 3.1415926535
ll powmod(ll base,ll exp,ll MOD){ll res=1;while(exp>0){if(exp%2==1) res=(res*base)%MOD;base=(base*base)%MOD;exp/=2;}return (res%MOD);}
int n;
const int d = 5000;
const int N = 10002;
int bit[N];

void upd(int i,int val){

	for(;i<N;i+=i&(-i))
	   bit[i]+=val;

}

int query(int i){

    int q = 0;

	for(;i>0;i-=i&(-i))
  	   q+=bit[i];

  	return q;

}

int query(int l,int r){
	return query(r)-query(l-1);
}

vector<pii> ver[N],hor[N];
vector<int> D[N];

int32_t main() {

    ios_base::sync_with_stdio(0);
	cin.tie(0);
    cout.tie(0);

    cin>>n;

    for(int i=0;i<n;i++){

    	int x1,y1,x2,y2;
    	cin>>x1>>y1>>x2>>y2;

    	x1+=d,x2+=d,y1+=d,y2+=d;

    	if(y1==y2)
    	  hor[y1].pb(mp(min(x1,x2) , max(x1,x2)));
    	else
		  ver[x1].pb(mp(min(y1,y2) , max(y1,y2)));

	}

	long long ans = 0;

	for(int i=0;i<N;i++)
	   for(auto pp1:hor[i]){

	      memset(bit, 0, sizeof bit);
	      for(int i = 0; i < N; ++i) D[i].clear();

	      for(int x=pp1.ff;x<=pp1.ss;x++){

			for(auto pp2:ver[x])
		     if(pp2.ff<=i && pp2.ss>i){
	      	  upd(x,1);
			  D[pp2.ss].pb(x);
	         }

		  }

	   for(int j=i+1;j<N;j++){

	   	 for(auto pp:hor[j]){

		  int curr = query(pp.ff,pp.ss);

	   	  ans += curr * (curr-1) / 2;

	     }

	   	 for(auto x:D[j])
	   	   upd(x,-1);

	   }

	  }

	cout<<ans;

    return 0;

}


 #include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define int long long
#define ll long long
#define mp make_pair
#define ss second
#define pb push_back
#define ff first
#define um unordered_map
#define us unordered_set
#define pll pair<ll,ll>
#define large 100005
const int mod = 1e9+7;
#define PI 3.1415926535
ll powmod(ll base,ll exp,ll MOD){ll res=1;while(exp>0){if(exp%2==1) res=(res*base)%MOD;base=(base*base)%MOD;exp/=2;}return (res%MOD);}
int n;
const int d = 5000;
const int N = 10005;
int bit[N];

void upd(int x,int val){

	for(int i=x;i<N;i+=(i&(-i)))
	   bit[i]+=val;

}

int query(int x){

    int q = 0;

	for(int i=x;i>0;i-=(i&(-i)))
  	   q+=bit[i];

  	return q;

}

int query(int l,int r){
	return query(r)-query(l-1);
}

vector<pii> ver[N],hor[N];
vector<int> D[N];

int32_t main() {

    ios_base::sync_with_stdio(0);
	cin.tie(0);
    cout.tie(0);

    cin>>n;

    for(int i=0;i<n;i++){

    	int x1,y1,x2,y2;
    	cin>>x1>>y1>>x2>>y2;

    	x1+=d,x2+=d,y1+=d,y2+=d;

    	if(y1==y2)
    	  hor[y1].pb(mp(min(x1,x2) , max(x1,x2)));
    	else
		  ver[x1].pb(mp(min(y1,y2) , max(y1,y2)));

	}

	ll ans = 0;

	for(int i=0;i<N;i++)
	   for(auto pp1:hor[i]){

	      memset(bit, 0, sizeof bit);
	      for(int i = 0; i < N; ++i) D[i].clear();

	      for(int x=pp1.ff;x<=pp1.ss;x++){

			for(auto pp2:ver[x])
		     if(pp2.ff<=i && pp2.ss>i){
	      	  upd(x,1);
			  D[pp2.ss].pb(x);
	         }

		  }

	   for(int j=i+1;j<N;j++){

	   	 for(auto pp:hor[j]){

		  int curr = query(pp.ff,pp.ss);

	   	  ans += curr * (curr-1) / 2;

	     }

	   	 for(auto x:D[j])
	   	   upd(x,-1);

	   }

	  }

	cout<<ans;

    return 0;

}