#include<bits/stdc++.h>
#define ms(a,v) memset(a,v,sizeof a)
#define ll long long
using namespace std;
map<int,bool> mat[10002];
int points[10002][4];
vector< pair<int,int> >inter;
vector< pair<int,int> >rec;

//Code By Stephan Ramirez dsramirezc@unal.edu.co
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d %d %d %d",&points[i][0],&points[i][1],&points[i][2],&points[i][3]);
        points[i][0]+=5000;
        points[i][1]+=5000;
        points[i][2]+=5000;
        points[i][3]+=5000;
    }

    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++){
            if(points[i][0]==points[i][2] && points[j][1]==points[j][3] ){
                if(min(points[j][0],points[j][2])<=points[i][0] &&  max(points[j][0],points[j][2])>=points[i][0]){
                    if(min(points[i][1],points[i][3])<=points[j][1] &&  max(points[i][1],points[i][3])>=points[j][1]){
                        inter.push_back(make_pair(points[i][0],points[j][1]));
                        rec.push_back(make_pair(i,j));
                        mat[points[i][0]][points[j][1]]=true;
                    }
                }
            }
            if(points[j][0]==points[j][2] && points[i][1]==points[i][3] ){
                if(min(points[i][0],points[i][2])<=points[j][0] &&  max(points[i][0],points[i][2])>=points[j][0]){
                    if(min(points[j][1],points[j][3])<=points[i][1] &&  max(points[j][1],points[j][3])>=points[i][1]){
                        inter.push_back(make_pair(points[j][0],points[i][1]));
                        rec.push_back(make_pair(j,i));
                        mat[points[j][0]][points[i][1]]=true;
                    }
                }
            }
        }
    }
    int ans=0;
    for( int i=0;i<inter.size();i++){
        for(int j=0;j<inter.size();j++){
            if(inter[i].first> inter[j].first && inter[i].second> inter[j].second && mat[ inter[i].first][inter[j].second]==true &&  mat[ inter[j].first][inter[i].second]==true ){
                int x=rec[i].first;
                int y=rec[j].second;
                 int x1=rec[j].first;
                int y1=rec[i].second;
                if(min(points[y][0],points[y][2])<=points[x][0] &&  max(points[y][0],points[y][2])>=points[x][0])
                    if(min(points[x][1],points[x][3])<=points[y][1] &&  max(points[x][1],points[x][3])>=points[y][1])
                        if(min(points[y1][0],points[y1][2])<=points[x1][0] &&  max(points[y1][0],points[y1][2])>=points[x1][0])
                           if(min(points[x1][1],points[x1][3])<=points[y1][1] &&  max(points[x1][1],points[x1][3])>=points[y1][1])
                                ans++;
            }
        }

    }
    printf("%d\n",ans);

	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	return 0;
}


#include<bits/stdc++.h>
#define ms(a,v) memset(a,v,sizeof a)
#define ll long long
using namespace std;
short points[5000][4];
set<short> adj[5000];
int ans=0;
bool visited[5000];

int root;

void dfs(int node,int p){
    visited[node]=true;

    if(p==3){
        bool flag=false;
        for(int i :adj[node])
            if(i==root){
                flag=true;
                break;
            }
        if(flag){
            //cout<<"hjk "<<node+1<<" "<<root+1<<endl;
            ans++;
        }
        visited[node]=false;
        return ;
    }
    for(int i: adj[node]){
        if(!visited[i])
            dfs(i,p+1);
    }
    visited[node]=false;
}
//Code By Stephan Ramirez dsramirezc@unal.edu.co
int main(){
    //freopen("in.txt","r",stdin);
    int n;
    scanf("%d",&n);
    //cout<<n<<endl;
    for(int i=0;i<n;i++)
        scanf("%d %d %d %d",&points[i][0],&points[i][1],&points[i][2],&points[i][3]);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(points[i][0]==points[i][2] && points[j][1]==points[j][3] ){
                if(min(points[j][0],points[j][2])<=points[i][0] &&  max(points[j][0],points[j][2])>=points[i][0]){
                    if(min(points[i][1],points[i][3])<=points[j][1] &&  max(points[i][1],points[i][3])>=points[j][1]){
                            adj[i].insert(j);
                            adj[j].insert(i);

                           // cout<<"inter "<<i<<" "<<j<<endl;

                    }
                }
            }
            if(points[j][0]==points[j][2] && points[i][1]==points[i][3] ){
                if(min(points[i][0],points[i][2])<=points[j][0] &&  max(points[i][0],points[i][2])>=points[j][0]){
                    if(min(points[j][1],points[j][3])<=points[i][1] &&  max(points[j][1],points[j][3])>=points[i][1]){
                           // cout<<"inter "<<i<<" "<<j<<endl;
                            adj[j].insert(i);
                            adj[i].insert(j);
                    }
                }
            }
        }
    }

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

        dfs(root,0);

    }

    printf("%d\n",ans/8);

	return 0;
}


#include<bits/stdc++.h>
#define ms(a,v) memset(a,v,sizeof a)
#define ll long long
using namespace std;
map<short,short> mat[10002];
int points[10002][4];
vector< pair<short,short> >rec;
set<int> adj[5005];
int ans=0;
bool visited[5005];
void dfs(int node,int p){
    //cout<<"node "<<node<<endl;
    //cout<<ans<<endl;
    visited[node]=true;
    for(int i: adj[node]){
        if(!visited[i]){
            dfs(i,node);
        }else if(p!=i){

           // cout<<node<<" me ag "<<i<<endl;
            ans++;
        }
    }
}
//Code By Stephan Ramirez dsramirezc@unal.edu.co
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d %d %d %d",&points[i][0],&points[i][1],&points[i][2],&points[i][3]);
        points[i][0]+=5000;
        points[i][1]+=5000;
        points[i][2]+=5000;
        points[i][3]+=5000;
    }

    int nd=1;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(points[i][0]==points[i][2] && points[j][1]==points[j][3] ){
                if(min(points[j][0],points[j][2])<=points[i][0] &&  max(points[j][0],points[j][2])>=points[i][0]){
                    if(min(points[i][1],points[i][3])<=points[j][1] &&  max(points[i][1],points[i][3])>=points[j][1]){
                        if(mat[points[i][0]][points[j][0]]==0){
                            adj[i].insert(j);
                           adj[j].insert(i);
                            mat[i][j]=true;
                        }
                    }
                }
            }
            if(points[j][0]==points[j][2] && points[i][1]==points[i][3] ){
                if(min(points[i][0],points[i][2])<=points[j][0] &&  max(points[i][0],points[i][2])>=points[j][0]){
                    if(min(points[j][1],points[j][3])<=points[i][1] &&  max(points[j][1],points[j][3])>=points[i][1]){
                        if(!mat[j][i]){
                            adj[i].insert(j);
                            adj[j].insert(i);
                            mat[j][i]=true;
                        }
                    }
                }
            }
        }
    }

    for(int i=0;i<n;i++){
        if(!visited[i]){
            dfs(i,n);
        }
    }
    printf("%d\n",max(ans-1,0));

	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	return 0;
}


#include<bits/stdc++.h>
#define ms(a,v) memset(a,v,sizeof a)
#define ll long long
using namespace std;
int points[10002][4];
set<int> adj[5005];
int ans=0;
bool visited[5005];
void dfs(int node,int p){
    //cout<<"node "<<node<<endl;
    //cout<<ans<<endl;
    visited[node]=true;
    for(int i: adj[node]){
        if(!visited[i]){
            dfs(i,node);
        }else if(p!=i){

           // cout<<node<<" me ag "<<i<<endl;
            ans++;
        }
    }
}
//Code By Stephan Ramirez dsramirezc@unal.edu.co
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d %d %d %d",&points[i][0],&points[i][1],&points[i][2],&points[i][3]);

    }

    int nd=1;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(points[i][0]==points[i][2] && points[j][1]==points[j][3] ){
                if(min(points[j][0],points[j][2])<=points[i][0] &&  max(points[j][0],points[j][2])>=points[i][0]){
                    if(min(points[i][1],points[i][3])<=points[j][1] &&  max(points[i][1],points[i][3])>=points[j][1]){
                            adj[i].insert(j);
                           adj[j].insert(i);

                    }
                }
            }
            if(points[j][0]==points[j][2] && points[i][1]==points[i][3] ){
                if(min(points[i][0],points[i][2])<=points[j][0] &&  max(points[i][0],points[i][2])>=points[j][0]){
                    if(min(points[j][1],points[j][3])<=points[i][1] &&  max(points[j][1],points[j][3])>=points[i][1]){
                            adj[i].insert(j);
                            adj[j].insert(i);
                    }
                }
            }
        }
    }

    for(int i=0;i<n;i++){
        if(!visited[i]){
            dfs(i,n);
        }
    }
    printf("%d\n",max(ans-1,0));

	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	return 0;
}


#include<bits/stdc++.h>
#define ms(a,v) memset(a,v,sizeof a)
#define ll long long
using namespace std;
short points[5000][4];
set<short> adj[5000];
int ans=0;
bool visited[5000];
bool mt[5000][5000];
int root;

void dfs(int node,int p){
    visited[node]=true;

    if(p==3){
        bool flag=false;
        for(int i=0;i<5000;i++)
            if(mt[node][i])
                if(i==root){
                    flag=true;
                    break;
                }
        if(flag){
            //cout<<"hjk "<<node+1<<" "<<root+1<<endl;
            ans++;
        }
        visited[node]=false;
        return ;
    }
    for(int i=0;i<5000;i++)
            if(mt[node][i])
                if(!visited[i])
                    dfs(i,p+1);

    visited[node]=false;
}
//Code By Stephan Ramirez dsramirezc@unal.edu.co
int main(){
    //freopen("in.txt","r",stdin);
    int n;
    scanf("%d",&n);
    //cout<<n<<endl;
    for(int i=0;i<n;i++)
        scanf("%d %d %d %d",&points[i][0],&points[i][1],&points[i][2],&points[i][3]);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(points[i][0]==points[i][2] && points[j][1]==points[j][3] ){
                if(min(points[j][0],points[j][2])<=points[i][0] &&  max(points[j][0],points[j][2])>=points[i][0]){
                    if(min(points[i][1],points[i][3])<=points[j][1] &&  max(points[i][1],points[i][3])>=points[j][1]){
                            mt[i][j]=true;
                            mt[j][i]=true;

                           // cout<<"inter "<<i<<" "<<j<<endl;

                    }
                }
            }
            if(points[j][0]==points[j][2] && points[i][1]==points[i][3] ){
                if(min(points[i][0],points[i][2])<=points[j][0] &&  max(points[i][0],points[i][2])>=points[j][0]){
                    if(min(points[j][1],points[j][3])<=points[i][1] &&  max(points[j][1],points[j][3])>=points[i][1]){
                           // cout<<"inter "<<i<<" "<<j<<endl;
                           mt[i][j]=true;
                            mt[j][i]=true;
                    }
                }
            }
        }
    }

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

        dfs(root,0);

    }

    printf("%d\n",ans/8);

	return 0;
}


