// Arup Guha
// 11/5/2013
// Solution to 2013 South East Regional Problem F: Star Simulations

import java.util.*;

public class stars {

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);
		int n = stdin.nextInt();
		int k = stdin.nextInt();

		while (n != 0) {

			pt[] list = new pt[n];
			for (int i=0; i<n; i++) {
				double x = stdin.nextDouble();
				double y = stdin.nextDouble();
				double z = stdin.nextDouble();
				list[i] = new pt(x,y,z);
			}

			randomize(list);

			// Set up first node.
			node root = new node(list[0]);

			// Insert the rest of the items.
			for (int i=1; i<n; i++)
				root.insert(list[i]);

			// Solve and output.
			System.out.println(solve(root, list, k));

			// Get next case.
			n = stdin.nextInt();
			k = stdin.nextInt();
		}
	}

	public static int solve(node root, pt[] list, int k) {

		// Sum over all nodes.
		int cnt = 0;
		for (int i=0; i<list.length; i++)
			cnt += root.numLessD(list[i], k, 0);

		// Divide by 2 because we counted each pair twice and subtract out each copy of a point
		// counted with itself.
		return (cnt-list.length)/2;
	}

	// Randomizes the order of list by swapping 5n pairs of randomly chosen items in list.
	public static void randomize(pt[] list) {

		Random r = new Random();
		int n = list.length;

		for (int i=0; i<5*n; i++) {
			int a = r.nextInt(n);
			int b = r.nextInt(n);
			swap(list, a, b);
		}
	}

	public static void swap(pt[] list, int i, int j) {
		pt tmp = list[i];
		list[i] = list[j];
		list[j] = tmp;
	}
}

class pt {

	public double x;
	public double y;
	public double z;

	public pt(double myx, double myy, double myz) {
		x = myx;
		y = myy;
		z = myz;
	}

	public double dist(pt other) {
		return Math.sqrt(Math.pow(x-other.x,2) + Math.pow(y-other.y,2) + Math.pow(z-other.z,2));
	}

	public String toString() {
		return "("+x+","+y+")";
	}
}

class node {

	public pt p;
	public node left;
	public node right;

	public node(pt myp) {
		p = myp;
		left = null;
		right = null;
	}

	public void insert(pt newPt) {
		insertRec(newPt, 0);
	}

	public void insertRec(pt newPt, int level) {

		// Determine which direction to go.
		boolean goLeft;
		if (level%3 == 0)      goLeft = (newPt.x <= p.x);
		else if (level%3 == 1) goLeft = (newPt.y <= p.y);
		else				   goLeft = (newPt.z <= p.z);

		// Go left - see if we need to recurse.
		if (goLeft) {
			if (left == null) left = new node(newPt);
			else left.insertRec(newPt, level+1);
		}

		// Same on right.
		else {
			if (right == null) right = new node(newPt);
			else right.insertRec(newPt, level+1);
		}
	}

	public int numLessD(pt other, int k, int level) {

		int cnt = 0;

		// Count this point only if it's close enough.
		double d = p.dist(other);
		if (d < k-1e-10) cnt++;

		// Only try going left if it exists.
		if (left != null) {
			if ((level%3 == 0 && other.x < p.x+k) ||	(level%3 == 1 && other.y < p.y+k) || (level%3 == 2 && other.z < p.z+k))
				cnt += left.numLessD(other, k, level+1);
		}

		// Same with right.
		if (right != null) {
			if ((level%3 == 0 && other.x > p.x-k) ||	(level%3 == 1 && other.y > p.y-k) || (level%3 == 2 && other.z > p.z-k))
				cnt += right.numLessD(other, k, level+1);
		}

		// Final answer.
		return cnt;
	}
}