// Arup Guha
// 7/2/2013
// Solution to 2012 South East Regional Division 1 Problem F: A Terribly Grimm Problem
// Note: This finishes in 44 seconds. I have finally implemented Dinic's Algorithm. This
//       sped up my previous version (Edmunds-Karp) from 4 1/2 minutes to 44 seconds on
//       my laptop. Considering that my solution once took 92 minutes, I am happy with this
//       implementation. It's very, very awkward and clunky. Not pretty at all.

import java.util.*;

public class f {

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);

		long low = stdin.nextLong();
		long high = stdin.nextLong();

		// Go through each case.
		while (low != 0) {
			solve(low, high);
			low = stdin.nextLong();
			high = stdin.nextLong();
		}
	}

	public static void solve(long low, long high) {

		int n = (int)(high-low+1);

		// Create list of each number's prime factors, and full list also.
		ArrayList[] factors = new ArrayList[n];
		TreeSet<Long> primes = new TreeSet<Long>();
		for (int i=0; i<n; i++) {
			factors[i] = getFactors(low+i);
			for (int j=0; j<factors[i].size(); j++)
				primes.add((Long)factors[i].get(j));
		}

		long[] primelist = new long[primes.size()];
		for (int i=0; i<primelist.length; i++)
			primelist[i] = primes.pollFirst();

		// Make mapping of node numbers here for flow grpah.
		HashMap<Long,Integer> map = new HashMap<Long,Integer>();
		for (int i=0; i<primelist.length; i++)
			map.put(primelist[i], n+1+i);

		Edge[][] graph = getInitGraph(factors, primelist, map, n);


		// Will store final answer here.
		long[] ans = new long[n];
		HashSet<Long> taken = new HashSet<Long>();

		// Main outer loop.
		for (int i=0; i<n; i++) {

			// Go through each factor in order, as directions state.
			for (int j=0; j<factors[i].size(); j++) {

				// Skip if we've assigned this one already.
				long next = (Long)factors[i].get(j);
				if (taken.contains(next)) continue;

				// Try this factor here.
				ans[i] = next;

				// Zero out the two necessary edges for this match.
				graph[0][i].capacity = 0;
				graph[graph[i+1][j].dest][0].capacity = 0;

				netflowdinic myFlow = new netflowdinic(graph, 0, graph.length-1);
				int flow = myFlow.getMaxFlow();

				// Found one that works, move on!
				if (flow == n-i-1) {
					taken.add(next);
					break;
				}

				// Undo assignment.
				graph[0][i].capacity = 1;
				graph[graph[i+1][j].dest][0].capacity = 1;
				ans[i] = 0;
			}
		}

		// Output result.
		for (int i=0; i<n-1; i++)
			System.out.print(ans[i]+" ");
		System.out.println(ans[n-1]);
	}

	// Creates and edgelist of the initial graph.
	public static Edge[][] getInitGraph(ArrayList[] factors, long[] primelist, HashMap<Long,Integer> map, int n) {

		// Nodes in flow graph: 0 = source, 1-n = composite #s, (n+1)-(numNodes-2) = primes#, numNodes-1 = sink
		int numNodes = n + primelist.length + 2;

		// Store graph here.
		Edge[][] G = new Edge[numNodes][];

		// Edges to composites.
		G[0] = new Edge[n];
		for (int i=1; i<=n; i++)
			G[0][i-1] = new Edge(1, i);

		// Place edges from composites to primes.
		for (int i=1; i<=n; i++) {
			G[i] = new Edge[factors[i-1].size()];
			for (int j=0; j<factors[i-1].size(); j++) {
				long curFactor = (Long)factors[i-1].get(j);
				G[i][j] = new Edge(1, map.get(curFactor));
			}
		}

		// Edges to sink.
		for (int i=n+1; i<numNodes-1; i++) {
			G[i] = new Edge[1];
			G[i][0] = new Edge(1, numNodes-1);
		}

		G[numNodes-1] = new Edge[0];
		return G;
	}

	// Returns all the unique prime factors of n.
	public static ArrayList<Long> getFactors(long n) {

		long div = 2;
		ArrayList<Long> list = new ArrayList<Long>();

		while (n >= div*div) {

			boolean divisor = false;
			while (n%div == 0) {
				n = n/div;
				divisor = true;
			}
			if (divisor) list.add(div);
			div++;
		}
		if (n > 1) list.add(n);

		return list;
	}
}