#include<bits/stdc++.h>
#define ms(a,v) memset(a,v,sizeof a)
#define ll long long
using namespace std;
short points[5005][4];
set<short> adj[5005];
int ans=0;
bool visited[5005];
void dfs(int node,int p){
    //cout<<"node "<<node<<endl;
    //cout<<ans<<endl;
    visited[node]=true;
    for(int i: adj[node]){
        if(!visited[i]){
            dfs(i,node);
        }else if(p!=i){

           // cout<<node<<" me ag "<<i<<endl;
            ans++;
        }
    }
}
//Code By Stephan Ramirez dsramirezc@unal.edu.co
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d %d %d %d",&points[i][0],&points[i][1],&points[i][2],&points[i][3]);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(points[i][0]==points[i][2] && points[j][1]==points[j][3] ){
                if(min(points[j][0],points[j][2])<=points[i][0] &&  max(points[j][0],points[j][2])>=points[i][0]){
                    if(min(points[i][1],points[i][3])<=points[j][1] &&  max(points[i][1],points[i][3])>=points[j][1]){
                            adj[i].insert(j);
                            adj[j].insert(i);

                    }
                }
            }
            if(points[j][0]==points[j][2] && points[i][1]==points[i][3] ){
                if(min(points[i][0],points[i][2])<=points[j][0] &&  max(points[i][0],points[i][2])>=points[j][0]){
                    if(min(points[j][1],points[j][3])<=points[i][1] &&  max(points[j][1],points[j][3])>=points[i][1]){
                            adj[i].insert(j);
                            adj[j].insert(i);
                    }
                }
            }
        }
    }

    for(int i=0;i<n;i++){
        if(!visited[i]){
            dfs(i,n);
        }
    }
    printf("%d\n",max(ans-1,0));

	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	return 0;
}


#include<bits/stdc++.h>
#define ms(a,v) memset(a,v,sizeof a)
#define ll long long
using namespace std;
short points[5000][4];
set<short> adj[5000];
int ans=0;
bool visited[5000];
bool mt[5000][5000];
int root;

void dfs(int node,int p){
    visited[node]=true;

    if(p==3){
        bool flag=false;
        for(int i=root;i<5000;i++)
            if(mt[node][i])
                if(i==root){
                    flag=true;
                    break;
                }
        if(flag){
            //cout<<"hjk "<<node+1<<" "<<root+1<<endl;
            ans++;
        }
        visited[node]=false;
        return ;
    }
    for(int i=root;i<5000;i++)
            if(mt[node][i])
                if(!visited[i])
                    dfs(i,p+1);

    visited[node]=false;
}
//Code By Stephan Ramirez dsramirezc@unal.edu.co
int main(){
    //freopen("in.txt","r",stdin);
    int n;
    scanf("%d",&n);
    //cout<<n<<endl;
    for(int i=0;i<n;i++)
        scanf("%d %d %d %d",&points[i][0],&points[i][1],&points[i][2],&points[i][3]);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(points[i][0]==points[i][2] && points[j][1]==points[j][3] ){
                if(min(points[j][0],points[j][2])<=points[i][0] &&  max(points[j][0],points[j][2])>=points[i][0]){
                    if(min(points[i][1],points[i][3])<=points[j][1] &&  max(points[i][1],points[i][3])>=points[j][1]){
                            mt[i][j]=true;
                            mt[j][i]=true;

                           // cout<<"inter "<<i<<" "<<j<<endl;

                    }
                }
            }else if(points[j][0]==points[j][2] && points[i][1]==points[i][3] ){
                if(min(points[i][0],points[i][2])<=points[j][0] &&  max(points[i][0],points[i][2])>=points[j][0]){
                    if(min(points[j][1],points[j][3])<=points[i][1] &&  max(points[j][1],points[j][3])>=points[i][1]){
                           // cout<<"inter "<<i<<" "<<j<<endl;
                           mt[i][j]=true;
                            mt[j][i]=true;
                    }
                }
            }
        }
    }

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

        dfs(root,0);

    }

    printf("%d\n",ans/2);

	return 0;
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
constexpr int inf = 0x3f3f3f3f;
constexpr double EPS = 1e-30;
constexpr double PI = atan(1) * 4;

template <typename T> inline bool chmax(T& x, T y) {return x < y ? x = y, 1 : 0;}
template <typename T> inline bool chmin(T& x, T y) {return x > y ? x = y, 1 : 0;}
inline int LSB(int i) {return (i & -i);}

constexpr int MAX = 1e4 + 5;

struct Segment{
    Segment* c[2];
    ll sum;

    Segment(){
        memset(c, 0, sizeof(c));
        sum = 0;
    }

    void combine(){
        sum = 0;
        for (int i = 0; i < 2; i++){
            if (c[i]) sum += c[i]->sum;
        }
    }
} *BIT[MAX + 5];

void update(Segment*& node, int l, int r, int ql, int qr, ll val){
    if (l > r || l > qr || r < ql || ql > qr) return;
    if (!node) node = new Segment();
    if (ql <= l && r <= qr){
        node->sum += val;
        return;
    }

    int mid = (l + r) >> 1;
    update(node->c[0], l, mid, ql, qr, val);
    update(node->c[1], mid + 1, r, ql, qr, val);
    node->combine();
}

ll query(Segment* node, int l, int r, int ql, int qr){
    if (l > r || l > qr || r < ql || ql > qr || !node) return 0;
    if (ql <= l && r <= qr) return node->sum;

    int mid = (l + r) >> 1;
    return query(node->c[0], l, mid, ql, qr) + query(node->c[1], mid + 1, r, ql, qr);
}

int n;
ll res;
//If int = 0, start point, else end point of segment
vector <pi> vert[MAX + 5], horizontal[MAX + 5];
vector <pair<pi, int> > seen; //Seen vertical lines already during the sweep

//Add val to y value "idx" to x value "x"
void add(int idx, int x, ll val){
    for (int i = idx; i <= MAX; i += LSB(i)){
        update(BIT[i], 1, MAX, x, x, val);
    }
}

//Query number of horizontal lines starting between x-coords 1 and x
ll get(int idx, int x){
    ll ret = 0;
    for (int i = idx; i; i -= LSB(i)) ret += query(BIT[i], 1, MAX, 1, x);
    return ret;
}

int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for (int i = 1, a, b, c, d; i <= n; i++){
        cin >> a >> b >> c >> d;
        a += 5001;
        b += 5001;
        c += 5001;
        d += 5001;

        //Vertical
        if (a == c){
            if (b > d) swap(b, d);
            vert[a].push_back({b, d});
        }
        else {
            //Horizontal
            if (a > c) swap(a, c);
            horizontal[a].push_back({b, a});
            horizontal[c].push_back({d, a});
        }
    }

    for (int i = 0; i <= MAX; i++){
        if (!vert[i].size()) continue;
        sort(vert[i].begin(), vert[i].end(), [](pi a, pi b){
            return a.first < b.first;
        });
    }

    for (int i = 1; i <= MAX; i++) BIT[i] = new Segment();
    for (int i = 1; i <= MAX; i++){
        for (auto j : vert[i]){
            //Vertical line, process these queries first
            for (auto k : seen){
                int top = min(k.first.second, j.second);
                int bottom = max(k.first.first, j.first);

                if (top > bottom){
                    ll many = get(top, k.second) - get(bottom - 1, k.second);
                    res += (many * (many - 1)) / 2;
                }
            }
        }

        for (auto j : horizontal[i]){
            //Horizontal Line
            if (j.second != i){
                add(j.first, j.second, -1);
            }
            else add(j.first, i, 1);
        }

        for (auto j : vert[i]){
            seen.push_back({j, i});
        }
    }

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


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
constexpr int inf = 0x3f3f3f3f;
constexpr double EPS = 1e-30;
constexpr double PI = atan(1) * 4;

template <typename T> inline bool chmax(T& x, T y) {return x < y ? x = y, 1 : 0;}
template <typename T> inline bool chmin(T& x, T y) {return x > y ? x = y, 1 : 0;}
inline int LSB(int i) {return (i & -i);}

constexpr int MAX = 1e4 + 5;

struct Segment{
    Segment* c[2];
    ll lazy;
    ll sum;

    Segment(){
        memset(c, 0, sizeof(c));
        lazy = sum = 0;
    }

    void combine(){
        sum = 0;
        for (int i = 0; i < 2; i++){
            if (c[i]) sum += c[i]->sum;
        }
    }
} *BIT[MAX + 5];

void update(Segment*& node, int l, int r, int ql, int qr, ll val){
    if (l > r || l > qr || r < ql || ql > qr) return;
    if (!node) node = new Segment();
    if (ql <= l && r <= qr){
        node->sum += val;
        return;
    }

    int mid = (l + r) >> 1;
    update(node->c[0], l, mid, ql, qr, val);
    update(node->c[1], mid + 1, r, ql, qr, val);
    node->combine();
}

ll query(Segment*& node, int l, int r, int ql, int qr){
    if (l > r || l > qr || r < ql || ql > qr || !node) return 0;
    if (ql <= l && r <= qr) return node->sum;

    int mid = (l + r) >> 1;
    return query(node->c[0], l, mid, ql, qr) + query(node->c[1], mid + 1, r, ql, qr);
}

int n;
ll res;
//If int = 0, start point, else end point of segment
vector <pi> vert[MAX + 5], horizontal[MAX + 5];
vector <pair<pi, int> > seen; //Seen vertical lines already during the sweep

//Add val to y value "idx" to x value "x"
void add(int idx, int x, int val){
    for (int i = idx; i <= MAX; i += LSB(i)){
        update(BIT[i], 1, MAX, x, x, val);
    }
}

//Query number of horizontal lines starting between x-coords 1 and x
ll get(int idx, int x){
    ll ret = 0;
    for (int i = idx; i; i -= LSB(i)) ret += query(BIT[i], 1, MAX, 1, x);
    return ret;
}

int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for (int i = 1, a, b, c, d; i <= n; i++){
        cin >> a >> b >> c >> d;
        a += 5001;
        b += 5001;
        c += 5001;
        d += 5001;

        //Vertical
        if (a == c){
            if (b > d) swap(b, d);
            vert[a].push_back({b, d});
        }
        else {
            //Horizontal
            if (a > c) swap(a, c);
            horizontal[a].push_back({b, 0});
            horizontal[c].push_back({d, 1});
        }
    }

    for (int i = 0; i <= MAX; i++){
        if (!vert[i].size()) continue;
        sort(vert[i].begin(), vert[i].end(), [](pi a, pi b){
            return a.first < b.first;
        });
    }

    for (int i = 1; i <= MAX; i++) BIT[i] = new Segment();
    for (int i = 1; i <= MAX; i++){
        for (auto j : vert[i]){
            //Vertical line, process these queries first
            for (auto k : seen){
                int top = min(k.first.second, j.second);
                int bottom = max(k.first.first, j.first);

                if (top > bottom){
                    ll many = get(top, k.second) - get(bottom - 1, k.second);
                    res += (many * (many - 1)) / 2;
                }
            }
        }

        for (auto j : horizontal[i]){
            //Horizontal Line
            if (j.second){
                add(j.first, i, -1);
            }
            else add(j.first, i, 1);
        }

        for (auto j : vert[i]){
            seen.push_back({j, i});
        }
    }

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


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
constexpr int inf = 0x3f3f3f3f;
constexpr double EPS = 1e-30;
constexpr double PI = atan(1) * 4;

template <typename T> inline bool chmax(T& x, T y) {return x < y ? x = y, 1 : 0;}
template <typename T> inline bool chmin(T& x, T y) {return x > y ? x = y, 1 : 0;}
inline int LSB(int i) {return (i & -i);}

constexpr int MAX = 1e4 + 5;

struct Segment{
    Segment* c[2];
    ll sum;

    Segment(){
        memset(c, 0, sizeof(c));
        sum = 0;
    }

    void combine(){
        sum = 0;
        for (int i = 0; i < 2; i++){
            if (c[i]) sum += c[i]->sum;
        }
    }
} *BIT[MAX + 5];

void update(Segment*& node, int l, int r, int ql, int qr, ll val){
    if (l > r || l > qr || r < ql || ql > qr) return;
    if (!node) node = new Segment();
    if (ql <= l && r <= qr){
        node->sum += val;
        return;
    }

    int mid = (l + r) >> 1;
    update(node->c[0], l, mid, ql, qr, val);
    update(node->c[1], mid + 1, r, ql, qr, val);
    node->combine();
}

ll query(Segment* node, int l, int r, int ql, int qr){
    if (l > r || l > qr || r < ql || ql > qr || !node) return 0;
    if (ql <= l && r <= qr) return node->sum;

    int mid = (l + r) >> 1;
    return query(node->c[0], l, mid, ql, qr) + query(node->c[1], mid + 1, r, ql, qr);
}

int n;
ll res;
//If int = 0, start point, else end point of segment
vector <pi> vert[MAX + 5], horizontal[MAX + 5];
vector <pair<pi, int> > seen; //Seen vertical lines already during the sweep

//Add val to y value "idx" to x value "x"
void add(int idx, int x, ll val){
    for (int i = idx; i <= MAX; i += LSB(i)){
        update(BIT[i], 1, MAX, x, x, val);
    }
}

//Query number of horizontal lines starting between x-coords 1 and x
ll get(int idx, int x){
    ll ret = 0;
    for (int i = idx; i; i -= LSB(i)) ret += query(BIT[i], 1, MAX, 1, x);
    return ret;
}

int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for (int i = 1, a, b, c, d; i <= n; i++){
        cin >> a >> b >> c >> d;
        a += 5001;
        b += 5001;
        c += 5001;
        d += 5001;

        //Vertical
        if (a == c){
            if (b > d) swap(b, d);
            vert[a].push_back({b, d});
        }
        else {
            //Horizontal
            if (a > c) swap(a, c);
            horizontal[a].push_back({b, 0});
            horizontal[c].push_back({d, 1});
        }
    }

    for (int i = 0; i <= MAX; i++){
        if (!vert[i].size()) continue;
        sort(vert[i].begin(), vert[i].end(), [](pi a, pi b){
            return a.first < b.first;
        });
    }

    for (int i = 1; i <= MAX; i++) BIT[i] = new Segment();
    for (int i = 1; i <= MAX; i++){
        for (auto j : vert[i]){
            //Vertical line, process these queries first
            for (auto k : seen){
                int top = min(k.first.second, j.second);
                int bottom = max(k.first.first, j.first);

                if (top > bottom){
                    ll many = get(top, k.second) - get(bottom - 1, k.second);
                    res += (many * (many - 1)) / 2;
                }
            }
        }

        for (auto j : horizontal[i]){
            //Horizontal Line
            if (j.second){
                add(j.first, i, -1);
            }
            else add(j.first, i, 1);
        }

        for (auto j : vert[i]){
            seen.push_back({j, i});
        }
    }

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


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
constexpr int inf = 0x3f3f3f3f;
constexpr double EPS = 1e-30;
constexpr double PI = atan(1) * 4;

template <typename T> inline bool chmax(T& x, T y) {return x < y ? x = y, 1 : 0;}
template <typename T> inline bool chmin(T& x, T y) {return x > y ? x = y, 1 : 0;}
inline int LSB(int i) {return (i & -i);}

constexpr int MAX = 1e4 + 5;

struct Segment{
    Segment* c[2];
    ll sum;

    Segment(){
        memset(c, 0, sizeof(c));
        sum = 0;
    }

    void combine(){
        sum = 0;
        for (int i = 0; i < 2; i++){
            if (c[i]) sum += c[i]->sum;
        }
    }
} *BIT[MAX + 5];

void update(Segment*& node, int l, int r, int ql, int qr, ll val){
    if (l > r || l > qr || r < ql || ql > qr) return;
    if (!node) node = new Segment();
    if (ql <= l && r <= qr){
        node->sum += val;
        return;
    }

    int mid = (l + r) >> 1;
    update(node->c[0], l, mid, ql, qr, val);
    update(node->c[1], mid + 1, r, ql, qr, val);
    node->combine();
}

ll query(Segment* node, int l, int r, int ql, int qr){
    if (l > r || l > qr || r < ql || ql > qr || !node) return 0;
    if (ql <= l && r <= qr) return node->sum;

    int mid = (l + r) >> 1;
    return query(node->c[0], l, mid, ql, qr) + query(node->c[1], mid + 1, r, ql, qr);
}

int n;
ll res;
//If int = 0, start point, else end point of segment
vector <pi> vert[MAX + 5], horizontal[MAX + 5];
vector <pair<pi, int> > seen; //Seen vertical lines already during the sweep

//Add val to y value "idx" to x value "x"
void add(int idx, int x, ll val){
    for (int i = idx; i <= MAX; i += LSB(i)){
        update(BIT[i], 1, MAX, x, x, val);
    }
}

//Query number of horizontal lines starting between x-coords 1 and x
ll get(int idx, int x){
    ll ret = 0;
    for (int i = idx; i; i -= LSB(i)) ret += query(BIT[i], 1, MAX, 1, x);
    return ret;
}

int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for (int i = 1, a, b, c, d; i <= n; i++){
        cin >> a >> b >> c >> d;
        a += 5001;
        b += 5001;
        c += 5001;
        d += 5001;

        //Vertical
        if (a == c){
            if (b > d) swap(b, d);
            vert[a].push_back({b, d});
        }
        else {
            //Horizontal
            if (a > c) swap(a, c);
            horizontal[a].push_back({b, 0});
            horizontal[c].push_back({d, 1});
        }
    }

    if (n < 4) return !printf("0\n");
    for (int i = 0; i <= MAX; i++){
        if (!vert[i].size()) continue;
        sort(vert[i].begin(), vert[i].end(), [](pi a, pi b){
            return a.first < b.first;
        });
    }

    for (int i = 1; i <= MAX; i++) BIT[i] = new Segment();
    for (int i = 1; i <= MAX; i++){
        for (auto j : vert[i]){
            //Vertical line, process these queries first
            for (auto k : seen){
                int top = min(k.first.second, j.second);
                int bottom = max(k.first.first, j.first);

                if (top > bottom){
                    ll many = get(top, k.second) - get(bottom - 1, k.second);
                    res += (many * (many - 1)) / 2;
                }
            }
        }

        for (auto j : horizontal[i]){
            //Horizontal Line
            if (j.second){
                add(j.first, i, -1);
            }
            else add(j.first, i, 1);
        }

        for (auto j : vert[i]){
            seen.push_back({j, i});
        }
    }

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


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei,op;
	// op=1:col op=0:lin
}lin[5005];

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		if(a == c){
			lin[i].op = 1;
			lin[i].hei = a;
			lin[i].f = min(b,d);
			lin[i].t = max(b,d);
		}
		else{
			lin[i].op = 0;
			lin[i].hei = b;
			lin[i].f = min(a,c);
			lin[i].t = max(a,c);
		}
	}
	for(LL i = 5000;i >= -5000;i --){
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].t == i && lin[j].f != lin[j].t) cinq[j] = 1;
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 0 && lin[j].hei == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 0) continue;
					if(!cinq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[j] ++;
						}
					}
				}
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(j == k) continue;
					if(!linq[k]) continue;
					sum += calculat(min(linq[j],linq[k]));
				}
			}
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].f == i && cinq[j]){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(!linq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[k] --;
						}
					}
				}
				cinq[j] = 0;
			}
		}
	}
	cout << sum << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei,op;
	// op=1:col op=0:lin
}lin[5005];

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		if(a == c){
			lin[i].op = 1;
			lin[i].hei = a;
			lin[i].f = min(b,d);
			lin[i].t = max(b,d);
		}
		else{
			lin[i].op = 0;
			lin[i].hei = b;
			lin[i].f = min(a,c);
			lin[i].t = max(a,c);
		}
	}
	for(LL i = 5000;i >= -5000;i --){
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].t == i) cinq[j] = 1;
			if(lin[j].op == 0 && lin[j].hei == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 0) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[j] ++;
						}
					}
				}
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(j == k) continue;
//					if(min(linq[j],linq[k]) >= 2){
//						cout << j << ' ' << k << endl;
//					}
					sum += calculat(min(linq[j],linq[k]));
				}
			}
			if(lin[j].op == 1 && lin[j].f == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[k] --;
//							cout << "F " << k << ' ' << linq[k] << endl;
						}
					}
				}
				cinq[j] = 0;
			}
		}
	}
	cout << sum << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei,op;
	// op=1:col op=0:lin
}lin[5005];

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		if(a == c){
			lin[i].op = 1;
			lin[i].hei = a;
			lin[i].f = min(b,d);
			lin[i].t = max(b,d);
		}
		else{
			lin[i].op = 0;
			lin[i].hei = b;
			lin[i].f = min(a,c);
			lin[i].t = max(a,c);
		}
	}
	for(LL i = 5000;i >= -5000;i --){
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].t == i) cinq[j] = 1;
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 0 && lin[j].hei == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 0) continue;
					if(!cinq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[j] ++;
						}
					}
				}
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(j == k) continue;
//					if(min(linq[j],linq[k]) >= 2){
//						cout << j << ' ' << k << endl;
//					}
					sum += calculat(min(linq[j],linq[k]));
				}
			}
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].f == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							if(linq[k]) linq[k] --;
//							cout << "F " << k << ' ' << linq[k] << endl;
						}
					}
				}
				cinq[j] = 0;
			}
		}
	}
	cout << sum << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei,op;
	// op=1:col op=0:lin
}lin[5005];

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		if(a == c){
			lin[i].op = 1;
			lin[i].hei = a;
			lin[i].f = min(b,d);
			lin[i].t = max(b,d);
		}
		else{
			lin[i].op = 0;
			lin[i].hei = b;
			lin[i].f = min(a,c);
			lin[i].t = max(a,c);
		}
	}
	for(LL i = 5000;i >= -5000;i --){
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].t == i) cinq[j] = 1;
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 0 && lin[j].hei == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 0) continue;
					if(!cinq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[j] ++;
						}
					}
				}
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(j == k) continue;
					if(!linq[k]) continue;
					sum += calculat(min(linq[j],linq[k]));
				}
			}
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].f == i && cinq[j]){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(!linq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[k] --;
						}
					}
				}
				cinq[j] = 0;
			}
		}
	}
	cout << sum << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei,op;
	// op=1:col op=0:lin
}lin[5005];
bool cmp(node x,node y){
	return x.f < y.f;
}

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		if(a == c){
			lin[i].op = 1;
			lin[i].hei = a;
			lin[i].f = min(b,d);
			lin[i].t = max(b,d);
		}
		else{
			lin[i].op = 0;
			lin[i].hei = b;
			lin[i].f = min(a,c);
			lin[i].t = max(a,c);
		}
	}
	sort(lin + 1,lin + 1 + n,cmp);
	for(LL i = 1;i <= n;i ++){
		if(lin[i].op == -1) continue;
		for(LL j = 1;j <= n;j ++){
			if(lin[i].t == lin[j].f){
				lin[i].t = lin[j].t;
				lin[j].op = -1;
			}
		}
	}
	for(LL i = 5000;i >= -5000;i --){
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].t == i) cinq[j] = 1;
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 0 && lin[j].hei == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 0) continue;
					if(!cinq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[j] ++;
						}
					}
				}
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(j == k) continue;
					if(!linq[k]) continue;
					sum += calculat(min(linq[j],linq[k]));
				}
			}
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].f == i && cinq[j]){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(!linq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[k] --;
						}
					}
				}
				cinq[j] = 0;
			}
		}
	}
	cout << sum << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei,op;
	// op=1:col op=0:lin
}lin[5005];

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		if(a == c){
			lin[i].op = 1;
			lin[i].hei = a;
			lin[i].f = min(b,d);
			lin[i].t = max(b,d);
		}
		else{
			lin[i].op = 0;
			lin[i].hei = b;
			lin[i].f = min(a,c);
			lin[i].t = max(a,c);
		}
	}
	for(LL i = 5000;i >= -5000;i --){
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].t == i) cinq[j] = 1;
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 0 && lin[j].hei == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 0) continue;
					if(!cinq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[j] ++;
						}
					}
				}
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(j == k) continue;
					if(!linq[k]) continue;
					sum += calculat(min(linq[j],linq[k]));
				}
			}
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].f == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(!linq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[k] --;
						}
					}
				}
				cinq[j] = 0;
			}
		}
	}
	cout << sum << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei,op;
	// op=1:col op=0:lin
}lin[5005];

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		if(a == c){
			lin[i].op = 1;
			lin[i].hei = a;
			lin[i].f = min(b,d);
			lin[i].t = max(b,d);
		}
		else{
			lin[i].op = 0;
			lin[i].hei = b;
			lin[i].f = min(a,c);
			lin[i].t = max(a,c);
		}
	}
	for(LL i = 5000;i >= -5000;i --){
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].t == i && lin[j].f != lin[j].t) cinq[j] = 1;
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 0 && lin[j].hei == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 0) continue;
					if(!cinq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[j] ++;
						}
					}
				}
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(j == k) continue;
					if(!linq[k]) continue;
					sum += calculat(min(linq[j],linq[k]));
				}
			}
		}
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].f == i && linq[j]){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(!linq[k]) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[k] --;
						}
					}
				}
				cinq[j] = 0;
			}
		}
	}
	cout << sum << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#define lowbit(x) ((x) & (-(x)))
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};
LL tr[10005] = {0};

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei;
}lin[5005],col[5005];
LL lcn = 0,ccn = 0;