class Edge {

	public int dest;
	public int capacity;
	public int flow;

	public Edge(int cap, int d) {
		capacity = cap;
		flow = 0;
		dest = d;
	}

	public String toString() {
		return "("+dest+" "+capacity+", "+flow+") ";
	}

	public int maxPushForward() {
		return capacity - flow;
	}

	public int maxPushBackward() {
		return flow;
	}

	public boolean pushForward(int moreflow) {

		// We can't push through this much flow.
		if (flow+moreflow > capacity)
			return false;

		// Push through.
		flow += moreflow;
		return true;
	}

	public boolean pushBack(int lessflow) {

		// Not enough to push back on.
		if (flow < lessflow)
			return false;

		flow -= lessflow;
		return true;
	}
}

class direction {

	public int prev;
	public boolean forward;

	public direction(int node, boolean dir) {
		prev = node;
		forward = dir;
	}

	public String toString() {
		if (forward)
			return "" + prev + "->";
		else
			return "" + prev + "<-";
	}
}

class pair {

	public int vertex;
	public int distance;

	public pair(int v, int d) {
		vertex = v;
		distance = d;
	}
}

class netflowdinic {

	private Edge[][] adjMat;
	private int source;
	private int dest;
	private HashMap[] lookup;
	private LinkedList[] backEdgeLookup;
	private int[] distance;

	public netflowdinic(Edge[][] matrix, int start, int end) {

		// Set up easy stuff.
		adjMat = matrix;
		source = start;
		dest = end;
		lookup = new HashMap[matrix.length];
		distance = new int[matrix.length];

		// Allocate empty LLs.
		backEdgeLookup = new LinkedList[matrix.length];
		for (int i=0; i<matrix.length; i++)
			backEdgeLookup[i] = new LinkedList<Integer>();

		// Fill these in.
		for (int i=0; i<adjMat.length; i++) {

			lookup[i] = new HashMap<Integer,Integer>();
			for (int j=0; j<adjMat[i].length; j++) {
				backEdgeLookup[adjMat[i][j].dest].offer(i);
				lookup[i].put(adjMat[i][j].dest,j);
				adjMat[i][j].flow = 0;
			}
		}
	}

	// Wrapper function for dfs that finds an augmenting path of a specific length.
	public ArrayList<direction> findAugmentingPath() {
		boolean[] used = new boolean[adjMat.length];
		ArrayList<direction> path = new ArrayList<direction>();
		path.add(new direction(source, true));
		path = findAugmentingPathRec(source, used, path);
		if (path == null) return null;
		return fix(path);
	}

	// Recursive function that builds the augmenting path from next to dest.
	public ArrayList<direction> findAugmentingPathRec(int next, boolean[] used, ArrayList<direction> path) {

		// We're done.
		if (next == dest) return path;

		// Mark this node.
		used[next] = true;
		int curDist = distance[next];

		// Find all neighbors and add into the queue. These are forward edges.
		for (int i=0; i<adjMat[next].length; i++) {

			int item = adjMat[next][i].dest;
			if (!used[item] && adjMat[next][i].maxPushForward() > 0 && distance[item] == curDist+1) {
				path.add(new direction(item, true));
				ArrayList<direction> temp = findAugmentingPathRec(item, used, path);
				if (temp != null)
					return temp;
				else
					path.remove(path.size()-1);
			}
		}

		// Now look for back edges.
		for (int i=0; i<backEdgeLookup[next].size(); i++) {

			int item = (Integer)backEdgeLookup[next].pollFirst();
			if (!used[item] && lookup[item].containsKey(next) && adjMat[item][(Integer)(lookup[item].get(next))].maxPushBackward() > 0 && distance[item] == curDist+1) {
				path.add(new direction(item, false));
				ArrayList<direction> temp = findAugmentingPathRec(item, used, path);
				if (temp != null)
					return temp;
				else
					path.remove(path.size()-1);
			}
			backEdgeLookup[next].offer(item);
		}

		return null;
	}