bool cmp1(node x,node y){
	return x.t < y.t;
}
bool cmp2(node x,node y){
	return x.hei < y.hei;
}

void modify(LL x,LL v){
	for(;x <= 10001;x += lowbit(x)){
		tr[x] += v;
	}
}

LL query(LL x){
	LL ret = 0;
	for(;x;x -= lowbit(x)){
		ret += tr[x];
	}
	return ret;
}

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

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		a += 5001; b += 5001; c += 5001; d += 5001;
		if(a == c){
			++ ccn;
			col[ccn].hei = a;
			col[ccn].f = min(b,d);
			col[ccn].t = max(b,d);
		}
		else{
			++ lcn;
			lin[lcn].hei = b;
			lin[lcn].f = min(a,c);
			lin[lcn].t = max(a,c);
		}
	}
	sort(lin + 1,lin + 1 + lcn,cmp2);
	sort(col + 1,col + 1 + ccn,cmp1);
//	for(LL i = 1;i <= lcn;i ++) printf("%lld %lld %lld\n",lin[i].f,lin[i].t,lin[i].hei);
//	for(LL i = 1;i <= ccn;i ++) printf("%lld %lld %lld\n",col[i].f,col[i].t,col[i].hei);
	for(LL i = 1;i <= lcn;i ++){
		memset(tr,0,sizeof(tr));
		for(LL j = 1;j <= ccn;j ++){
			if(col[j].f <= lin[i].hei && lin[i].hei <= col[j].t){
				if(lin[i].f <= col[j].hei && col[j].hei <= lin[i].t){
					modify(col[j].hei,1);
				}
			}
		}
		LL cur = 1,tmp;
		for(LL j = i + 1;j <= lcn;j ++){
			if(lin[i].hei == lin[j].hei) continue;
			while(1){
				if(cur <= ccn && col[cur].t < lin[j].hei){
					modify(col[cur].hei,-1);
					cur ++;
				}
				else break;
			}
			tmp = query_sum(lin[j].f,lin[j].t);
//			cout << i << ' ' << j << ' ' << tmp << endl;
			sum += ((tmp) * (tmp - 1)) / 2;
		}
	}
	cout << sum << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#define lowbit(x) ((x) & (-(x)))
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};
LL tr[10005] = {0};
LL q[5005] = {0},inq;

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei;
}lin[5005],col[5005];
LL lcn = 0,ccn = 0;

bool cmp1(node x,node y){
	return x.t < y.t;
}
bool cmp2(node x,node y){
	return x.hei < y.hei;
}

void modify(LL x,LL v){
	for(;x <= 10001;x += lowbit(x)){
		tr[x] += v;
	}
}

LL query(LL x){
	LL ret = 0;
	for(;x;x -= lowbit(x)){
		ret += tr[x];
	}
	return ret;
}

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

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		a += 5001; b += 5001; c += 5001; d += 5001;
		if(a == c){
			++ ccn;
			col[ccn].hei = a;
			col[ccn].f = min(b,d);
			col[ccn].t = max(b,d);
		}
		else{
			++ lcn;
			lin[lcn].hei = b;
			lin[lcn].f = min(a,c);
			lin[lcn].t = max(a,c);
		}
	}
	sort(lin + 1,lin + 1 + lcn,cmp2);
	sort(col + 1,col + 1 + ccn,cmp1);
//	for(LL i = 1;i <= lcn;i ++) printf("%lld %lld %lld\n",lin[i].f,lin[i].t,lin[i].hei);
//	for(LL i = 1;i <= ccn;i ++) printf("%lld %lld %lld\n",col[i].f,col[i].t,col[i].hei);
	for(LL i = 1;i <= lcn;i ++){
		memset(tr,0,sizeof(tr));
		inq = 0;
		for(LL j = 1;j <= ccn;j ++){
			if(col[j].f <= lin[i].hei && lin[i].hei <= col[j].t){
				if(lin[i].f <= col[j].hei && col[j].hei <= lin[i].t){
					modify(col[j].hei,1);
					q[++ inq] = j;
				}
			}
		}
		LL cur = 1,tmp;
		for(LL j = i + 1;j <= lcn;j ++){
			if(lin[i].hei == lin[j].hei) continue;
			while(1){
				if(cur <= inq && col[q[cur]].t < lin[j].hei){
					modify(col[q[cur]].hei,-1);
					cur ++;
				}
				else break;
			}
			tmp = query_sum(lin[j].f,lin[j].t);
//			cout << i << ' ' << j << ' ' << tmp << endl;
			sum += ((tmp) * (tmp - 1)) / 2;
		}
	}
	cout << sum << endl;
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#pragma GCC optimize(2)
using namespace std;
typedef long long LL;

LL n,m,k,a,b,c,d,sum = 0;
LL cinq[5005] = {0};
LL linq[5005] = {0};

LL calculat(LL x){
	return ((x * (x - 1)) / 2);
}

struct node{
	LL f,t,hei,op;
	// op=1:col op=0:lin
}lin[5005];

int main(){
	ios::sync_with_stdio(false);
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> a >> b >> c >> d;
		if(a == c){
			lin[i].op = 1;
			lin[i].hei = a;
			lin[i].f = min(b,d);
			lin[i].t = max(b,d);
		}
		else{
			lin[i].op = 0;
			lin[i].hei = b;
			lin[i].f = min(a,c);
			lin[i].t = max(a,c);
		}
	}
	for(LL i = 5000;i >= -5000;i --){
		for(LL j = 1;j <= n;j ++){
			if(lin[j].op == 1 && lin[j].t == i) cinq[j] = 1;
			if(lin[j].op == 0 && lin[j].hei == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 0) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							linq[j] ++;
						}
					}
				}
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(j == k) continue;
//					if(min(linq[j],linq[k]) >= 2){
//						cout << j << ' ' << k << endl;
//					}
					sum += calculat(min(linq[j],linq[k]));
				}
			}
			if(lin[j].op == 1 && lin[j].f == i){
				for(LL k = 1;k <= n;k ++){
					if(lin[k].op == 1) continue;
					if(lin[j].f <= lin[k].hei && lin[k].hei <= lin[j].t){
						if(lin[k].f <= lin[j].hei && lin[j].hei <= lin[k].t){
							if(linq[k]) linq[k] --;
//							cout << "F " << k << ' ' << linq[k] << endl;
						}
					}
				}
				cinq[j] = 0;
			}
		}
	}
	cout << sum << endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

#define start_routine() int begtime = clock();
#define end_routine() int endtime = clock(); cerr << endl << "Time elapsed: " << (endtime - begtime)*1000/CLOCKS_PER_SEC << " ms"; return 0
#define speed() cin.tie(0), cout.tie(0), ios_base::sync_with_stdio(false)
// #define exit(a, b) return cout << a, b;

#define loop(i,a,b) for(ll i=a;i<b;i++)
#define all(v) v.begin(), v.end()

#define print(stuff) cout << stuff << endl
#define printc(stuff) for(auto x: stuff) cout << x << " "; cout << endl;
#define printPrec(stuff) cout << fixed << setprecision(15) << stuff << endl;
#define debug(stuff) cout << #stuff << ": " << stuff <<endl
#define debugc(stuff) cout << #stuff << ": "; for(auto x: stuff) cout << x << " "; cout << endl;
#define len length
#define ret0 return 0
#define ret return

#define ll long long
#define ld long double
#define fi first
#define endl '\n'
#define se second
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define fill(ar, x) memset(ar, x, sizeof ar)

#define vl vector<ll>
#define sl set<ll>
#define pll pair<ll, ll>
#define mll map<ll, ll>
#define pq priority_queue<ll>

// typedef tree<ll,null_type,less<ll>,rb_tree_tag,
// tree_order_statistics_node_update> indexed_set;

#define inf (long long int) 1e18
#define eps 0.000001
#define mod 1000000007
#define mod1 998244353
#define MAXN (ll)5e3+5

const ll nax = 2*MAXN + 10;
bool cmp(pair<pll, ll> &A, pair<pll, ll> &B){
    return A.se < B.se;
}

ll fenwick[nax]={0};
void update(ll x, ll val, ll n){
    for(; x<nax; x += x&(-x)){
        // debug(x);
        fenwick[x]+=val;
    }
}

ll query(ll x){
    ll res=0;
    for(; x>0; x -= x&(-x)){
        res+= fenwick[x];
    }
    return res;
}

void solve(){
    ll n;
    cin>>n;
    vector<pair<pll, ll>> horizontals, verticals; // horizontals -> right, left, y.. verticals -> top, bottom, x
    loop(i,0,n){
        ll x1, y1, x2, y2;
        cin>>x1>>y1>>x2>>y2;
        x1+=MAXN, y1+=MAXN, x2+=MAXN, y2+=MAXN;
        // x1+=10, y1+=10, x2+=10, y2+=10;
        if(x1==x2){
            ll top = max(y1, y2), bottom = min(y1, y2);
            verticals.pb(mp(mp(top, bottom), x1));
        }
        else if(y1==y2){
            ll right = max(x1, x2), left = min(x1, x2);
            horizontals.pb(mp(mp(right, left), y1));
        }
    }
    sort(all(horizontals), cmp);
    sort(all(verticals));
    reverse(all(verticals));

    // print("horizontals");
    // for(auto x: horizontals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }
    // print("verticals");
    // for(auto x: verticals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }

    ll ans = 0;
    for(ll i=0; i<horizontals.size(); i++){
        // print("first hor: "<<horizontals[i].fi.fi<<" "<<horizontals[i].fi.se<<" "<<horizontals[i].se);
        vector<pair<pll, ll>> valid;
        fill(fenwick, 0);
        for(auto x: verticals){
            // debug(x.fi.se <<" " << horizontals[i].se);
            if(x.fi.se <= horizontals[i].se){
                valid.pb(x);
            }
        }

        // print("valid");
        // for(auto x: valid){
        //     print(x.fi.fi<< " "<<x.fi.se<<" "<<x.se);
        // }
        ll ptr=0;
        for(ll j=horizontals.size()-1; j>i; j--){
            // print("second hor: "<<horizontals[j].fi.fi<<" "<<horizontals[j].fi.se<<" "<<horizontals[j].se);
            ll cnt = 0;
            while(ptr < valid.size()){
                if(valid[ptr].fi.fi >= horizontals[j].se){
                    // print("in");
                    update(valid[ptr].se, 1, n);
                    ptr++;
                }
                else break;
            }
            ll l = max(horizontals[i].fi.se, horizontals[j].fi.se);
            ll r = min(horizontals[i].fi.fi, horizontals[j].fi.fi);
            cnt = query(r) - query(l-1);
            ans += (cnt*(cnt-1))/2;
            // debug(cnt);
        }

    }
    print(ans);

}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    #ifndef ONLINE_JUDGE
        start_routine();
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif

    ll t = 1;
    // cin>>t;
    while(t--){
        solve();
    }

    #ifndef ONLINE_JUDGE
        end_routine();
    #endif
}


#include<bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

#define start_routine() int begtime = clock();
#define end_routine() int endtime = clock(); cerr << endl << "Time elapsed: " << (endtime - begtime)*1000/CLOCKS_PER_SEC << " ms"; return 0
#define speed() cin.tie(0), cout.tie(0), ios_base::sync_with_stdio(false)
// #define exit(a, b) return cout << a, b;

#define loop(i,a,b) for(ll i=a;i<b;i++)
#define all(v) v.begin(), v.end()

#define print(stuff) cout << stuff << endl
#define printc(stuff) for(auto x: stuff) cout << x << " "; cout << endl;
#define printPrec(stuff) cout << fixed << setprecision(15) << stuff << endl;
#define debug(stuff) cout << #stuff << ": " << stuff <<endl
#define debugc(stuff) cout << #stuff << ": "; for(auto x: stuff) cout << x << " "; cout << endl;
#define len length
#define ret0 return 0
#define ret return

#define ll long long
#define ld long double
#define fi first
#define endl '\n'
#define se second
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define fill(ar, x) memset(ar, x, sizeof ar)

#define vl vector<ll>
#define sl set<ll>
#define pll pair<ll, ll>
#define mll map<ll, ll>
#define pq priority_queue<ll>

// typedef tree<ll,null_type,less<ll>,rb_tree_tag,
// tree_order_statistics_node_update> indexed_set;

#define inf (long long int) 1e18
#define eps 0.000001
#define mod 1000000007
#define mod1 998244353
#define MAXN (ll)5e3+5

const ll nax = 2*MAXN + 10;
bool cmp(pair<pll, ll> &A, pair<pll, ll> &B){
    return A.se < B.se;
}

ll fenwick[nax]={0};
void update(ll x, ll val, ll n){
    for(; x<=nax; x += x&(-x)){
        // debug(x);
        fenwick[x]+=val;
    }
}

ll query(ll x){
    ll res=0;
    for(; x>0; x -= x&(-x)){
        res+= fenwick[x];
    }
    return res;
}

void solve(){
    ll n;
    cin>>n;
    vector<pair<pll, ll>> horizontals, verticals; // horizontals -> right, left, y.. verticals -> top, bottom, x
    loop(i,0,n){
        ll x1, y1, x2, y2;
        cin>>x1>>y1>>x2>>y2;
        x1+=MAXN, y1+=MAXN, x2+=MAXN, y2+=MAXN;
        // x1+=10, y1+=10, x2+=10, y2+=10;
        if(x1==x2){
            ll top = max(y1, y2), bottom = min(y1, y2);
            verticals.pb(mp(mp(top, bottom), x1));
        }
        else if(y1==y2){
            ll right = max(x1, x2), left = min(x1, x2);
            horizontals.pb(mp(mp(right, left), y1));
        }
    }
    sort(all(horizontals), cmp);
    sort(all(verticals));
    reverse(all(verticals));

    // print("horizontals");
    // for(auto x: horizontals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }
    // print("verticals");
    // for(auto x: verticals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }

    ll ans = 0;
    for(ll i=0; i<horizontals.size(); i++){
        // print("first hor: "<<horizontals[i].fi.fi<<" "<<horizontals[i].fi.se<<" "<<horizontals[i].se);
        vector<pair<pll, ll>> valid;
        fill(fenwick, 0);
        for(auto x: verticals){
            // debug(x.fi.se <<" " << horizontals[i].se);
            if(x.fi.se <= horizontals[i].se){
                valid.pb(x);
            }
        }

        // print("valid");
        // for(auto x: valid){
        //     print(x.fi.fi<< " "<<x.fi.se<<" "<<x.se);
        // }
        ll ptr=0;
        for(ll j=horizontals.size()-1; j>i; j--){
            // print("second hor: "<<horizontals[j].fi.fi<<" "<<horizontals[j].fi.se<<" "<<horizontals[j].se);
            ll cnt = 0;
            while(ptr < valid.size()){
                if(valid[ptr].fi.fi >= horizontals[j].se){
                    // print("in");
                    if(query(valid[ptr].se)-query(valid[ptr].se-1) == 0)update(valid[ptr].se, 1, n);
                    ptr++;
                }
                else break;
            }
            ll l = max(horizontals[i].fi.se, horizontals[j].fi.se);
            ll r = min(horizontals[i].fi.fi, horizontals[j].fi.fi);
            if(r>=l) cnt = query(r) - query(l-1);
            ans += (cnt*(cnt-1))/2;
            // debug(cnt);
        }

    }
    print(ans);

}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    #ifndef ONLINE_JUDGE
        start_routine();
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif

    ll t = 1;
    // cin>>t;
    while(t--){
        solve();
    }

    #ifndef ONLINE_JUDGE
        end_routine();
    #endif
}


#include<bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

#define start_routine() int begtime = clock();
#define end_routine() int endtime = clock(); cerr << endl << "Time elapsed: " << (endtime - begtime)*1000/CLOCKS_PER_SEC << " ms"; return 0
#define speed() cin.tie(0), cout.tie(0), ios_base::sync_with_stdio(false)
// #define exit(a, b) return cout << a, b;

#define loop(i,a,b) for(ll i=a;i<b;i++)
#define all(v) v.begin(), v.end()

#define print(stuff) cout << stuff << endl
#define printc(stuff) for(auto x: stuff) cout << x << " "; cout << endl;
#define printPrec(stuff) cout << fixed << setprecision(15) << stuff << endl;
#define debug(stuff) cout << #stuff << ": " << stuff <<endl
#define debugc(stuff) cout << #stuff << ": "; for(auto x: stuff) cout << x << " "; cout << endl;
#define len length
#define ret0 return 0
#define ret return

#define ll long long
#define ld long double
#define fi first
#define endl '\n'
#define se second
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define fill(ar, x) memset(ar, x, sizeof ar)

#define vl vector<ll>
#define sl set<ll>
#define pll pair<ll, ll>
#define mll map<ll, ll>
#define pq priority_queue<ll>

// typedef tree<ll,null_type,less<ll>,rb_tree_tag,
// tree_order_statistics_node_update> indexed_set;

#define inf (long long int) 1e18
#define eps 0.000001
#define mod 1000000007
#define mod1 998244353
#define MAXN (ll)5e3+5

const ll nax = 2*MAXN + 10;
bool cmp(pair<pll, ll> &A, pair<pll, ll> &B){
    return A.se < B.se;
}

ll fenwick[nax]={0};
void update(ll x, ll val, ll n){
    for(; x<nax; x += x&(-x)){
        // debug(x);
        fenwick[x]+=val;
    }
}

ll query(ll x){
    ll res=0;
    for(; x>0; x -= x&(-x)){
        res+= fenwick[x];
    }
    return res;
}

void solve(){
    ll n;
    cin>>n;
    vector<pair<pll, ll>> horizontals, verticals; // horizontals -> right, left, y.. verticals -> top, bottom, x
    loop(i,0,n){
        ll x1, y1, x2, y2;
        cin>>x1>>y1>>x2>>y2;
        x1+=MAXN, y1+=MAXN, x2+=MAXN, y2+=MAXN;
        // x1+=10, y1+=10, x2+=10, y2+=10;
        if(x1==x2){
            ll top = max(y1, y2), bottom = min(y1, y2);
            verticals.pb(mp(mp(top, bottom), x1));
        }
        else if(y1==y2){
            ll right = max(x1, x2), left = min(x1, x2);
            horizontals.pb(mp(mp(right, left), y1));
        }
    }
    sort(all(horizontals), cmp);
    sort(all(verticals));
    reverse(all(verticals));

    // print("horizontals");
    // for(auto x: horizontals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }
    // print("verticals");
    // for(auto x: verticals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }

    ll ans = 0;
    for(ll i=0; i<horizontals.size(); i++){
        // print("first hor: "<<horizontals[i].fi.fi<<" "<<horizontals[i].fi.se<<" "<<horizontals[i].se);
        vector<pair<pll, ll>> valid;
        fill(fenwick, 0);
        for(auto x: verticals){
            // debug(x.fi.se <<" " << horizontals[i].se);
            if(x.fi.se <= horizontals[i].se){
                valid.pb(x);
            }
        }

        // print("valid");
        // for(auto x: valid){
        //     print(x.fi.fi<< " "<<x.fi.se<<" "<<x.se);
        // }
        ll ptr=0;
        for(ll j=horizontals.size()-1; j>i; j--){
            // print("second hor: "<<horizontals[j].fi.fi<<" "<<horizontals[j].fi.se<<" "<<horizontals[j].se);
            ll cnt = 0;
            while(ptr < valid.size()){
                if(valid[ptr].fi.fi >= horizontals[j].se){
                    // print("in");
                    if(query(valid[ptr].se)-query(valid[ptr].se-1) == 0)update(valid[ptr].se, 1, n);
                    ptr++;
                }
                else break;
            }
            ll l = max(horizontals[i].fi.se, horizontals[j].fi.se);
            ll r = min(horizontals[i].fi.fi, horizontals[j].fi.fi);
            cnt = query(r) - query(l-1);
            ans += (cnt*(cnt-1))/2;
            // debug(cnt);
        }

    }
    print(ans);

}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    #ifndef ONLINE_JUDGE
        start_routine();
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif

    ll t = 1;
    // cin>>t;
    while(t--){
        solve();
    }

    #ifndef ONLINE_JUDGE
        end_routine();
    #endif
}


#include<bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

#define start_routine() int begtime = clock();
#define end_routine() int endtime = clock(); cerr << endl << "Time elapsed: " << (endtime - begtime)*1000/CLOCKS_PER_SEC << " ms"; return 0
#define speed() cin.tie(0), cout.tie(0), ios_base::sync_with_stdio(false)
// #define exit(a, b) return cout << a, b;

#define loop(i,a,b) for(ll i=a;i<b;i++)
#define all(v) v.begin(), v.end()