	// This is to fix the faulty output of the recursive functions. The directions are "off by one".
	public static ArrayList<direction> fix(ArrayList<direction> list) {
		for (int i=0; i<list.size()-1; i++)
			list.get(i).forward = list.get(i+1).forward;
		return list;
	}

	// This is the BFS that labels all of the distances from the source.
	public boolean labelDistances() {

		Arrays.fill(distance, -1);

		// Set up BFS.
		boolean[] inQueue = new boolean[adjMat.length];
		for (int i=0; i<inQueue.length; i++)
			inQueue[i] = false;

		LinkedList<pair> bfs_queue = new LinkedList<pair>();
		bfs_queue.offer(new pair(source, 0));
		inQueue[source] = true;

		// Our BFS will go until we clear out the queue.
		while (bfs_queue.size() > 0) {

			// Add all the new neighbors of the current node.
			pair nextItem = bfs_queue.poll();
			int next = nextItem.vertex;

			// Store distance from source.
			distance[next] = nextItem.distance;

			// Find all neighbors and add into the queue. These are forward edges.
			for (int i=0; i<adjMat[next].length; i++) {

				int item = adjMat[next][i].dest;
				if (!inQueue[item] && adjMat[next][i].maxPushForward() > 0) {
					bfs_queue.offer(new pair(item, nextItem.distance+1) );
					inQueue[item] = true;
				}
			}

			// Now look for back edges.
			for (int i=0; i<backEdgeLookup[next].size(); i++) {

				int item = (Integer)backEdgeLookup[next].pollFirst();
				if (!inQueue[item] && lookup[item].containsKey(next) && adjMat[item][(Integer)(lookup[item].get(next))].maxPushBackward() > 0) {
					bfs_queue.offer(new pair(item, nextItem.distance+1));
					inQueue[item] = true;
				}
				backEdgeLookup[next].offer(item);
			}
		}

		// No augmenting path found.
		return inQueue[dest];
	}


	// Run the Max Flow Algorithm here.
	public int getMaxFlow() {

		int flow = 0;

		// Outer level - do BFS to label nodes.
		while (labelDistances()) {

			ArrayList<direction> nextpath = findAugmentingPath();

			// Run adjusted DFS here.
			while (nextpath != null) {



				// Check what the best flow through this path is.
				int this_flow = Integer.MAX_VALUE;
				for (int i=0; i<nextpath.size()-1; i++) {

					if (nextpath.get(i).forward) {
						this_flow = Math.min(this_flow, adjMat[nextpath.get(i).prev][(Integer)lookup[nextpath.get(i).prev].get(nextpath.get(i+1).prev)].maxPushForward());
					}
					else {
						this_flow = Math.min(this_flow, adjMat[nextpath.get(i+1).prev][(Integer)lookup[nextpath.get(i+1).prev].get(nextpath.get(i).prev)].maxPushBackward());
					}
				}

				// Now, put this flow through.
				for (int i=0; i<nextpath.size()-1; i++) {

					if (nextpath.get(i).forward) {
						adjMat[nextpath.get(i).prev][(Integer)lookup[nextpath.get(i).prev].get(nextpath.get(i+1).prev)].pushForward(this_flow);
					}
					else {
						adjMat[nextpath.get(i+1).prev][(Integer)lookup[nextpath.get(i+1).prev].get(nextpath.get(i).prev)].pushBack(this_flow);
					}
				}

				// Add this flow in and then get the next path.
				flow += this_flow;
				nextpath = findAugmentingPath();
			}
		}

		return flow;
	}
}