#define print(stuff) cout << stuff << endl
#define printc(stuff) for(auto x: stuff) cout << x << " "; cout << endl;
#define printPrec(stuff) cout << fixed << setprecision(15) << stuff << endl;
#define debug(stuff) cout << #stuff << ": " << stuff <<endl
#define debugc(stuff) cout << #stuff << ": "; for(auto x: stuff) cout << x << " "; cout << endl;
#define len length
#define ret0 return 0
#define ret return

#define ll long long
#define ld long double
#define fi first
#define endl '\n'
#define se second
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define fill(ar, x) memset(ar, x, sizeof ar)

#define vl vector<ll>
#define sl set<ll>
#define pll pair<ll, ll>
#define mll map<ll, ll>
#define pq priority_queue<ll>

// typedef tree<ll,null_type,less<ll>,rb_tree_tag,
// tree_order_statistics_node_update> indexed_set;

#define inf (long long int) 1e18
#define eps 0.000001
#define mod 1000000007
#define mod1 998244353
#define MAXN (ll)5e3+5

const ll nax = 2*MAXN + 10;
bool cmp(pair<pll, ll> &A, pair<pll, ll> &B){
    return A.se < B.se;
}

ll fenwick[nax]={0};
void update(ll x, ll val, ll n){
    for(; x<nax; x += x&(-x)){
        // debug(x);
        fenwick[x]+=val;
    }
}

ll query(ll x){
    ll res=0;
    for(; x>0; x -= x&(-x)){
        res+= fenwick[x];
    }
    return res;
}

void solve(){
    ll n;
    cin>>n;
    vector<pair<pll, ll>> horizontals, verticals; // horizontals -> right, left, y.. verticals -> top, bottom, x
    loop(i,0,n){
        ll x1, y1, x2, y2;
        cin>>x1>>y1>>x2>>y2;
        // x1+=MAXN, y1+=MAXN, x2+=MAXN, y2+=MAXN;
        x1+=10, y1+=10, x2+=10, y2+=10;
        if(x1==x2){
            ll top = max(y1, y2), bottom = min(y1, y2);
            verticals.pb(mp(mp(top, bottom), x1));
        }
        else if(y1==y2){
            ll right = max(x1, x2), left = min(x1, x2);
            horizontals.pb(mp(mp(right, left), y1));
        }
    }
    sort(all(horizontals), cmp);
    sort(all(verticals));
    reverse(all(verticals));

    // print("horizontals");
    // for(auto x: horizontals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }
    // print("verticals");
    // for(auto x: verticals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }

    ll ans = 0;
    for(ll i=0; i<horizontals.size(); i++){
        // print("first hor: "<<horizontals[i].fi.fi<<" "<<horizontals[i].fi.se<<" "<<horizontals[i].se);
        vector<pair<pll, ll>> valid;
        fill(fenwick, 0);
        for(auto x: verticals){
            // debug(x.fi.se <<" " << horizontals[i].se);
            if(x.fi.se <= horizontals[i].se){
                valid.pb(x);
            }
        }

        // print("valid");
        // for(auto x: valid){
        //     print(x.fi.fi<< " "<<x.fi.se<<" "<<x.se);
        // }
        ll ptr=0;
        for(ll j=horizontals.size()-1; j>i; j--){
            // print("second hor: "<<horizontals[j].fi.fi<<" "<<horizontals[j].fi.se<<" "<<horizontals[j].se);
            ll cnt = 0;
            while(ptr < valid.size()){
                if(valid[ptr].fi.fi >= horizontals[j].se){
                    // print("in");
                    update(valid[ptr].se, 1, n);
                    ptr++;
                }
                else break;
            }
            ll l = max(horizontals[i].fi.se, horizontals[j].fi.se);
            ll r = min(horizontals[i].fi.fi, horizontals[j].fi.fi);
            cnt = query(r) - query(l-1);
            ans += (cnt*(cnt-1))/2;
            // debug(cnt);
        }

    }
    print(ans);

}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    #ifndef ONLINE_JUDGE
        start_routine();
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif

    ll t = 1;
    // cin>>t;
    while(t--){
        solve();
    }

    #ifndef ONLINE_JUDGE
        end_routine();
    #endif
}


#include<bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

#define start_routine() int begtime = clock();
#define end_routine() int endtime = clock(); cerr << endl << "Time elapsed: " << (endtime - begtime)*1000/CLOCKS_PER_SEC << " ms"; return 0
#define speed() cin.tie(0), cout.tie(0), ios_base::sync_with_stdio(false)
// #define exit(a, b) return cout << a, b;

#define loop(i,a,b) for(ll i=a;i<b;i++)
#define all(v) v.begin(), v.end()

#define print(stuff) cout << stuff << endl
#define printc(stuff) for(auto x: stuff) cout << x << " "; cout << endl;
#define printPrec(stuff) cout << fixed << setprecision(15) << stuff << endl;
#define debug(stuff) cout << #stuff << ": " << stuff <<endl
#define debugc(stuff) cout << #stuff << ": "; for(auto x: stuff) cout << x << " "; cout << endl;
#define len length
#define ret0 return 0
#define ret return

#define ll long long
#define ld long double
#define fi first
#define endl '\n'
#define se second
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define fill(ar, x) memset(ar, x, sizeof ar)

#define vl vector<ll>
#define sl set<ll>
#define pll pair<ll, ll>
#define mll map<ll, ll>
#define pq priority_queue<ll>

// typedef tree<ll,null_type,less<ll>,rb_tree_tag,
// tree_order_statistics_node_update> indexed_set;

#define inf (long long int) 1e18
#define eps 0.000001
#define mod 1000000007
#define mod1 998244353
#define MAXN (ll)5e3+5

const ll nax = 2*MAXN + 10;
bool cmp(pair<pll, ll> &A, pair<pll, ll> &B){
    return A.se < B.se;
}

ll fenwick[nax]={0};
void update(ll x, ll val, ll n){
    for(; x<=nax; x += x&(-x)){
        // debug(x);
        fenwick[x]+=val;
    }
}

ll query(ll x){
    ll res=0;
    for(; x>0; x -= x&(-x)){
        res+= fenwick[x];
    }
    return res;
}

void solve(){
    ll n;
    cin>>n;
    vector<pair<pll, ll>> horizontals, verticals; // horizontals -> right, left, y.. verticals -> top, bottom, x
    loop(i,0,n){
        ll x1, y1, x2, y2;
        cin>>x1>>y1>>x2>>y2;
        x1+=MAXN, y1+=MAXN, x2+=MAXN, y2+=MAXN;
        // x1+=10, y1+=10, x2+=10, y2+=10;
        if(x1==x2){
            ll top = max(y1, y2), bottom = min(y1, y2);
            verticals.pb(mp(mp(top, bottom), x1));
        }
        else if(y1==y2){
            ll right = max(x1, x2), left = min(x1, x2);
            horizontals.pb(mp(mp(right, left), y1));
        }
    }
    sort(all(horizontals), cmp);
    sort(all(verticals));
    reverse(all(verticals));

    // print("horizontals");
    // for(auto x: horizontals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }
    // print("verticals");
    // for(auto x: verticals){
    //     print(x.fi.fi<<" "<<x.fi.se<<" "<<x.se);
    // }

    ll ans = 0;
    for(ll i=0; i<horizontals.size(); i++){
        // print("first hor: "<<horizontals[i].fi.fi<<" "<<horizontals[i].fi.se<<" "<<horizontals[i].se);
        vector<pair<pll, ll>> valid;
        fill(fenwick, 0);
        for(auto x: verticals){
            // debug(x.fi.se <<" " << horizontals[i].se);
            if(x.fi.se <= horizontals[i].se){
                valid.pb(x);
            }
        }

        // print("valid");
        // for(auto x: valid){
        //     print(x.fi.fi<< " "<<x.fi.se<<" "<<x.se);
        // }
        ll ptr=0;
        for(ll j=horizontals.size()-1; j>i; j--){
            // print("second hor: "<<horizontals[j].fi.fi<<" "<<horizontals[j].fi.se<<" "<<horizontals[j].se);
            ll cnt = 0;
            while(ptr < valid.size()){
                if(valid[ptr].fi.fi >= horizontals[j].se){
                    // print("in");
                    if(query(valid[ptr].se)-query(valid[ptr].se-1) == 0)update(valid[ptr].se, 1, n);
                    ptr++;
                }
                else break;
            }
            ll l = max(horizontals[i].fi.se, horizontals[j].fi.se);
            ll r = min(horizontals[i].fi.fi, horizontals[j].fi.fi);
            cnt = query(r) - query(l-1);
            ans += (cnt*(cnt-1))/2;
            // debug(cnt);
        }

    }
    print(ans);

}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    #ifndef ONLINE_JUDGE
        start_routine();
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
    #endif

    ll t = 1;
    // cin>>t;
    while(t--){
        solve();
    }

    #ifndef ONLINE_JUDGE
        end_routine();
    #endif
}


/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author tatsumack
 */

#include <iostream>
#include <fstream>

#include <iostream>
#include <limits.h>
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>

#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <queue>
#include <unordered_map>
#include <unordered_set>

#define int long long
#define REP(i, n) for (int i = 0, i##_len = (n); i < i##_len; ++i)
#define REPS(i, n) for (int i = 1, i##_len = (n); i <= i##_len; ++i)
#define FOR(i, a, b) for (int i = (a), i##_len = (b); i <= i##_len; ++i)
#define REV(i, a, b) for (int i = (a); i >= (b); --i)
#define CLR(a, b) memset((a), (b), sizeof(a))
#define DUMP(x) cout << #x << " = " << (x) << endl;
#define INF 1001001001001001001ll
#define fcout cout << fixed << setprecision(12)

using namespace std;

typedef pair<int, int> P;

struct BIT {
    int n;
    vector<int> bit; // 1-indexd

    BIT(int sz) {
        bit.resize(sz + 1);
        n = sz;
    }

    int sum(int i) {
        int s = 0;
        while (i > 0) {
            s += bit[i];
            i -= i & -i;
        }
        return s;
    }

    void add(int i, int x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
};

class ECountTheRectangles {
public:
    static constexpr int kStressIterations = 0;

    static void generateTest(std::ostream& test) {
    }

    int geta = 5001;
    int maxY = 10009;

    void solve(std::istream& cin, std::ostream& cout) {
        int n;
        cin >> n;
        vector<vector<P>> h(maxY), v(maxY);
        REP(i, n) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            x1 += geta;
            y1 += geta;
            x2 += geta;
            y2 += geta;
            if (y1 == y2) {
                if (x1 > x2) swap(x1, x2);
                h[y1].emplace_back(x1, x2);
            } else {
                if (y1 > y2) swap(y1, y2);
                v[x1].emplace_back(y1, y2);
            }
        }

        BIT bit(maxY);
        int res = 0;
        REP(y, maxY) {
            for (auto kv : h[y]) {

                int l, r;
                tie(l, r) = kv;

                map<int, vector<int>> cnt;
                FOR(x, l, r) {
                    for (auto kv2 : v[x]) {
                        int b, u;
                        tie(b, u) = kv2;
                        if (b <= y && y < u) {
                            cnt[u].push_back(x);
                            bit.add(x, 1);
                        }
                    }
                }

                FOR(y2, y + 1, maxY - 1) {
                    for (auto kv2 : h[y2]) {
                        int num = bit.sum(kv2.second) - bit.sum(kv2.first - 1);
                        if (num == 0) continue;
                        res += num * (num - 1) / 2;
                    }
                    for (int x : cnt[y2]) {
                        bit.add(x, -1);
                    }
                }
            }
        }
        cout << res << endl;
    }
};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    std::istream& in(std::cin);
    std::ostream& out(std::cout);

    ECountTheRectangles solver;
    solver.solve(in, out);
    return 0;
}


/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author tatsumack
 */

#include <iostream>
#include <fstream>

#include <iostream>
#include <limits.h>
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>

#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <queue>
#include <unordered_map>
#include <unordered_set>

#define int long long
#define REP(i, n) for (int i = 0, i##_len = (n); i < i##_len; ++i)
#define REPS(i, n) for (int i = 1, i##_len = (n); i <= i##_len; ++i)
#define FOR(i, a, b) for (int i = (a), i##_len = (b); i <= i##_len; ++i)
#define REV(i, a, b) for (int i = (a); i >= (b); --i)
#define CLR(a, b) memset((a), (b), sizeof(a))
#define DUMP(x) cout << #x << " = " << (x) << endl;
#define INF 1001001001001001001ll
#define fcout cout << fixed << setprecision(12)

using namespace std;

typedef pair<int, int> P;

struct BIT {
    int n;
    vector<int> bit; // 1-indexd

    BIT(int sz) {
        bit.resize(sz + 1);
        n = sz;
    }

    int sum(int i) {
        int s = 0;
        while (i > 0) {
            s += bit[i];
            i -= i & -i;
        }
        return s;
    }

    void add(int i, int x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
};

class ECountTheRectangles {
public:
    static constexpr int kStressIterations = 0;

    static void generateTest(std::ostream& test) {
    }

    int geta = 5001;
    int maxY = 10009;

    void solve(std::istream& cin, std::ostream& cout) {
        int n;
        cin >> n;
        vector<vector<P>> h(maxY), v(maxY);
        REP(i, n) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            x1 += geta;
            y1 += geta;
            x2 += geta;
            y2 += geta;
            if (y1 == y2) {
                if (x1 > x2) swap(x1, x2);
                h[y1].emplace_back(x1, x2);
            } else {
                if (y1 > y2) swap(y1, y2);
                v[x1].emplace_back(y1, y2);
            }
        }

        BIT bit(maxY);
        unordered_map<int, vector<int>> cnt;
        int res = 0;
        REP(y, maxY) {
            for (auto kv : h[y]) {

                int l, r;
                tie(l, r) = kv;

                FOR(x, l, r) {
                    for (auto kv2 : v[x]) {
                        int b, u;
                        tie(b, u) = kv2;
                        if (b <= y && y < u) {
                            cnt[u].push_back(x);
                            bit.add(x, 1);
                        }
                    }
                }

                FOR(y2, y + 1, maxY - 1) {
                    for (auto kv2 : h[y2]) {
                        int num = bit.sum(kv2.second) - bit.sum(kv2.first - 1);
                        if (num == 0) continue;
                        res += num * (num - 1) / 2;
                    }
                    for (int x : cnt[y2]) {
                        bit.add(x, -1);
                    }
                    cnt[y2].clear();
                }
            }
        }
        cout << res << endl;
    }
};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    std::istream& in(std::cin);
    std::ostream& out(std::cout);

    ECountTheRectangles solver;
    solver.solve(in, out);
    return 0;
}


/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author tatsumack
 */

#include <iostream>
#include <fstream>

#include <iostream>
#include <limits.h>
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>

#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <queue>
#include <unordered_map>
#include <unordered_set>

#define int long long
#define REP(i, n) for (int i = 0, i##_len = (n); i < i##_len; ++i)
#define REPS(i, n) for (int i = 1, i##_len = (n); i <= i##_len; ++i)
#define FOR(i, a, b) for (int i = (a), i##_len = (b); i <= i##_len; ++i)
#define REV(i, a, b) for (int i = (a); i >= (b); --i)
#define CLR(a, b) memset((a), (b), sizeof(a))
#define DUMP(x) cout << #x << " = " << (x) << endl;
#define INF 1001001001001001001ll
#define fcout cout << fixed << setprecision(12)

using namespace std;

typedef pair<int, int> P;

// Range Sum Query
struct SegmentTree {
private:
    int n;
    vector<int> node;
public:
    SegmentTree(vector<int> v) {
        int sz = (int) v.size();
        n = 1;
        while (n < sz) n *= 2;
        node.resize(2 * n - 1, 0);

        for (int i = 0; i < sz; i++) node[i + n - 1] = v[i];
        for (int i = n - 2; i >= 0; i--) node[i] = node[i * 2 + 1] + node[i * 2 + 2];
    }

    void add(int k, int val) {
        k += (n - 1);
        node[k] += val;

        while (k > 0) {
            k = (k - 1) / 2;
            node[k] = node[2 * k + 1] + node[2 * k + 2];
        }
    }

    int getsum(int a, int b, int k = 0, int l = 0, int r = -1) {
        if (r < 0) r = n;
        if (b <= l || r <= a) return 0;
        if (a <= l && r <= b) return node[k];

        int vl = getsum(a, b, 2 * k + 1, l, (l + r) / 2);
        int vr = getsum(a, b, 2 * k + 2, (l + r) / 2, r);
        return vl + vr;
    }
};

class ECountTheRectangles {
public:
    static constexpr int kStressIterations = 0;
    static void generateTest(std::ostream& test) {
    }

    int geta = 5000;
    int maxY = 10009;

    void solve(std::istream& cin, std::ostream& cout) {
        int n;
        cin >> n;
        vector<vector<P>> h(maxY), v(maxY);
        REP(i, n) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            x1 += geta;
            y1 += geta;
            x2 += geta;
            y2 += geta;
            if (y1 == y2) {
                if (x1 > x2) swap(x1, x2);
                h[y1].emplace_back(x1, x2);
            }
            else {
                if (y1 > y2) swap(y1, y2);
                v[x1].emplace_back(y1, y2);
            }
        }

        int res = 0;
        REP(y, maxY) {
            for (auto kv : h[y]) {
                SegmentTree seg(vector<int>(maxY, 0));

                int l, r;
                tie(l, r) = kv;

                map<int, vector<int>> cnt;
                FOR(x, l, r) {
                    for (auto kv2 : v[x]) {
                        int b, u;
                        tie(b, u) = kv2;
                        if (b <= y && y <= u) {
                            cnt[u].push_back(x);
                            seg.add(x, 1);
                        }
                    }
                }

                FOR(y2, y + 1, maxY) {
                    for (auto kv2 : h[y2]) {
                        int num = seg.getsum(kv2.first, kv2.second+1);
                        if (num == 0) continue;
                        res += num * (num - 1) / 2;
                    }
                    for (int x : cnt[y2]) {
                        seg.add(x, -1);
                    }
                }
            }
        }
        cout << res << endl;
    }
};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    std::istream& in(std::cin);
    std::ostream& out(std::cout);

    ECountTheRectangles solver;
    solver.solve(in, out);
    return 0;
}


/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author tatsumack
 */

#include <iostream>
#include <fstream>

#include <iostream>
#include <limits.h>
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>

#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <queue>
#include <unordered_map>
#include <unordered_set>

#define int long long
#define REP(i, n) for (int i = 0, i##_len = (n); i < i##_len; ++i)
#define REPS(i, n) for (int i = 1, i##_len = (n); i <= i##_len; ++i)
#define FOR(i, a, b) for (int i = (a), i##_len = (b); i <= i##_len; ++i)
#define REV(i, a, b) for (int i = (a); i >= (b); --i)
#define CLR(a, b) memset((a), (b), sizeof(a))
#define DUMP(x) cout << #x << " = " << (x) << endl;
#define INF 1001001001001001001ll
#define fcout cout << fixed << setprecision(12)

using namespace std;

typedef pair<int, int> P;

// Range Sum Query
struct SegmentTree {
private:
    int n;
    vector<int> node;
public:
    SegmentTree(vector<int> v) {
        int sz = (int) v.size();
        n = 1;
        while (n < sz) n *= 2;
        node.resize(2 * n - 1, 0);

        for (int i = 0; i < sz; i++) node[i + n - 1] = v[i];
        for (int i = n - 2; i >= 0; i--) node[i] = node[i * 2 + 1] + node[i * 2 + 2];
    }

    void add(int k, int val) {
        k += (n - 1);
        node[k] += val;

        while (k > 0) {
            k = (k - 1) / 2;
            node[k] = node[2 * k + 1] + node[2 * k + 2];
        }
    }

    int getsum(int a, int b, int k = 0, int l = 0, int r = -1) {
        if (r < 0) r = n;
        if (b <= l || r <= a) return 0;
        if (a <= l && r <= b) return node[k];

        int vl = getsum(a, b, 2 * k + 1, l, (l + r) / 2);
        int vr = getsum(a, b, 2 * k + 2, (l + r) / 2, r);
        return vl + vr;
    }
};

class ECountTheRectangles {
public:
    static constexpr int kStressIterations = 0;
    static void generateTest(std::ostream& test) {
    }

    int geta = 5000;
    int maxY = 10009;

    void solve(std::istream& cin, std::ostream& cout) {
        int n;
        cin >> n;
        vector<vector<P>> h(maxY), v(maxY);
        REP(i, n) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            x1 += geta;
            y1 += geta;
            x2 += geta;
            y2 += geta;
            if (y1 == y2) {
                if (x1 > x2) swap(x1, x2);
                h[y1].emplace_back(x1, x2);
            }
            else {
                if (y1 > y2) swap(y1, y2);
                v[x1].emplace_back(y1, y2);
            }
        }

        SegmentTree seg(vector<int>(maxY, 0));
        int res = 0;
        REP(y, maxY) {
            for (auto kv : h[y]) {

                int l, r;
                tie(l, r) = kv;

                map<int, vector<int>> cnt;
                FOR(x, l, r) {
                    for (auto kv2 : v[x]) {
                        int b, u;
                        tie(b, u) = kv2;
                        if (b <= y && y < u) {
                            cnt[u].push_back(x);
                            seg.add(x, 1);
                        }
                    }
                }

                FOR(y2, y + 1, maxY - 1) {
                    for (auto kv2 : h[y2]) {
                        int num = seg.getsum(kv2.first, kv2.second+1);
                        if (num == 0) continue;
                        res += num * (num - 1) / 2;
                    }
                    for (int x : cnt[y2]) {
                        seg.add(x, -1);
                    }
                }
            }
        }
        cout << res << endl;
    }
};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    std::istream& in(std::cin);
    std::ostream& out(std::cout);

    ECountTheRectangles solver;
    solver.solve(in, out);
    return 0;
}


/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author tatsumack
 */

#include <iostream>
#include <fstream>

#include <iostream>
#include <limits.h>
#include <algorithm>
#include <bitset>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>

#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <queue>
#include <unordered_map>
#include <unordered_set>

#define int long long
#define REP(i, n) for (int i = 0, i##_len = (n); i < i##_len; ++i)
#define REPS(i, n) for (int i = 1, i##_len = (n); i <= i##_len; ++i)
#define FOR(i, a, b) for (int i = (a), i##_len = (b); i <= i##_len; ++i)
#define REV(i, a, b) for (int i = (a); i >= (b); --i)
#define CLR(a, b) memset((a), (b), sizeof(a))
#define DUMP(x) cout << #x << " = " << (x) << endl;
#define INF 1001001001001001001ll
#define fcout cout << fixed << setprecision(12)

using namespace std;

typedef pair<int, int> P;

// Range Sum Query
struct SegmentTree {
private:
    int n;
    vector<int> node;
public:
    SegmentTree(vector<int> v) {
        int sz = (int) v.size();
        n = 1;
        while (n < sz) n *= 2;
        node.resize(2 * n - 1, 0);

        for (int i = 0; i < sz; i++) node[i + n - 1] = v[i];
        for (int i = n - 2; i >= 0; i--) node[i] = node[i * 2 + 1] + node[i * 2 + 2];
    }

    void add(int k, int val) {
        k += (n - 1);
        node[k] += val;

        while (k > 0) {
            k = (k - 1) / 2;
            node[k] = node[2 * k + 1] + node[2 * k + 2];
        }
    }

    int getsum(int a, int b, int k = 0, int l = 0, int r = -1) {
        if (r < 0) r = n;
        if (b <= l || r <= a) return 0;
        if (a <= l && r <= b) return node[k];

        int vl = getsum(a, b, 2 * k + 1, l, (l + r) / 2);
        int vr = getsum(a, b, 2 * k + 2, (l + r) / 2, r);
        return vl + vr;
    }
};

class ECountTheRectangles {
public:
    static constexpr int kStressIterations = 0;
    static void generateTest(std::ostream& test) {
    }

    int geta = 5000;
    int maxY = 10009;

    void solve(std::istream& cin, std::ostream& cout) {
        int n;
        cin >> n;
        vector<vector<P>> h(maxY), v(maxY);
        REP(i, n) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            x1 += geta;
            y1 += geta;
            x2 += geta;
            y2 += geta;
            if (y1 == y2) {
                if (x1 > x2) swap(x1, x2);
                h[y1].emplace_back(x1, x2);
            }
            else {
                if (y1 > y2) swap(y1, y2);
                v[x1].emplace_back(y1, y2);
            }
        }

        int res = 0;
        REP(y, maxY) {
            for (auto kv : h[y]) {
                SegmentTree seg(vector<int>(maxY, 0));

                int l, r;
                tie(l, r) = kv;

                map<int, vector<int>> cnt;
                FOR(x, l, r) {
                    for (auto kv2 : v[x]) {
                        int b, u;
                        tie(b, u) = kv2;
                        if (b <= y && y <= u) {
                            cnt[u].push_back(x);
                            seg.add(x, 1);
                        }
                    }
                }

                FOR(y2, y + 1, maxY - 1) {
                    for (auto kv2 : h[y2]) {
                        int num = seg.getsum(kv2.first, kv2.second+1);
                        if (num == 0) continue;
                        res += num * (num - 1) / 2;
                    }
                    for (int x : cnt[y2]) {
                        seg.add(x, -1);
                    }
                }
            }
        }
        cout << res << endl;
    }
};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    std::istream& in(std::cin);
    std::ostream& out(std::cout);

    ECountTheRectangles solver;
    solver.solve(in, out);
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a) memset(a,0,sizeof a)
const int N=1e5+5;
const int INF=1e9+5;
ll read(ll &a){scanf("%lld",&a);return a;}
int read(int &a){scanf("%d",&a);return a;}
int read(){int a;scanf("%d",&a);return a;}
int read(int &a,int &b){scanf("%d %d",&a,&b);return a;}
int n;
struct edge
{
    int a;
    int b1,b2;
    edge(int a=0,int b1=0,int b2=0):a(a),b1(b1),b2(b2){}
    bool operator <(const edge b)const
    {
        if(a!=b.a)
            return a<b.a;

        if(b1!=b.b1)
            return b1<b.b1;

        if(b2!=b.b2)
            return b2<b.b2;
    }
};
vector<edge>r;
vector<edge>c;

int tree[N<<2];
int M;
void modify(int n,ll v)
{
    for(tree[n+=M]+=v,n>>=1;n;n>>=1)
        tree[n]=tree[n*2]+tree[n*2+1];
}
ll query(int l,int r)
{
    ll ans=0;
    for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) ans+=tree[l^1];
        if(r&1)ans+=tree[r^1];
    }
    return ans;
}

int X1,X2,Y1,Y2;
int main()
{

    for(M=1;M<5010;M<<=1);
    cin>>n;

    while(n--)
    {
        cin>>X1>>Y1>>X2>>Y2;

        if(X1>X2)
            swap(X1,X2);
        if(Y1>Y2)
            swap(Y1,Y2);
        if(X1==X2)
            c.push_back(edge(X1,Y1,Y2));
        else
            r.push_back(edge(Y1,X1,X2));
    }
    ll ans=0;
    //cout<<r.size()<<' '<<c.size()<<endl;
    if(r.size()<c.size())
    {
        //cout<<"r"<<endl;
        swap(r,c);
    }

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

    sort(c.begin(),c.end());
    //cout<<c.size()<<endl;
    //cout<<c[0].a<<' '<<c[0].b1<<endl;
    for(int i=0;i<c.size();i++)
    {
        mem(tree);
        priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >pq;

        for(edge &h:r)
        {
            if(h.b1<=c[i].a)
            {
                //cout<<h.b1<<endl;
                modify(h.a,1);
                pq.emplace(h.b2,h.a);
                //cout<<pq.top().first<<endl;
            }
        }
        for(int j=i+1;j<c.size();j++)
        {
            while(!pq.empty()&&pq.top().first<c[j].a)
            {
                modify(pq.top().second,-1);
                pq.pop();
            }
            int low=max(c[i].b1,c[j].b1);
            int high=min(c[i].b2,c[j].b2);
            //cout<<low<<' '<<high<<endl;
            if(low<high)
            {
                int cnt=query(low,high);
                //cout<<cnt<<endl;
                ans+=cnt*(cnt-1)/2;
            }
        }
    }
    cout<<ans<<endl;

    return 0;
}
/*
100
0 0 1
0 1 1
1 0 1
*/


#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a) memset(a,0,sizeof a)
const int N=1e5+5;
const int INF=1e9+5;
ll read(ll &a){scanf("%lld",&a);return a;}
int read(int &a){scanf("%d",&a);return a;}
int read(){int a;scanf("%d",&a);return a;}
int read(int &a,int &b){scanf("%d %d",&a,&b);return a;}
int n;
struct edge
{
    int a;
    int b1,b2;
    edge(int a=0,int b1=0,int b2=0):a(a),b1(b1),b2(b2){}
    bool operator <(const edge b)const
    {

            return a<b.a;

    }
};
vector<edge>r;
vector<edge>c;

int tree[N<<2];
int M;
void modify(int n,ll v)
{
    for(tree[n+=M]+=v,n>>=1;n;n>>=1)
        tree[n]=tree[n*2]+tree[n*2+1];
}
ll query(int l,int r)
{
    ll ans=0;
    for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) ans+=tree[l^1];
        if(r&1)ans+=tree[r^1];
    }
    return ans;
}

int X1,X2,Y1,Y2;
int main()
{

    for(M=1;M<5010;M<<=1);
    //cout<<M<<endl;
    cin>>n;

    while(n--)
    {
        cin>>X1>>Y1>>X2>>Y2;

        if(X1>X2)
            swap(X1,X2);
        if(Y1>Y2)
            swap(Y1,Y2);
        if(X1==X2)
            c.push_back(edge(X1,Y1,Y2));
        else
            r.push_back(edge(Y1,X1,X2));
    }
    ll ans=0;
    //cout<<r.size()<<' '<<c.size()<<endl;
    if(r.size()<c.size())
    {
        //cout<<"r"<<endl;
        swap(r,c);
    }

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

    sort(c.begin(),c.end());
    //cout<<c.size()<<endl;
    //cout<<c[0].a<<' '<<c[0].b1<<endl;
    for(int i=0;i<c.size();i++)
    {
        mem(tree);
        priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >pq;

        for(edge &h:r)
        {
            if(h.b1<=c[i].a)
            {
                //cout<<h.b1<<endl;
                modify(h.a,1);
                pq.emplace(h.b2,h.a);
                //cout<<pq.top().first<<endl;
            }
        }
        for(int j=i+1;j<c.size();j++)
        {
            while(!pq.empty()&&pq.top().first<c[j].a)
            {
                modify(pq.top().second,-1);
                pq.pop();
            }
            int low=max(c[i].b1,c[j].b1);
            int high=min(c[i].b2,c[j].b2);
            //cout<<low<<' '<<high<<endl;
            if(low<=high)
            {
                int cnt=query(low,high+1);
                //cout<<cnt<<endl;
                ans+=cnt*(cnt-1)/2;
            }
        }
    }
    cout<<ans<<endl;

    return 0;
}
/*
100
0 0 1
0 1 1
1 0 1
*/


#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a) memset(a,0,sizeof a)
const int N=1e5+5;
const int INF=1e9+5;
ll read(ll &a){scanf("%lld",&a);return a;}
int read(int &a){scanf("%d",&a);return a;}
int read(){int a;scanf("%d",&a);return a;}
int read(int &a,int &b){scanf("%d %d",&a,&b);return a;}
int n;
struct edge
{
    int a;
    int b1,b2;
    edge(int a=0,int b1=0,int b2=0):a(a),b1(b1),b2(b2){}
    bool operator <(const edge b)const
    {
        if(a!=b.a)
            return a<b.a;

        if(b1!=b.b1)
            return b1<b.b1;

        if(b2!=b.b2)
            return b2<b.b2;
    }
};
vector<edge>r;
vector<edge>c;

int tree[N<<2];
int M;
void modify(int n,ll v)
{
    for(tree[n+=M]+=v,n>>=1;n;n>>=1)
        tree[n]=tree[n*2]+tree[n*2+1];
}
ll query(int l,int r)
{
    ll ans=0;
    for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) ans+=tree[l^1];
        if(r&1)ans+=tree[r^1];
    }
    return ans;
}

int X1,X2,Y1,Y2;
int main()
{

    for(M=1;M<5010;M<<=1);
    cin>>n;

    while(n--)
    {
        cin>>X1>>Y1>>X2>>Y2;

        if(X1>X2)
            swap(X1,X2);
        if(Y1>Y2)
            swap(Y1,Y2);
        if(X1==X2)
            c.push_back(edge(X1,Y1,Y2));
        else
            r.push_back(edge(Y1,X1,X2));
    }
    ll ans=0;
    //cout<<r.size()<<' '<<c.size()<<endl;
    if(r.size()<c.size())
    {
        //cout<<"r"<<endl;
        swap(r,c);
    }

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

    sort(c.begin(),c.end());
    //cout<<c.size()<<endl;
    //cout<<c[0].a<<' '<<c[0].b1<<endl;
    for(int i=0;i<c.size();i++)
    {
        mem(tree);
        priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >pq;

        for(edge &h:r)
        {
            if(h.b1<=c[i].a)
            {
                //cout<<h.b1<<endl;
                modify(h.a,1);
                pq.emplace(h.b2,h.a);
                //cout<<pq.top().first<<endl;
            }
        }
        for(int j=i+1;j<c.size();j++)
        {
            while(!pq.empty()&&pq.top().first<c[j].a)
            {
                modify(pq.top().second,-1);
                pq.pop();
            }
            int low=max(c[i].b1,c[j].b1);
            int high=min(c[i].b2,c[j].b2);
            //cout<<low<<' '<<high<<endl;
            if(low<=high)
            {
                int cnt=query(low,high);
                //cout<<cnt<<endl;
                ans+=cnt*(cnt-1)/2;
            }
        }
    }
    cout<<ans<<endl;

    return 0;
}
/*
100
0 0 1
0 1 1
1 0 1
*/