diff --git a/crm/pengine/clone.c b/crm/pengine/clone.c
index 6f76003ad2..c92697b474 100644
--- a/crm/pengine/clone.c
+++ b/crm/pengine/clone.c
@@ -1,1304 +1,1239 @@
 /* $Id: clone.c,v 1.6 2006/07/18 06:19:33 andrew Exp $ */
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <portability.h>
 
 #include <crm/msg_xml.h>
 #include <allocate.h>
 #include <utils.h>
 #include <lib/crm/pengine/utils.h>
 
 void clone_create_notifications(
 	resource_t *rsc, action_t *action, action_t *action_complete,
 	pe_working_set_t *data_set);
 
 typedef struct clone_variant_data_s
 {
 		resource_t *self;
 
 		int clone_max;
 		int clone_node_max;
 
 		int active_clones;
 		int max_nodes;
 		
 		gboolean interleave;
 		gboolean ordered;
 
 		crm_data_t *xml_obj_child;
 		
 		gboolean notify_confirm;
 		
 		GListPtr child_list; /* resource_t* */
 		
 } clone_variant_data_t;
 
 void child_stopping_constraints(
 	clone_variant_data_t *clone_data, enum pe_ordering type,
 	resource_t *child, resource_t *last, pe_working_set_t *data_set);
 
 void child_starting_constraints(
 	clone_variant_data_t *clone_data, enum pe_ordering type,
 	resource_t *child, resource_t *last, pe_working_set_t *data_set);
 
 
 #define get_clone_variant_data(data, rsc)				\
 	CRM_ASSERT(rsc->variant == pe_clone || rsc->variant == pe_master); \
 	data = (clone_variant_data_t *)rsc->variant_opaque;
 
 
 
 void clone_set_cmds(resource_t *rsc)
 {
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 	clone_data->self->cmds = &resource_class_alloc_functions[clone_data->self->variant];
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 		child_rsc->cmds = &resource_class_alloc_functions[child_rsc->variant];
 		child_rsc->cmds->set_cmds(child_rsc);
 		);
 }
 
 int clone_num_allowed_nodes(resource_t *rsc)
 {
 	int num_nodes = 0;
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	/* what *should* we return here? */
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 		int tmp_num_nodes = child_rsc->cmds->num_allowed_nodes(child_rsc);
 		if(tmp_num_nodes > num_nodes) {
 			num_nodes = tmp_num_nodes;
 		}
 		);
 
 	return num_nodes;
 }
 
-#if 0
 static gint sort_rsc_provisional(gconstpointer a, gconstpointer b)
 {
 	const resource_t *resource1 = (const resource_t*)a;
 	const resource_t *resource2 = (const resource_t*)b;
 
 	CRM_ASSERT(resource1 != NULL);
 	CRM_ASSERT(resource2 != NULL);
 
 	if(resource1->provisional == resource2->provisional) {
 		return 0;
 
 	} else if(resource1->provisional) {
 		return 1;
 
 	} else if(resource2->provisional) {
 		return -1;
 	}
 	CRM_CHECK(FALSE, return 0);
 	return 0;
 }
 
-static GListPtr
-next_color(GListPtr head, GListPtr iter, int max)
+static node_t *
+next_node(resource_t *rsc, int max)
 {
-	color_t *color = NULL;
-	GListPtr local_iter = iter;
-	crm_debug_4("Checking iter: %p", iter);
-	if(local_iter != NULL) {
-		local_iter = local_iter->next;
-	}	
-	for(; local_iter != NULL; local_iter = local_iter->next) {
-		color = local_iter->data;
-		crm_debug_5("Color %d: %d",
-			  color->details->id, color->details->num_resources);
-		if(color->details->num_resources < max) {
-			return local_iter;
-		}
-	}
-	
-	local_iter = head;
-	crm_debug_4("Now checking head: %p", head);
-	for(; local_iter != NULL; local_iter = local_iter->next) {
-		color = local_iter->data;
-		crm_debug_5("Color %d: %d",
-			  color->details->id, color->details->num_resources);
-		if(color->details->num_resources < max) {
-			return local_iter;
-		}
-	}	
-
-	crm_debug_3("Nothing available: %p", head);
 	return NULL;
 }
-#endif		
 
 node_t *
 clone_color(resource_t *rsc, pe_working_set_t *data_set)
 {
-#if 0
-	GListPtr color_ptr = NULL;
-	GListPtr child_colors = NULL;
 	int local_node_max = 0;
-	int reverse_pointer = 0;
+/* 	int reverse_pointer = 0; */
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	if(clone_data->self->provisional == FALSE) {
 		return NULL;
 	}
 	local_node_max = clone_data->clone_node_max; 
 	clone_data->max_nodes = rsc->cmds->num_allowed_nodes(rsc);
 	
 	/* give already allocated resources every chance to run on the node
 	 *   specified.  other resources can be moved/started where we want
 	 *   as required
 	 */
 	clone_data->child_list = g_list_sort(
  		clone_data->child_list, sort_rsc_provisional);
 
 	crm_debug_2("Coloring children of: %s", rsc->id);
 	
 	if(rsc->stickiness <= 0) {
 		while(local_node_max > 1
 		      && clone_data->max_nodes * (local_node_max -1)
 		      >= clone_data->clone_max) {			
 			local_node_max--;
 			crm_debug("Dropped the effective value of"
 				  " clone_node_max to: %d",
 				  local_node_max);
 		}
 	}
 
 	clone_data->self->allowed_nodes = g_list_sort(
 		clone_data->self->allowed_nodes, sort_node_weight);
-	
+
 	slist_iter(a_node, node_t, clone_data->self->allowed_nodes, lpc,
-		   color_t *new_color = NULL;
+		   
 		   if(can_run_resources(a_node) == FALSE) {
 			   crm_debug_2("Node cant run resources: %s",
 				       a_node->details->uname);
 			   continue;
 		   }
-		   crm_debug_3("Processing node %s for: %s",
-			       a_node->details->uname, rsc->id);
-
-		   new_color = create_color(data_set, NULL, NULL);
-		   new_color->local_weight = a_node->weight;
-		   new_color->details->candidate_nodes = g_list_append(
-			   NULL, node_copy(a_node));
-		   child_colors = g_list_append(child_colors, new_color);
-		   crm_debug_3("Created color %d for node %s (score = %d): %s",
-			       new_color->id, a_node->details->uname, a_node->weight, rsc->id);
+		   crm_debug_3("Processing node %s (score=%d) for: %s",
+			       a_node->details->uname, a_node->weight, rsc->id);
 
 		   slist_iter(child, resource_t, clone_data->child_list, lpc2,
 			      node_t *current = NULL;
-			      if(child->provisional == FALSE) {
-				      CRM_CHECK(child->color != NULL, continue);
-				      current = child->color->details->chosen_node;
-
-			      } else if(child->running_on != NULL) {
+			      if(child->running_on != NULL) {
 				      current = child->running_on->data;
 			      }
 			      
 			      if(current == NULL) {
 				      crm_debug_2("Not active: %s", child->id);
 				      continue;
 
 			      } else if(current->details->online == FALSE
 					|| current->details->unclean
 					|| current->details->shutdown) {
 				      crm_debug_2("Unavailable node: %s", child->id);
 				      continue;
 
 			      } else if(current->details != a_node->details) {
 				      crm_debug_2("Wrong node: %s", child->id);
 				      continue;
 
-			      } else if(child->provisional == FALSE) {
-				      /* make sure it shows up */
-				      native_assign_color(child, new_color);
-				      crm_debug("Previously colored: %s",
-						child->id);
-				      
-				      continue;
-				      
 			      } else if(g_list_length(child->running_on) != 1) {
 				      crm_debug("active != 1: %s", child->id);
 				      
 				      continue;
 
-			      } else if(new_color->details->num_resources
-					>= local_node_max) {
+			      } else if(a_node->count >= local_node_max) {
 				      crm_warn("Node %s too full for: %s",
 					       a_node->details->uname,
 					       child->id);
 				      continue;
 			      }
 
 			      a_node->weight = merge_weights(a_node->weight, child->stickiness);
-			      new_color->local_weight = a_node->weight;
-
-			      crm_debug_2("Assigning color: %s", child->id);
-			      native_assign_color(child, new_color);
+			      native_assign_node(rsc, NULL, a_node);
 			   );
-		   
-		   native_assign_color(rsc, new_color);
+		   native_assign_node(clone_data->self, NULL, a_node);
 		);
 
 	while(local_node_max > 1
 	      && clone_data->max_nodes * (local_node_max -1)
 	      >= clone_data->clone_max) {
 		local_node_max--;
 		crm_debug("Dropped the effective value of clone_node_max to: %d",
 			  local_node_max);
 	}
 	
-
-	child_colors = g_list_sort(child_colors, sort_color_weight);
-	
 	/* allocate the rest */
 	slist_iter(child, resource_t, clone_data->child_list, lpc2,
+		   node_t *node = NULL;
 		   if(child->provisional == FALSE) {
 			   crm_debug_2("Skipping allocated resource: %s", child->id);
 			   continue;
 		   }
 		   crm_debug_2("Processing unalloc'd resource: %s", child->id);
-		   color_ptr = next_color(
-			   child_colors, color_ptr, local_node_max);
-		   if(child->variant == pe_native) {
-			   native_assign_color(child, color_ptr?color_ptr->data:data_set->no_color);
-		   } else if(child->variant == pe_group) {
-			   group_assign_color(child, color_ptr?color_ptr->data:data_set->no_color);
-		   } else {
-			   crm_err("Bad variant: %d", child->variant);
-		   }
+		   node = next_node(rsc, local_node_max);
+		   native_assign_node(child, NULL, node);
 		);
 
 	clone_data->self->provisional = FALSE;
 	if(rsc->stickiness >= INFINITY) {
 		return NULL;
 	}
-	
+
+#if 0
 	reverse_pointer = g_list_length(child_colors) - 1;
 	slist_iter(color, color_t, child_colors, lpc,
 		   color_t *replace_color = NULL;
 		   resource_t *replace_rsc = NULL;
 		   
 		   CRM_CHECK(color != NULL, continue);
 		   if(color->details->num_resources != 0) {
 			   crm_debug_4("color %d has %d resources",
 				       color->id, color->details->num_resources);
 			   break;
 
 		   } else if(lpc >= reverse_pointer) {
 			   crm_debug_3("lpc %d, reverse lpc %d", lpc, reverse_pointer);
 			   break;
 		   }
 
 		   crm_debug_3("Color %d has %d resources, stealing one from...",
 			       color->id, color->details->num_resources);
 		   
 		   do {
 			   crm_debug_3("lpc %d, reverse lpc %d", lpc, reverse_pointer);
 			   if(lpc >= reverse_pointer) {
 				   return NULL;
 			   }
 			   replace_color = g_list_nth_data(child_colors, reverse_pointer);
 			   reverse_pointer--;
 
 			   CRM_CHECK(replace_color != NULL, continue);
 			   CRM_CHECK(replace_color->details->num_resources >= 0, continue);
 			   if(replace_color->details->num_resources == 0) {
 				   continue;
 			   }
 
 			   CRM_CHECK(replace_color->details->allocated_resources != NULL, continue);
 			   replace_rsc = replace_color->details->allocated_resources->data;
 
 			   crm_debug_3("\tColor %d with %d resources (index = %d, rsc = %s)",
 				       replace_color->id, replace_color->details->num_resources,
 				       reverse_pointer+1, replace_rsc?replace_rsc->id:"none");
 
 		   } while(replace_color == NULL
 			   || replace_color->id == 0
 			   || replace_color->details->num_resources == 0);
 
 		   if(replace_rsc->variant == pe_native) {
 			   native_assign_color(replace_rsc, color);
 
 		   } else if(replace_rsc->variant == pe_group) {
 			   group_assign_color(replace_rsc, color);
 
 		   } else {
 			   crm_err("Bad variant: %d", replace_rsc->variant);
 		   }
 		);
-#endif		
+#endif
 	return NULL;
 }
 
 static void
 clone_update_pseudo_status(
 	resource_t *child, gboolean *stopping, gboolean *starting) 
 {
 	CRM_ASSERT(stopping != NULL);
 	CRM_ASSERT(starting != NULL);
 
 	slist_iter(
 		action, action_t, child->actions, lpc,
 
 		if(*starting && *stopping) {
 			return;
 
 		} else if(action->optional) {
 			crm_debug_3("Skipping optional: %s", action->uuid);
 			continue;
 
 		} else if(action->pseudo == FALSE && action->runnable == FALSE){
 			crm_debug_3("Skipping unrunnable: %s", action->uuid);
 			continue;
 
 		} else if(safe_str_eq(CRMD_ACTION_STOP, action->task)) {
 			crm_debug_2("Stopping due to: %s", action->uuid);
 			*stopping = TRUE;
 
 		} else if(safe_str_eq(CRMD_ACTION_START, action->task)) {
 			if(action->runnable == FALSE) {
 				crm_debug_3("Skipping pseduo-op: %s run=%d, pseudo=%d",
 					    action->uuid, action->runnable, action->pseudo);
 			} else {
 				crm_debug_2("Starting due to: %s", action->uuid);
 				crm_debug_3("%s run=%d, pseudo=%d",
 					    action->uuid, action->runnable, action->pseudo);
 				*starting = TRUE;
 			}
 		}
 		);
 
 }
 
 void clone_create_actions(resource_t *rsc, pe_working_set_t *data_set)
 {
 	gboolean child_starting = FALSE;
 	gboolean child_stopping = FALSE;
 	action_t *stop = NULL;
 	action_t *start = NULL;
 	action_t *action_complete = NULL;
 	resource_t *last_start_rsc = NULL;
 	resource_t *last_stop_rsc = NULL;
 	clone_variant_data_t *clone_data = NULL;
 
 	get_clone_variant_data(clone_data, rsc);
 	
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 		child_rsc->cmds->create_actions(child_rsc, data_set);
 		clone_update_pseudo_status(
 			child_rsc, &child_stopping, &child_starting);
 		
 		if(child_rsc->starting) {
 			last_start_rsc = child_rsc;
 		}
 		if(child_rsc->stopping) {
 			last_stop_rsc = child_rsc;
 		}
 		);
 
 	/* start */
 	start = start_action(clone_data->self, NULL, !child_starting);
 	action_complete = custom_action(
 		clone_data->self, started_key(rsc),
 		CRMD_ACTION_STARTED, NULL, !child_starting, TRUE, data_set);
 
 	start->pseudo = TRUE;
 	action_complete->pseudo = TRUE;
 	action_complete->priority = INFINITY;
 	
 	child_starting_constraints(clone_data, pe_ordering_optional, 
 				   NULL, last_start_rsc, data_set);
 
 	clone_create_notifications(
 		rsc, start, action_complete, data_set);	
 
 
 	/* stop */
 	stop = stop_action(clone_data->self, NULL, !child_stopping);
 	action_complete = custom_action(
 		clone_data->self, stopped_key(rsc),
 		CRMD_ACTION_STOPPED, NULL, !child_stopping, TRUE, data_set);
 
 	stop->pseudo = TRUE;
 	action_complete->pseudo = TRUE;
 	action_complete->priority = INFINITY;
 	
 	child_stopping_constraints(clone_data, pe_ordering_optional,
 				   NULL, last_stop_rsc, data_set);
 
 	
 	clone_create_notifications(rsc, stop, action_complete, data_set);	
 	rsc->actions = clone_data->self->actions;	
 
 	if(stop->post_notified != NULL && start->pre_notify != NULL) {
 		order_actions(stop->post_notified, start->pre_notify, pe_ordering_optional);	
 	}
 }
 
 void
 clone_create_notifications(
 	resource_t *rsc, action_t *action, action_t *action_complete,
 	pe_working_set_t *data_set)
 {
 	/*
 	 * pre_notify -> pre_notify_complete -> pseudo_action
 	 *   -> (real actions) -> pseudo_action_complete
 	 *   -> post_notify -> post_notify_complete
 	 *
 	 * if the pre_noitfy requires confirmation,
 	 *   then a list of confirmations will be added as triggers
 	 *   to pseudo_action in clone_expand()
 	 */
 	action_t *notify = NULL;
 	action_t *notify_complete = NULL;
 	enum action_tasks task;
 	char *notify_key = NULL;
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 	
 	if(rsc->notify == FALSE) {
 		return;
 	}
 	
 	task = text2task(action->task);
 
 	/* create pre_notify */
 	notify_key = generate_notify_key(
 		clone_data->self->id, "pre", action->task);
 	notify = custom_action(clone_data->self, notify_key,
 			       CRMD_ACTION_NOTIFY, NULL,
 			       action->optional, TRUE, data_set);
 	
 	add_hash_param(notify->meta, "notify_type", "pre");
 	add_hash_param(notify->meta, "notify_operation", action->task);
 	if(clone_data->notify_confirm) {
 		add_hash_param(notify->meta, "notify_confirm", "yes");
 	} else {
 		add_hash_param(notify->meta, "notify_confirm", "no");
 	}
 	notify->pseudo = TRUE;
 
 	/* create pre_notify_complete */
 	notify_key = generate_notify_key(
 		clone_data->self->id, "confirmed-pre", action->task);
 	notify_complete = custom_action(clone_data->self, notify_key,
 			       CRMD_ACTION_NOTIFIED, NULL,
 			       action->optional, TRUE, data_set);
 	add_hash_param(notify_complete->meta, "notify_type", "pre");
 	add_hash_param(notify_complete->meta, "notify_operation", action->task);
 	if(clone_data->notify_confirm) {
 		add_hash_param(notify->meta, "notify_confirm", "yes");
 	} else {
 		add_hash_param(notify->meta, "notify_confirm", "no");
 	}
 	notify->pseudo = TRUE;
 	notify_complete->pseudo = TRUE;
 
 	/* pre_notify before pre_notify_complete */
 	custom_action_order(
 		clone_data->self, NULL, notify,
 		clone_data->self, NULL, notify_complete,
 		pe_ordering_manditory, data_set);
 	
 	/* pre_notify_complete before action */
 	custom_action_order(
 		clone_data->self, NULL, notify_complete,
 		clone_data->self, NULL, action,
 		pe_ordering_manditory, data_set);
 
 	action->pre_notify = notify;
 	action->pre_notified = notify_complete;
 	
 	/* create post_notify */
 	notify_key = generate_notify_key
 		(clone_data->self->id, "post", action->task);
 	notify = custom_action(clone_data->self, notify_key,
 			       CRMD_ACTION_NOTIFY, NULL,
 			       action_complete->optional, TRUE, data_set);
 	add_hash_param(notify->meta, "notify_type", "post");
 	add_hash_param(notify->meta, "notify_operation", action->task);
 	if(clone_data->notify_confirm) {
 		add_hash_param(notify->meta, "notify_confirm", "yes");
 	} else {
 		add_hash_param(notify->meta, "notify_confirm", "no");
 	}
 	notify->pseudo = TRUE;
 
 	/* action_complete before post_notify */
 	custom_action_order(
 		clone_data->self, NULL, action_complete,
 		clone_data->self, NULL, notify, 
 		pe_ordering_postnotify, data_set);
 	
 	/* create post_notify_complete */
 	notify_key = generate_notify_key(
 		clone_data->self->id, "confirmed-post", action->task);
 	notify_complete = custom_action(clone_data->self, notify_key,
 			       CRMD_ACTION_NOTIFIED, NULL,
 			       action->optional, TRUE, data_set);
 	add_hash_param(notify_complete->meta, "notify_type", "pre");
 	add_hash_param(notify_complete->meta, "notify_operation", action->task);
 	if(clone_data->notify_confirm) {
 		add_hash_param(notify->meta, "notify_confirm", "yes");
 	} else {
 		add_hash_param(notify->meta, "notify_confirm", "no");
 	}
 	notify_complete->pseudo = TRUE;
 
 	/* post_notify before post_notify_complete */
 	custom_action_order(
 		clone_data->self, NULL, notify,
 		clone_data->self, NULL, notify_complete,
 		pe_ordering_manditory, data_set);
 
 	action->post_notify = notify;
 	action->post_notified = notify_complete;
 
 
 	if(safe_str_eq(action->task, CRMD_ACTION_STOP)) {
 		/* post_notify_complete before start */
 		custom_action_order(
 			clone_data->self, NULL, notify_complete,
 			clone_data->self, start_key(clone_data->self), NULL,
 			pe_ordering_optional, data_set);
 
 	} else if(safe_str_eq(action->task, CRMD_ACTION_START)) {
 		/* post_notify_complete before promote */
 		custom_action_order(
 			clone_data->self, NULL, notify_complete,
 			clone_data->self, promote_key(clone_data->self), NULL,
 			pe_ordering_optional, data_set);
 
 	} else if(safe_str_eq(action->task, CRMD_ACTION_DEMOTE)) {
 		/* post_notify_complete before promote */
 		custom_action_order(
 			clone_data->self, NULL, notify_complete,
 			clone_data->self, stop_key(clone_data->self), NULL,
 			pe_ordering_optional, data_set);
 	}
 }
 
 void
 child_starting_constraints(
 	clone_variant_data_t *clone_data, enum pe_ordering type,
 	resource_t *child, resource_t *last, pe_working_set_t *data_set)
 {
 	if(clone_data->ordered
 	   || clone_data->self->restart_type == pe_restart_restart) {
 		type = pe_ordering_manditory;
 	}
 	if(child == NULL) {
 		if(clone_data->ordered && last != NULL) {
 			crm_debug_4("Ordered version (last node)");
 			/* last child start before global started */
 			custom_action_order(
 				last, start_key(last), NULL,
 				clone_data->self, started_key(clone_data->self), NULL,
 				type, data_set);
 		}
 		
 	} else if(clone_data->ordered) {
 		crm_debug_4("Ordered version");
 		if(last == NULL) {
 			/* global start before first child start */
 			last = clone_data->self;
 
 		} /* else: child/child relative start */
 
 		order_start_start(last, child, type);
 
 	} else {
 		crm_debug_4("Un-ordered version");
 		
 		/* child start before global started */
 		custom_action_order(
 			child, start_key(child), NULL,
 			clone_data->self, started_key(clone_data->self), NULL,
 			type, data_set);
                 
 		/* global start before child start */
 /* 		order_start_start(clone_data->self, child, type); */
 		order_start_start(
 			clone_data->self, child, pe_ordering_manditory);
 	}
 }
 
 void
 child_stopping_constraints(
 	clone_variant_data_t *clone_data, enum pe_ordering type,
 	resource_t *child, resource_t *last, pe_working_set_t *data_set)
 {
 	if(clone_data->ordered
 	   || clone_data->self->restart_type == pe_restart_restart) {
 		type = pe_ordering_manditory;
 	}
 	
 	if(child == NULL) {
 		if(clone_data->ordered && last != NULL) {
 			crm_debug_4("Ordered version (last node)");
 			/* global stop before first child stop */
 			order_stop_stop(clone_data->self, last,
 					pe_ordering_manditory);
 		}
 		
 	} else if(clone_data->ordered && last != NULL) {
 		crm_debug_4("Ordered version");
 
 		/* child/child relative stop */
 		order_stop_stop(child, last, type);
 
 	} else if(clone_data->ordered) {
 		crm_debug_4("Ordered version (1st node)");
 		/* first child stop before global stopped */
 		custom_action_order(
 			child, stop_key(child), NULL,
 			clone_data->self, stopped_key(clone_data->self), NULL,
 			type, data_set);
 
 	} else {
 		crm_debug_4("Un-ordered version");
 
 		/* child stop before global stopped */
 		custom_action_order(
 			child, stop_key(child), NULL,
 			clone_data->self, stopped_key(clone_data->self), NULL,
 			type, data_set);
                         
 		/* global stop before child stop */
 		order_stop_stop(clone_data->self, child, type);
 	}
 }
 
 
 void
 clone_internal_constraints(resource_t *rsc, pe_working_set_t *data_set)
 {
 	resource_t *last_rsc = NULL;	
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	clone_data->self->cmds->internal_constraints(clone_data->self, data_set);
 	
 	/* global stop before stopped */
 	custom_action_order(
 		clone_data->self, stop_key(clone_data->self), NULL,
 		clone_data->self, stopped_key(clone_data->self), NULL,
 		pe_ordering_optional, data_set);
 
 	/* global start before started */
 	custom_action_order(
 		clone_data->self, start_key(clone_data->self), NULL,
 		clone_data->self, started_key(clone_data->self), NULL,
 		pe_ordering_optional, data_set);
 	
 	/* global stopped before start */
 	custom_action_order(
 		clone_data->self, stopped_key(clone_data->self), NULL,
 		clone_data->self, start_key(clone_data->self), NULL,
 		pe_ordering_optional, data_set);
 	
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 
 		child_rsc->cmds->internal_constraints(child_rsc, data_set);
 
 		child_starting_constraints(
 			clone_data, pe_ordering_optional,
 			child_rsc, last_rsc, data_set);
 
 		child_stopping_constraints(
 			clone_data, pe_ordering_optional,
 			child_rsc, last_rsc, data_set);
 
 		last_rsc = child_rsc;
 		
 		);
 
 	child_starting_constraints(
 		clone_data, pe_ordering_optional,
 		NULL, last_rsc, data_set);
 	
 	child_stopping_constraints(
 		clone_data, pe_ordering_optional,
 		NULL, last_rsc, data_set);
 }
 
 static resource_t*
 find_compatible_child(resource_t *local_child, resource_t *rsc)
 {
 #if 0
 	node_t *local_node = NULL;
 	node_t *node = NULL;
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 	CRM_ASSERT(local_child->color != NULL);
 	
 	local_node = local_child->color->details->candidate_nodes->data;
 	if(local_node == NULL) {
 		crm_debug("Can't colocate unrunnable child %s with %s",
 			 local_child->id, rsc->id);
 		return NULL;
 	}
 	
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 		CRM_ASSERT(child_rsc->color != NULL);
 		node = child_rsc->color->details->candidate_nodes->data;
 		if(node->details == local_node->details) {
 			crm_info("Colocating %s with %s on %s",
 				 local_child->id, child_rsc->id, node->details->uname);
 			return child_rsc;
 		}
 		);
 	crm_debug("Can't colocate child %s with %s",
 		 local_child->id, rsc->id);
 #endif
 	return NULL;
 }
 
 void clone_rsc_colocation_lh(
 	resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
 {
 	gboolean do_interleave = FALSE;
 	resource_t *rsc = constraint->rsc_lh;
 	clone_variant_data_t *clone_data = NULL;
 	clone_variant_data_t *clone_data_rh = NULL;
 	
 	if(rsc == NULL) {
 		pe_err("rsc_lh was NULL for %s", constraint->id);
 		return;
 
 	} else if(constraint->rsc_rh == NULL) {
 		pe_err("rsc_rh was NULL for %s", constraint->id);
 		return;
 		
 	} else {
 		crm_debug_4("Processing constraints from %s", rsc->id);
 	}
 	
 	get_clone_variant_data(clone_data, rsc);
 
 	if(constraint->rsc_rh->variant == pe_clone) {
 		get_clone_variant_data(
 			clone_data_rh, constraint->rsc_rh);
 		if(clone_data->clone_node_max
 		   != clone_data_rh->clone_node_max) {
 			pe_err("Cannot interleave "XML_CIB_TAG_INCARNATION
 			       " %s and %s because"
 			       " they do not support the same number of"
 			       " resources per node",
 			       constraint->rsc_lh->id, constraint->rsc_rh->id);
 			
 		/* only the LHS side needs to be labeled as interleave */
 		} else if(clone_data->interleave) {
 			do_interleave = TRUE;
 
 		} else if(constraint->score != INFINITY) {
 			pe_warn("rsc_colocations other than \"-INFINITY\""
 				" are not supported for non-interleaved "
 				XML_CIB_TAG_INCARNATION" resources");
 			return;
 		}
 
 	} else if(constraint->score != -INFINITY) {
 		pe_warn("Co-location scores other than \"-INFINITY\" are not "
 			" allowed for non-"XML_CIB_TAG_INCARNATION" resources");
 		return;
 	}
 	
 	if(do_interleave) {
 		resource_t *rh_child = NULL;
 		
 		slist_iter(lh_child, resource_t, clone_data->child_list, lpc,
 
 			   CRM_ASSERT(lh_child != NULL);
 			   rh_child = find_compatible_child(lh_child, rsc_rh);
 			   if(rh_child == NULL) {
 				   continue;
 			   }
 			   lh_child->cmds->rsc_colocation_lh(
 				   lh_child, rh_child, constraint);
 			);
 		return;
 	}
 	
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 		
 		child_rsc->cmds->rsc_colocation_lh(child_rsc, constraint->rsc_rh, constraint);
 		);
 }
 
 
 
 void clone_rsc_colocation_rh(
 	resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
 {
 	clone_variant_data_t *clone_data = NULL;
 	CRM_CHECK(rsc_lh != NULL, return);
 	CRM_CHECK(rsc_lh->variant == pe_native, return);
 	
 	crm_debug_3("Processing RH of constraint %s", constraint->id);
 
 	if(rsc_rh == NULL) {
 		pe_err("rsc_rh was NULL for %s", constraint->id);
 		return;
 		
 	} else if(constraint->score != -INFINITY) {
 		pe_warn("rsc_dependencies other than \"must_not\" "
 			"are not supported for clone resources");
 		return;
 		
 	} else {
 		print_resource(LOG_DEBUG_3, "LHS", rsc_lh, FALSE);
 	}
 	
 	get_clone_variant_data(clone_data, rsc_rh);
 
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 		
 		print_resource(LOG_DEBUG_3, "RHS", child_rsc, FALSE);
 		child_rsc->cmds->rsc_colocation_rh(rsc_lh, child_rsc, constraint);
 		);
 }
 
 
 void clone_rsc_order_lh(resource_t *rsc, order_constraint_t *order)
 {
 	char *stop_id = NULL;
 	char *start_id = NULL;
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	crm_debug_3("Processing LH of ordering constraint %d", order->id);
 
 	stop_id = stop_key(rsc);
 	start_id = start_key(rsc);
 	
 	if(safe_str_eq(order->lh_action_task, start_id)) {
 		crm_free(order->lh_action_task);
 		order->lh_action_task = started_key(rsc);
 
 	} else if(safe_str_eq(order->lh_action_task, stop_id)) {
 		crm_free(order->lh_action_task);
 		order->lh_action_task = stopped_key(rsc);
 	}
 
 	crm_free(start_id);
 	crm_free(stop_id);
 	
 	clone_data->self->cmds->rsc_order_lh(clone_data->self, order);
 }
 
 void clone_rsc_order_rh(
 	action_t *lh_action, resource_t *rsc, order_constraint_t *order)
 {
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	crm_debug_3("Processing RH of ordering constraint %d", order->id);
 
  	clone_data->self->cmds->rsc_order_rh(lh_action, clone_data->self, order);
 
 }
 
 void clone_rsc_location(resource_t *rsc, rsc_to_node_t *constraint)
 {
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	crm_debug_3("Processing location constraint %s for %s", constraint->id, rsc->id);
 
 	clone_data->self->cmds->rsc_location(clone_data->self, constraint);
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 
 		child_rsc->cmds->rsc_location(child_rsc, constraint);
 		);
 }
 
 static gint
 sort_notify_entries(gconstpointer a, gconstpointer b)
 {
 	int tmp;
 	const notify_entry_t *entry_a = a;
 	const notify_entry_t *entry_b = b;
 
 	if(entry_a == NULL && entry_b == NULL) { return 0; }
 	if(entry_a == NULL) { return 1; }
 	if(entry_b == NULL) { return -1; }
 
 	if(entry_a->rsc == NULL && entry_b->rsc == NULL) { return 0; }
 	if(entry_a->rsc == NULL) { return 1; }
 	if(entry_b->rsc == NULL) { return -1; }
 
 	tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id);
 	if(tmp != 0) {
 		return tmp;
 	}
 
 	if(entry_a->node == NULL && entry_b->node == NULL) { return 0; }
 	if(entry_a->node == NULL) { return 1; }
 	if(entry_b->node == NULL) { return -1; }
 
 	return strcmp(entry_a->node->details->id, entry_b->node->details->id);
 }
 
 static void
 expand_list(GListPtr list, int clones,
 	    char **rsc_list, char **node_list, char **uuid_list)
 {
 	const char *uname = NULL;
 	const char *rsc_id = NULL;
 	const char *last_rsc_id = NULL;
 	
 	CRM_CHECK(list != NULL, return);
 	if(rsc_list) {
 		CRM_CHECK(*rsc_list == NULL, *rsc_list = NULL);
 	}
 	if(node_list) {
 		CRM_CHECK(*node_list == NULL, *node_list = NULL);
 	}
 	
 	slist_iter(entry, notify_entry_t, list, lpc,
 
 		   CRM_CHECK(entry != NULL, continue);
 		   rsc_id = entry->rsc->id;
 		   CRM_CHECK(rsc_id != NULL, rsc_id = "__none__");
 		   uname = NULL;
 		   if(entry->node) {
 			   uname = entry->node->details->uname;
 		   }
 		   CRM_CHECK(uname != NULL, uname = "__none__");
 
 		   /* filter dups */
 		   if(safe_str_eq(rsc_id, last_rsc_id)) {
 			   continue;
 		   }
 		   last_rsc_id = rsc_id;
 
 		   if(rsc_list != NULL) {
 			   int existing_len = 0;
 			   int len = 2 + strlen(rsc_id); /* +1 space, +1 EOS */
 			   if(rsc_list && *rsc_list) {
 				   existing_len = strlen(*rsc_list);
 			   }
 
 			   crm_debug_5("Adding %s (%dc) at offset %d",
 				       rsc_id, len-2, existing_len);
 			   crm_realloc(*rsc_list, len + existing_len);
 			   sprintf(*rsc_list + existing_len, "%s ", rsc_id);
 		   }
 		   
 		   if(node_list != NULL) {
 			   int existing_len = 0;
 			   int len = 2 + strlen(uname);
 			   if(node_list && *node_list) {
 				   existing_len = strlen(*node_list);
 			   }
 			   
 			   crm_debug_5("Adding %s (%dc) at offset %d",
 				       uname, len-2, existing_len);
 			   crm_realloc(*node_list, len + existing_len);
 			   sprintf(*node_list + existing_len, "%s ", uname);
 		   }
 		   );
 }
 
 void clone_expand(resource_t *rsc, pe_working_set_t *data_set)
 {
 	char *rsc_list = NULL;
 	char *node_list = NULL;
 	char *uuid_list = NULL;	
 
 	notify_data_t *n_data = NULL;
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	crm_malloc0(n_data, sizeof(notify_data_t));
 	n_data->keys = g_hash_table_new_full(
 		g_str_hash, g_str_equal,
 		g_hash_destroy_str, g_hash_destroy_str);
 	
 	crm_debug_2("Processing actions from %s", rsc->id);
 
 	
 	if(rsc->notify) {
 		slist_iter(
 			child_rsc, resource_t, clone_data->child_list, lpc,
 			
 			slist_iter(
 				op, action_t, clone_data->self->actions, lpc2,
 			
 				child_rsc->cmds->create_notify_element(
 					child_rsc, op, n_data, data_set);
 				);
 			);
 	}
 	
 	/* expand the notify data */		
 	if(rsc->notify && n_data->stop) {
 		n_data->stop = g_list_sort(
 			n_data->stop, sort_notify_entries);
 		rsc_list = NULL; node_list = NULL;
 		expand_list(n_data->stop, clone_data->clone_max,
 			    &rsc_list, &node_list, &uuid_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_stop_resource"), rsc_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_stop_uname"), node_list);
 	}
 
 	if(rsc->notify && n_data->start) {
 		n_data->start = g_list_sort(
 			n_data->start, sort_notify_entries);
 		rsc_list = NULL; node_list = NULL; 
 		expand_list(n_data->start, clone_data->clone_max,
 			    &rsc_list, &node_list, &uuid_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_start_resource"), rsc_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_start_uname"), node_list);
 	}
 	
 	if(rsc->notify && n_data->demote) {
 		n_data->demote = g_list_sort(
 			n_data->demote, sort_notify_entries);
 		rsc_list = NULL; node_list = NULL;
 		expand_list(n_data->demote, clone_data->clone_max,
 			    &rsc_list, &node_list, &uuid_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_demote_resource"), rsc_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_demote_uname"), node_list);
 	}
 	
 	if(rsc->notify && n_data->promote) {
 		n_data->promote = g_list_sort(
 			n_data->promote, sort_notify_entries);
 		rsc_list = NULL; node_list = NULL; uuid_list = NULL;
 		expand_list(n_data->promote, clone_data->clone_max,
 			    &rsc_list, &node_list, &uuid_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_promote_resource"), rsc_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_promote_uname"), node_list);
 	}
 	
 	if(rsc->notify && n_data->active) {
 		n_data->active = g_list_sort(
 			n_data->active, sort_notify_entries);
 		rsc_list = NULL; node_list = NULL; uuid_list = NULL;
 		expand_list(n_data->active, clone_data->clone_max,
 			    &rsc_list, &node_list, &uuid_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_active_resource"), rsc_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_active_uname"), node_list);
 	}
 
 	if(rsc->notify && n_data->slave) {
 		n_data->slave = g_list_sort(
 			n_data->slave, sort_notify_entries);
 		rsc_list = NULL; node_list = NULL; uuid_list = NULL;
 		expand_list(n_data->slave, clone_data->clone_max,
 			    &rsc_list, &node_list, &uuid_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_slave_resource"), rsc_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_slave_uname"), node_list);
 	}
 
 	if(rsc->notify && n_data->master) {
 		n_data->master = g_list_sort(
 			n_data->master, sort_notify_entries);
 		rsc_list = NULL; node_list = NULL; uuid_list = NULL;
 		expand_list(n_data->master, clone_data->clone_max,
 			    &rsc_list, &node_list, &uuid_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_master_resource"), rsc_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_master_uname"), node_list);
 	}
 
 	if(rsc->notify && n_data->inactive) {
 		n_data->inactive = g_list_sort(
 			n_data->inactive, sort_notify_entries);
 		rsc_list = NULL; node_list = NULL; uuid_list = NULL;
 		expand_list(n_data->inactive, clone_data->clone_max,
 			    &rsc_list, &node_list, &uuid_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_inactive_resource"), rsc_list);
 		g_hash_table_insert(
 			n_data->keys,
 			crm_strdup("notify_inactive_uname"), node_list);
 	}
 	
 	/* yes, we DO need this second loop */
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 		
 		child_rsc->cmds->expand(child_rsc, data_set);
 
 		);
 	
 /* 	slist_iter( */
 /* 		action, action_t, clone_data->self->actions, lpc2, */
 
 /* 		if(safe_str_eq(action->task, CRMD_ACTION_NOTIFY)) { */
 /* 			action->meta_xml = notify_xml; */
 /* 		} */
 /* 		); */
 	
 	clone_data->self->cmds->expand(clone_data->self, data_set);
 
 	/* destroy the notify_data */
 	pe_free_shallow(n_data->stop);
 	pe_free_shallow(n_data->start);
 	pe_free_shallow(n_data->demote);
 	pe_free_shallow(n_data->promote);
 	pe_free_shallow(n_data->master);
 	pe_free_shallow(n_data->slave);
 	pe_free_shallow(n_data->active);
 	pe_free_shallow(n_data->inactive);
 	g_hash_table_destroy(n_data->keys);
 	crm_free(n_data);
 }
 
 
 void
 clone_agent_constraints(resource_t *rsc)
 {
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 		
 		child_rsc->cmds->agent_constraints(child_rsc);
 		);
 }
 
 void
 clone_create_notify_element(resource_t *rsc, action_t *op,
 			    notify_data_t *n_data, pe_working_set_t *data_set)
 {
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 		
 		child_rsc->cmds->create_notify_element(
 			child_rsc, op, n_data, data_set);
 		);
 }
 
 static gint sort_rsc_id(gconstpointer a, gconstpointer b)
 {
 	const resource_t *resource1 = (const resource_t*)a;
 	const resource_t *resource2 = (const resource_t*)b;
 
 	CRM_ASSERT(resource1 != NULL);
 	CRM_ASSERT(resource2 != NULL);
 
 	return strcmp(resource1->id, resource2->id);
 }
 
 gboolean
 clone_create_probe(resource_t *rsc, node_t *node, action_t *complete,
 		    gboolean force, pe_working_set_t *data_set) 
 {
 	gboolean any_created = FALSE;
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	clone_data->child_list = g_list_sort(
 		clone_data->child_list, sort_rsc_id);
 
 	if(rsc->globally_unique == FALSE && clone_data->clone_node_max == 1) {
 		/* only look for one copy */	 
 		slist_iter(	 
 			child_rsc, resource_t, clone_data->child_list, lpc,	 
 
 			if(pe_find_node_id(child_rsc->running_on, node->details->id)) {	 
 				return child_rsc->cmds->create_probe(
 					child_rsc, node, complete, force, data_set);
 			}
 			);
 	}
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 
 		if(child_rsc->cmds->create_probe(
 			   child_rsc, node, complete, force, data_set)) {
 			any_created = TRUE;
 		}
 		
 		if(any_created
 		   && rsc->globally_unique == FALSE
 		   && clone_data->clone_node_max == 1) {
 			/* only look for one copy (clone :0) */	 
 			break;
 		}
 		);
 
 	return any_created;
 }
 
 void
 clone_stonith_ordering(
 	resource_t *rsc,  action_t *stonith_op, pe_working_set_t *data_set)
 {
 	clone_variant_data_t *clone_data = NULL;
 	get_clone_variant_data(clone_data, rsc);
 
 	slist_iter(
 		child_rsc, resource_t, clone_data->child_list, lpc,
 
 		child_rsc->cmds->stonith_ordering(
 			child_rsc, stonith_op, data_set);
 		);
 }
diff --git a/crm/pengine/native.c b/crm/pengine/native.c
index 156682f107..71ee2aa8c9 100644
--- a/crm/pengine/native.c
+++ b/crm/pengine/native.c
@@ -1,1526 +1,1469 @@
 /* $Id: native.c,v 1.161 2006/08/17 07:17:15 andrew Exp $ */
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <portability.h>
 
 #include <pengine.h>
 #include <crm/pengine/rules.h>
 #include <lib/crm/pengine/utils.h>
 #include <crm/msg_xml.h>
 #include <allocate.h>
 #include <utils.h>
 
 #define DELETE_THEN_REFRESH 1
 
 void node_list_update(GListPtr list1, GListPtr list2);
 
 void native_rsc_colocation_rh_must(resource_t *rsc_lh, gboolean update_lh,
 				   resource_t *rsc_rh, gboolean update_rh);
 
 void native_rsc_colocation_rh_mustnot(resource_t *rsc_lh, gboolean update_lh,
 				      resource_t *rsc_rh, gboolean update_rh);
 
 void filter_nodes(resource_t *rsc);
 
 void create_notifications(resource_t *rsc, pe_working_set_t *data_set);
 void Recurring(resource_t *rsc, action_t *start, node_t *node,
 			      pe_working_set_t *data_set);
 void pe_pre_notify(
 	resource_t *rsc, node_t *node, action_t *op, 
 	notify_data_t *n_data, pe_working_set_t *data_set);
 void pe_post_notify(
 	resource_t *rsc, node_t *node, action_t *op, 
 	notify_data_t *n_data, pe_working_set_t *data_set);
 
 gboolean DeleteRsc(resource_t *rsc, node_t *node, pe_working_set_t *data_set);
 void NoRoleChange(resource_t *rsc, node_t *current, node_t *next, pe_working_set_t *data_set);
 gboolean StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
 gboolean StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
 extern gboolean DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
 gboolean PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
 gboolean RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
 gboolean NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set);
 
 enum rsc_role_e rsc_state_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX] = {
 /* Current State */	
 /*    Next State:  Unknown 	    Stopped	      Started	        Slave	          Master */
 /* Unknown */	{ RSC_ROLE_UNKNOWN, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, },
 /* Stopped */	{ RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE,   RSC_ROLE_SLAVE, },
 /* Started */	{ RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_STARTED, RSC_ROLE_SLAVE,   RSC_ROLE_MASTER, },
 /* Slave */	{ RSC_ROLE_STOPPED, RSC_ROLE_STOPPED, RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE,   RSC_ROLE_MASTER, },
 /* Master */	{ RSC_ROLE_STOPPED, RSC_ROLE_SLAVE,   RSC_ROLE_UNKNOWN, RSC_ROLE_SLAVE,   RSC_ROLE_MASTER, },
 };
 
 gboolean (*rsc_action_matrix[RSC_ROLE_MAX][RSC_ROLE_MAX])(resource_t*,node_t*,pe_working_set_t*) = {
 /* Current State */	
 /*    Next State: Unknown	Stopped		Started		Slave		Master */
 /* Unknown */	{ RoleError,	StopRsc,	RoleError,	RoleError,	RoleError,  },
 /* Stopped */	{ RoleError,	NullOp,		StartRsc,	StartRsc,	RoleError,  },
 /* Started */	{ RoleError,	StopRsc,	NullOp,		NullOp,	        PromoteRsc,  },
 /* Slave */	{ RoleError,	StopRsc,	RoleError,	NullOp,		PromoteRsc, },
 /* Master */	{ RoleError,	RoleError,	RoleError,	DemoteRsc,	NullOp,     },
 };
 
 
 typedef struct native_variant_data_s
 {
 /* 		GListPtr allowed_nodes;    /\* node_t*   *\/ */
 
 } native_variant_data_t;
 
 #define get_native_variant_data(data, rsc)				\
 	CRM_ASSERT(rsc->variant == pe_native);				\
 	CRM_ASSERT(rsc->variant_opaque != NULL);			\
 	data = (native_variant_data_t *)rsc->variant_opaque;
 
 
+
 static gboolean
 native_choose_node(resource_t *rsc)
 {
 	/*
 	  1. Sort by weight
 	  2. color.chosen_node = the node (of those with the highest wieght)
 				   with the fewest resources
 	  3. remove color.chosen_node from all other colors
 	*/
 	GListPtr nodes = NULL;
 	node_t *chosen = NULL;
-	int multiple = 0;
 
 	crm_debug_3("Choosing node for %s from %d candidates",
 		    rsc->id, g_list_length(rsc->allowed_nodes));
 
 	if(rsc->allowed_nodes) {
 		rsc->allowed_nodes = g_list_sort(
 			rsc->allowed_nodes, sort_node_weight);
 		nodes = rsc->allowed_nodes;
 		chosen = g_list_nth_data(nodes, 0);
 	}
 	
-	if(chosen == NULL) {
-		crm_debug("Could not allocate a node for %s", rsc->id);
-		rsc->next_role = RSC_ROLE_STOPPED;
-		return FALSE;
-
-	} else if(chosen->details->unclean
-		  || chosen->details->standby
-		  || chosen->details->shutdown) {
-		crm_debug("All nodes for color %s are unavailable"
-			  ", unclean or shutting down", rsc->id);
-		rsc->next_role = RSC_ROLE_STOPPED;
-		return FALSE;
-		
-	} else if(chosen->weight < 0) {
-		crm_debug_2("Even highest ranked node for color %s, had weight %d",
-			  rsc->id, chosen->weight);
-		rsc->next_role = RSC_ROLE_STOPPED;
-		return FALSE;
-	}
-
-	if(rsc->next_role == RSC_ROLE_UNKNOWN) {
-		rsc->next_role = RSC_ROLE_STARTED;
-	}
-	
-	slist_iter(candidate, node_t, nodes, lpc, 
-		   crm_debug("Color %s, Node[%d] %s: %d", rsc->id, lpc,
-			       candidate->details->uname, candidate->weight);
-		   if(chosen->weight > 0
-		      && candidate->details->unclean == FALSE
-		      && candidate->weight == chosen->weight) {
-			   multiple++;
-		   } else {
-			   break;
-		   }
-		);
-
-	if(multiple > 1) {
-		int log_level = LOG_INFO;
-		char *score = score2char(chosen->weight);
-		if(chosen->weight >= INFINITY) {
-			log_level = LOG_WARNING;
-		}
-		
-		crm_log_maybe(log_level, "%d nodes with equal score (%s) for"
-			      " running the listed resources (chose %s):",
-			      multiple, score, chosen->details->uname);
-		crm_free(score);
-	}
-	
-	/* todo: update the old node for each resource to reflect its
-	 * new resource count
-	 */
-
-	crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id);
-	rsc->allocated_to = node_copy(chosen);
-	chosen->details->num_resources++;
-	
-	return TRUE;
+	return native_assign_node(rsc, nodes, chosen);
 }
 
 void native_set_cmds(resource_t *rsc)
 {
 }
 
 int native_num_allowed_nodes(resource_t *rsc)
 {
 	int num_nodes = 0;
 
 	if(rsc->next_role == RSC_ROLE_STOPPED) {
 		return 0;
 	}
 	
 	crm_debug_4("Default case");
 	slist_iter(
 		this_node, node_t, rsc->allowed_nodes, lpc,
 		crm_debug_3("Rsc %s Checking %s: %d",
 			    rsc->id, this_node->details->uname,
 			    this_node->weight);
 		if(this_node->details->shutdown
 		   || this_node->details->online == FALSE) {
 			this_node->weight = -INFINITY;
 		}
 		if(this_node->weight < 0) {				
 			continue;
 /* 			} else if(this_node->details->unclean) { */
 /* 				continue; */
 		}
 		
 		num_nodes++;
 		);
 
 	crm_debug_2("Resource %s can run on %d nodes", rsc->id, num_nodes);
 	return num_nodes;
 }
 
 
 node_t *
 native_color(resource_t *rsc, pe_working_set_t *data_set)
 {
 	print_resource(LOG_DEBUG_2, "Allocating: ", rsc, FALSE);
 	
 	if(rsc->provisional == FALSE) {
 		return rsc->allocated_to;
 	}
 	if(rsc->is_allocating) {
 		crm_err("Dependancy loop detected involving %s", rsc->id);
 		return NULL;
 	}
 	
 	rsc->is_allocating = TRUE;
 	rsc->rsc_cons = g_list_sort(rsc->rsc_cons, sort_cons_strength);
 
 	/*------ Pre-processing ------*/
 	slist_iter(
 		constraint, rsc_colocation_t, rsc->rsc_cons, lpc,
 
 		crm_debug_3("Pre-Processing %s", constraint->id);		
 
 		/* or use ordering constraints? */
 		constraint->rsc_rh->cmds->color(
 			constraint->rsc_rh, data_set);
 		rsc->cmds->rsc_colocation_lh(
 			rsc, constraint->rsc_rh, constraint);
 		
 		);
 
 	if(native_choose_node(rsc) ) {
 		crm_debug("Allocated resource %s to %s",
 			    rsc->id, rsc->allocated_to->details->uname);
 	} else {
 		pe_warn("Resource %s cannot run anywhere", rsc->id);
 	}
 	rsc->provisional = FALSE;
 	rsc->is_allocating = FALSE;
 
 	/*------ Post-processing ------*/
 	slist_iter(
 		constraint, rsc_colocation_t, rsc->rsc_cons, lpc,
 		crm_debug_3("Post-Processing %s", constraint->id);
 		rsc->cmds->rsc_colocation_lh(
 			rsc, constraint->rsc_rh, constraint);
 		);
 	print_resource(LOG_DEBUG_3, "Allocated ", rsc, TRUE);
 
 	return rsc->allocated_to;
 }
 
 void
 Recurring(resource_t *rsc, action_t *start, node_t *node,
 			 pe_working_set_t *data_set) 
 {
 	char *key = NULL;
 	const char *name = NULL;
 	const char *value = NULL;
 	const char *interval = NULL;
 	const char *node_uname = NULL;
 
 	int interval_ms = 0;
 	action_t *mon = NULL;
 	gboolean is_optional = TRUE;
 	GListPtr possible_matches = NULL;
 	
 	crm_debug_2("Creating recurring actions for %s", rsc->id);
 	if(node != NULL) {
 		node_uname = node->details->uname;
 	}
 	
 	xml_child_iter_filter(
 		rsc->ops_xml, operation, "op",
 		
 		is_optional = TRUE;
 		name = crm_element_value(operation, "name");
 		interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
 		interval_ms = crm_get_msec(interval);
 
 		if(interval_ms <= 0) {
 			continue;
 		}
 
 		value = crm_element_value(operation, "disabled");
 		if(crm_is_true(value)) {
 			continue;
 		}
 		
 		key = generate_op_key(rsc->id, name, interval_ms);
 		if(start != NULL) {
 			crm_debug_3("Marking %s %s due to %s",
 				    key, start->optional?"optional":"manditory",
 				    start->uuid);
 			is_optional = start->optional;
 		} else {
 			crm_debug_2("Marking %s optional", key);
 			is_optional = TRUE;
 		}
 		
 		/* start a monitor for an already active resource */
 		possible_matches = find_actions_exact(rsc->actions, key, node);
 		if(possible_matches == NULL) {
 			is_optional = FALSE;
 			crm_debug_3("Marking %s manditory: not active", key);
 		}
 
 		value = crm_element_value(operation, "role");
 		if((rsc->next_role == RSC_ROLE_MASTER && value == NULL)
 		   || (value != NULL && text2role(value) != rsc->next_role)) {
 			int log_level = LOG_DEBUG_2;
 			const char *foo = "Ignoring";
 			if(is_optional) {
 				log_level = LOG_INFO;
 				foo = "Cancelling";
 				/* its running : cancel it */
 
 				mon = custom_action(
 					rsc, crm_strdup(key), CRMD_ACTION_CANCEL, node,
 					FALSE, TRUE, data_set);
 
 				mon->task = CRMD_ACTION_CANCEL;
 				add_hash_param(mon->meta, XML_LRM_ATTR_INTERVAL, interval);
 				add_hash_param(mon->meta, XML_LRM_ATTR_TASK, name);
 				
 				custom_action_order(
 					rsc, NULL, mon,
 					rsc, promote_key(rsc), NULL,
 					pe_ordering_optional, data_set);
 
 				mon = NULL;
 			}
 			
 			crm_log_maybe(log_level, "%s action %s (%s vs. %s)",
 				      foo , key, value?value:role2text(RSC_ROLE_SLAVE),
 				      role2text(rsc->next_role));
 			crm_free(key);
 			key = NULL;
 			continue;
 		}		
 		
 		mon = custom_action(rsc, key, name, node,
 				    is_optional, TRUE, data_set);
 
 		if(is_optional) {
 			crm_debug("%s\t   %s (optional)",
 				  crm_str(node_uname), mon->uuid);
 		}
 		
 		if(start == NULL || start->runnable == FALSE) {
 			crm_debug("%s\t   %s (cancelled : start un-runnable)",
 				  crm_str(node_uname), mon->uuid);
 			mon->runnable = FALSE;
 
 		} else if(node == NULL
 			  || node->details->online == FALSE
 			  || node->details->unclean) {
 			crm_debug("%s\t   %s (cancelled : no node available)",
 				  crm_str(node_uname), mon->uuid);
 			mon->runnable = FALSE;
 		
 		} else if(mon->optional == FALSE) {
 			crm_notice("%s\t   %s", crm_str(node_uname),mon->uuid);
 		}
 
 		custom_action_order(rsc, start_key(rsc), NULL,
 				    NULL, crm_strdup(key), mon,
 				    pe_ordering_restart, data_set);
 
 		if(rsc->next_role == RSC_ROLE_MASTER) {
 			char *running_master = crm_itoa(EXECRA_RUNNING_MASTER);
 			add_hash_param(mon->meta, XML_ATTR_TE_TARGET_RC, running_master);
 			custom_action_order(
 				rsc, promote_key(rsc), NULL,
 				rsc, NULL, mon,
 				pe_ordering_optional, data_set);
 			crm_free(running_master);
 		}		
 		);	
 }
 
 void native_create_actions(resource_t *rsc, pe_working_set_t *data_set)
 {
 	action_t *start = NULL;
 	node_t *chosen = NULL;
 	enum rsc_role_e role = RSC_ROLE_UNKNOWN;
 	enum rsc_role_e next_role = RSC_ROLE_UNKNOWN;
 
 	chosen = rsc->allocated_to;
 	if(chosen != NULL) {
 		CRM_CHECK(rsc->next_role != RSC_ROLE_UNKNOWN, rsc->next_role = RSC_ROLE_STARTED);
 	}
 
 	unpack_instance_attributes(
 		rsc->xml, XML_TAG_ATTR_SETS,
 		chosen?chosen->details->attrs:NULL,
 		rsc->parameters, NULL, data_set->now);
 
 	crm_debug_2("%s: %s->%s", rsc->id,
 		    role2text(rsc->role), role2text(rsc->next_role));
 	
 	if(g_list_length(rsc->running_on) > 1) {
  		if(rsc->recovery_type == recovery_stop_start) {
 			pe_proc_err("Attempting recovery of resource %s", rsc->id);
 			StopRsc(rsc, NULL, data_set);
 			rsc->role = RSC_ROLE_STOPPED;
 		}
 		
 	} else if(rsc->running_on != NULL) {
 		node_t *current = rsc->running_on->data;
 		NoRoleChange(rsc, current, chosen, data_set);
 
 	} else if(rsc->role == RSC_ROLE_STOPPED && rsc->next_role == RSC_ROLE_STOPPED) {
 		char *key = start_key(rsc);
 		GListPtr possible_matches = find_actions(rsc->actions, key, NULL);
 		slist_iter(
 			action, action_t, possible_matches, lpc,
 			action->optional = TRUE;
 /*			action->pseudo = TRUE; */
 			);
 		crm_debug_2("Stopping a stopped resource");
 		crm_free(key);
 		return;
 	} 
 
 	role = rsc->role;
 
 	while(role != rsc->next_role) {
 		next_role = rsc_state_matrix[role][rsc->next_role];
 		crm_debug_2("Executing: %s->%s (%s)",
 			  role2text(role), role2text(next_role), rsc->id);
 		if(rsc_action_matrix[role][next_role](
 			   rsc, chosen, data_set) == FALSE) {
 			break;
 		}
 		role = next_role;
 	}
 
 	if(rsc->next_role != RSC_ROLE_STOPPED && rsc->is_managed) {
 		start = start_action(rsc, chosen, TRUE);
 		Recurring(rsc, start, chosen, data_set);
 	}
 }
 
 void native_internal_constraints(resource_t *rsc, pe_working_set_t *data_set)
 {
 	order_restart(rsc);
 	custom_action_order(rsc, demote_key(rsc), NULL,
 			    rsc, stop_key(rsc), NULL,
 			    pe_ordering_manditory, data_set);
 	custom_action_order(rsc, start_key(rsc), NULL,
 			    rsc, promote_key(rsc), NULL,
 			    pe_ordering_optional, data_set);
 
 	custom_action_order(
 		rsc, stop_key(rsc), NULL, rsc, delete_key(rsc), NULL, 
 		pe_ordering_optional, data_set);
 
 	custom_action_order(
 		rsc, delete_key(rsc), NULL, rsc, start_key(rsc), NULL, 
 		pe_ordering_manditory, data_set);	
 }
 
 void native_rsc_colocation_lh(
 	resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
 {
 	if(rsc_lh == NULL) {
 		pe_err("rsc_lh was NULL for %s", constraint->id);
 		return;
 
 	} else if(constraint->rsc_rh == NULL) {
 		pe_err("rsc_rh was NULL for %s", constraint->id);
 		return;
 	}
 	
 	crm_debug_2("Processing colocation constraint between %s and %s",
 		    rsc_lh->id, rsc_rh->id);
 	
 	rsc_rh->cmds->rsc_colocation_rh(rsc_lh, rsc_rh, constraint);		
 }
 
 static gboolean
 filter_colocation_constraint(
 	resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
 {
 	if(constraint->score == 0){
 		return FALSE;
 	}
 
 	if(constraint->state_lh != NULL
 	   && text2role(constraint->state_lh) != rsc_lh->next_role) {
 		crm_debug_4("RH: Skipping constraint: \"%s\" state filter",
 			    constraint->state_rh);
 		return FALSE;
 	}
 	
 	if(constraint->state_rh != NULL
 	   && text2role(constraint->state_rh) != rsc_rh->next_role) {
 		crm_debug_4("RH: Skipping constraint: \"%s\" state filter",
 			    constraint->state_rh);
 		return FALSE;
 	}
 	return TRUE;
 }
 
 static void
 native_update_node_weight(
 	resource_t *rsc, const char *id, node_t *node, int score)
 {
 	node_t *node_rh = NULL;
 	CRM_CHECK(node != NULL, return);
 	
 	node_rh = pe_find_node_id(
 		rsc->allowed_nodes, node->details->id);
 
 	if(node_rh == NULL) {
 		pe_err("Node not found - adding %s to %s",
 		       node->details->id, rsc->id);
 		node_rh = node_copy(node);
 		rsc->allowed_nodes = g_list_append(
 			rsc->allowed_nodes, node_rh);
 
 		node_rh = pe_find_node_id(
 			rsc->allowed_nodes, node->details->id);
 
 		CRM_CHECK(node_rh != NULL, return);
 		return;
 	}
 
 	CRM_CHECK(node_rh != NULL, return);
 	
 	if(node_rh == NULL) {
 		pe_err("Node not found - cant update");
 		return;
 	}
 
 	if(node_rh->weight >= INFINITY && score <= -INFINITY) {
 		pe_err("Constraint \"%s\" mixes +/- INFINITY (%s)",
 		       id, rsc->id);
 		
 	} else if(node_rh->details->shutdown == TRUE
 		  || node_rh->details->online == FALSE
 		  || node_rh->details->unclean == TRUE) {
 
 	} else if(node_rh->weight <= -INFINITY && score >= INFINITY) {
 		pe_err("Constraint \"%s\" mixes +/- INFINITY (%s)",
 			 id, rsc->id);
 	}
 
 	if(node_rh->fixed) {
 		/* warning */
 		crm_debug_2("Constraint %s is irrelevant as the"
 			 " weight of node %s is fixed as %d (%s).",
 			 id, node_rh->details->uname,
 			 node_rh->weight, rsc->id);
 		return;
 	}	
 	
 	crm_debug_3("Constraint %s, node %s, rsc %s: %d + %d",
 		   id, node_rh->details->uname, rsc->id,
 		   node_rh->weight, score);
 	node_rh->weight = merge_weights(node_rh->weight, score);
 	if(node_rh->weight <= -INFINITY) {
 		crm_debug_3("Constraint %s (-INFINITY): node %s weight %d (%s).",
 			    id, node_rh->details->uname,
 			    node_rh->weight, rsc->id);
 		
 	} else if(node_rh->weight >= INFINITY) {
 		crm_debug_3("Constraint %s (+INFINITY): node %s weight %d (%s).",
 			    id, node_rh->details->uname,
 			    node_rh->weight, rsc->id);
 
 	} else {
 		crm_debug_3("Constraint %s (%d): node %s weight %d (%s).",
 			    id, score, node_rh->details->uname,
 			    node_rh->weight, rsc->id);
 	}
 
 	if(node_rh->weight < 0) {
 		node_rh->fixed = TRUE;
 	}
 
 	crm_action_debug_3(print_node("Updated", node_rh, FALSE));
 
 	return;
 }
 
 void native_rsc_colocation_rh(
 	resource_t *rsc_lh, resource_t *rsc_rh, rsc_colocation_t *constraint)
 {
 	crm_debug_2("%sColocating %s with %s (%s, weight=%d)",
 		    constraint->score >= 0?"":"Anti-",
 		    rsc_lh->id, rsc_rh->id, constraint->id, constraint->score);
 	
 	if(filter_colocation_constraint(rsc_lh, rsc_rh, constraint) == FALSE) {
 		return;
 	}
 	
 	if(rsc_lh->provisional && rsc_rh->provisional) {
 #if 0
 		/* should we do this? */
 		crm_debug("combine priorities of %s and %s",
 			  rsc_lh->id, rsc_rh->id);
 		node_list_update(rsc_lh->allowed_nodes, rsc_rh->allowed_nodes);
 #endif
 		return;
 
 	} else if( (!rsc_lh->provisional) && (!rsc_rh->provisional) ) {
 		/* error check */
 		if(constraint->score != INFINITY) {
 			return;
 			
 		} else if(rsc_lh->allocated_to == rsc_rh->allocated_to) {
 			return;
 
 		} else if(rsc_lh->allocated_to && rsc_rh->allocated_to
 		   && rsc_lh->allocated_to->details
 			  == rsc_rh->allocated_to->details) {
 			return;
 		}
 		
 		crm_err("%s and %s are both allocated"
 			" but to different nodes: %s vs. %s",
 			rsc_lh->id, rsc_rh->id,
 			rsc_lh->allocated_to?rsc_lh->allocated_to->details->uname:"n/a",
 			rsc_rh->allocated_to?rsc_rh->allocated_to->details->uname:"n/a");
 		return;
 		
 	} else if(rsc_lh->provisional == FALSE && rsc_lh->allocated_to) {
 		crm_debug_3("update _them_    : postproc color version");
 		native_update_node_weight(
 			rsc_rh, constraint->id, rsc_lh->allocated_to,
 			constraint->score);
 		
 	} else if(rsc_rh->provisional == FALSE && rsc_rh->allocated_to) {
 		crm_debug_3("update _us_  : postproc color alt version ");
 		native_update_node_weight(
 			rsc_lh, constraint->id, rsc_rh->allocated_to,
 			constraint->score);
 	}
 }
 
 void
 node_list_update(GListPtr list1, GListPtr list2)
 {
 	node_t *other_node = NULL;
 
 	slist_iter(
 		node, node_t, list1, lpc,
 
 		if(node == NULL) {
 			continue;
 		}
 
 		other_node = (node_t*)pe_find_node_id(
 			list2, node->details->id);
 
 		if(other_node != NULL) {
 			crm_debug_4("%s + %s: %d + %d",
 				    node->details->uname, 
 				    other_node->details->uname, 
 				    node->weight, other_node->weight);
 			node->weight = merge_weights(
 				other_node->weight, node->weight);
 		}
 		);	
 }
 
 void native_rsc_order_lh(resource_t *lh_rsc, order_constraint_t *order)
 {
 	GListPtr lh_actions = NULL;
 	action_t *lh_action = order->lh_action;
 
 	crm_debug_3("Processing LH of ordering constraint %d", order->id);
 
 	if(lh_action != NULL) {
 		lh_actions = g_list_append(NULL, lh_action);
 
 	} else if(lh_action == NULL && lh_rsc != NULL) {
 		lh_actions = find_actions(
 			lh_rsc->actions, order->lh_action_task, NULL);
 
 		if(lh_actions == NULL) {
 			crm_debug_4("No LH-Side (%s/%s) found for constraint",
 				  lh_rsc->id, order->lh_action_task);
 
 			if(lh_rsc->next_role == RSC_ROLE_STOPPED) {
 				resource_t *rh_rsc = order->rh_rsc;
 				if(order->rh_action && order->type == pe_ordering_restart) {
 					crm_debug_3("No LH(%s/%s) found for RH(%s)...",
 						    lh_rsc->id, order->lh_action_task,
 						    order->rh_action->uuid);
 					order->rh_action->runnable = FALSE;
 					return;
 				
 				} else if(rh_rsc != NULL) {
 					crm_debug_3("No LH(%s/%s) found for RH(%s/%s)...",
 						    lh_rsc->id, order->lh_action_task,
 						    rh_rsc->id, order->rh_action_task);
 					rh_rsc->cmds->rsc_order_rh(NULL, rh_rsc, order);
 					return;
 				}
 			}
 			
 			return;
 		}
 
 	} else {
 		pe_warn("No LH-Side (%s) specified for constraint",
 			 order->lh_action_task);
 		if(order->rh_rsc != NULL) {
 			crm_debug_4("RH-Side was: (%s/%s)",
 				  order->rh_rsc->id,
 				  order->rh_action_task);
 				  
 		} else if(order->rh_action != NULL
 			  && order->rh_action->rsc != NULL) {
 			crm_debug_4("RH-Side was: (%s/%s)",
 				  order->rh_action->rsc->id,
 				  order->rh_action_task);
 				  
 		} else if(order->rh_action != NULL) {
 			crm_debug_4("RH-Side was: %s",
 				  order->rh_action_task);
 		} else {
 			crm_debug_4("RH-Side was NULL");
 		}		
 		
 		return;
 	}
 
 	slist_iter(
 		lh_action_iter, action_t, lh_actions, lpc,
 
 		resource_t *rh_rsc = order->rh_rsc;
 		if(rh_rsc == NULL && order->rh_action) {
 			rh_rsc = order->rh_action->rsc;
 		}
 		
 		if(rh_rsc) {
 			rh_rsc->cmds->rsc_order_rh(
 				lh_action_iter, rh_rsc, order);
 
 		} else if(order->rh_action) {
 			order_actions(lh_action_iter, order->rh_action, order->type); 
 
 		}
 		);
 
 	pe_free_shallow_adv(lh_actions, FALSE);
 }
 
 void native_rsc_order_rh(
 	action_t *lh_action, resource_t *rsc, order_constraint_t *order)
 {
 	GListPtr rh_actions = NULL;
 	action_t *rh_action = order->rh_action;
 
 	crm_debug_3("Processing RH of ordering constraint %d", order->id);
 
 	if(rh_action != NULL) {
 		rh_actions = g_list_append(NULL, rh_action);
 
 	} else if(rh_action == NULL && rsc != NULL) {
 		rh_actions = find_actions(
 			rsc->actions, order->rh_action_task, NULL);
 		
 		if(rh_actions == NULL) {
 			crm_debug_4("No RH-Side (%s/%s) found for constraint..."
 				  " ignoring",
 				  rsc->id, order->rh_action_task);
 			crm_debug_4("LH-Side was: (%s/%s)",
 				  order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"<NULL>",
 				  order->lh_action_task);
 			return;
 		}
 			
 	}  else if(rh_action == NULL) {
 		crm_debug_4("No RH-Side (%s) specified for constraint..."
 			  " ignoring", order->rh_action_task);
 		crm_debug_4("LH-Side was: (%s/%s)",
 			  order->lh_rsc?order->lh_rsc->id:order->lh_action?order->lh_action->rsc->id:"<NULL>",
 			  order->lh_action_task);
 		return;
 	} 
 
 	slist_iter(
 		rh_action_iter, action_t, rh_actions, lpc,
 
 		if(lh_action) {
 		order_actions(lh_action, rh_action_iter, order->type); 
 
 		} else if(order->type == pe_ordering_restart) {
 			rh_action_iter->runnable = FALSE;
 		}
 		
 		);
 
 	pe_free_shallow_adv(rh_actions, FALSE);
 }
 
 void native_rsc_location(resource_t *rsc, rsc_to_node_t *constraint)
 {
 	GListPtr or_list;
 
 	crm_debug_2("Applying %s (%s) to %s", constraint->id,
 		    role2text(constraint->role_filter), rsc->id);
 
 	/* take "lifetime" into account */
 	if(constraint == NULL) {
 		pe_err("Constraint is NULL");
 		return;
 
 	} else if(rsc == NULL) {
 		pe_err("LHS of rsc_to_node (%s) is NULL", constraint->id);
 		return;
 
 	} else if(constraint->role_filter > 0
 		  && constraint->role_filter != rsc->next_role) {
 		crm_debug("Constraint (%s) is not active (role : %s)",
 			    constraint->id, role2text(constraint->role_filter));
 		return;
 		
 	} else if(is_active(constraint) == FALSE) {
 		crm_debug_2("Constraint (%s) is not active", constraint->id);
 		return;
 	}
     
 	if(constraint->node_list_rh == NULL) {
 		crm_debug_2("RHS of constraint %s is NULL", constraint->id);
 		return;
 	}
 	or_list = node_list_or(
 		rsc->allowed_nodes, constraint->node_list_rh, FALSE);
 		
 	pe_free_shallow(rsc->allowed_nodes);
 	rsc->allowed_nodes = or_list;
 	slist_iter(node, node_t, or_list, lpc,
 		   crm_debug_3("%s + %s : %d", rsc->id, node->details->uname, node->weight);
 		);
 }
 
 void native_expand(resource_t *rsc, pe_working_set_t *data_set)
 {
 	slist_iter(
 		action, action_t, rsc->actions, lpc,
 		crm_debug_4("processing action %d for rsc=%s",
 			  action->id, rsc->id);
 		graph_element_from_action(action, data_set);
 		);
 }
 
 
 
 void
 native_agent_constraints(resource_t *rsc)
 {
 }
 
 
 
 
 
 /*
  * Remove any nodes with a -ve weight
  */
 void
 filter_nodes(resource_t *rsc)
 {
 	print_resource(LOG_DEBUG_3, "Filtering nodes for: ", rsc, FALSE);
 	slist_iter(
 		node, node_t, rsc->allowed_nodes, lpc,
 		if(node == NULL) {
 			pe_err("Invalid NULL node");
 			
 		} else if(node->weight < 0.0
 			  || node->details->shutdown
 			  || node->details->online == FALSE
 			  || node->details->type == node_ping) {
 			crm_action_debug_3(print_node("Removing", node, FALSE));
 			rsc->allowed_nodes =
 				g_list_remove(rsc->allowed_nodes, node);
 			crm_free(node);
 			lpc = -1; /* restart the loop */
 		}
 		);
 }
 
 void
 create_notifications(resource_t *rsc, pe_working_set_t *data_set)
 {
 	if(rsc->notify == FALSE) {
 		return;
 	}
 	
 /* 	slist_iter( */
 /* 		action, action_t, rsc->actions, lpc, */
 		
 /* 		); */
 
 }
 
 static void
 register_activity(resource_t *rsc, enum action_tasks task, node_t *node, notify_data_t *n_data)
 {
 	notify_entry_t *entry = NULL;
 	crm_malloc0(entry, sizeof(notify_entry_t));
 	entry->rsc = rsc;
 	entry->node = node;
 	switch(task) {
 		case start_rsc:
 			n_data->start = g_list_append(n_data->start, entry);
 			break;
 		case stop_rsc:
 			n_data->stop = g_list_append(n_data->stop, entry);
 			break;
 		case action_promote:
 			n_data->promote = g_list_append(n_data->promote, entry);
 			break;
 		case action_demote:
 			n_data->demote = g_list_append(n_data->demote, entry);
 			break;
 		default:
 			crm_err("Unsupported notify action: %s", task2text(task));
 			break;
 	}
 	
 }
 
 
 static void
 register_state(resource_t *rsc, node_t *on_node, notify_data_t *n_data)
 {
 	notify_entry_t *entry = NULL;
 	crm_malloc0(entry, sizeof(notify_entry_t));
 	entry->rsc = rsc;
 	entry->node = on_node;
 
 	crm_debug_2("%s state: %s", rsc->id, role2text(rsc->next_role));
 
 	switch(rsc->next_role) {
 		case RSC_ROLE_STOPPED:
 /* 			n_data->inactive = g_list_append(n_data->inactive, entry); */
 			crm_free(entry);
 			break;
 		case RSC_ROLE_STARTED:
 			n_data->active = g_list_append(n_data->active, entry);
 			break;
 		case RSC_ROLE_SLAVE:
  			n_data->slave = g_list_append(n_data->slave, entry); 
 			break;
 		case RSC_ROLE_MASTER:
 			n_data->master = g_list_append(n_data->master, entry);
 			break;
 		default:
 			crm_err("Unsupported notify role");
 			break;
 	}
 }
 
 void
 native_create_notify_element(resource_t *rsc, action_t *op,
 			     notify_data_t *n_data, pe_working_set_t *data_set)
 {
 	node_t *next_node = NULL;
 	gboolean registered = FALSE;
 	char *op_key = NULL;
 	GListPtr possible_matches = NULL;
 	enum action_tasks task = text2task(op->task);
 	
 	if(op->pre_notify == NULL || op->post_notify == NULL) {
 		/* no notifications required */
 		crm_debug_4("No notificaitons required for %s", op->task);
 		return;
 	}
 	next_node = rsc->allocated_to;
 	op_key = generate_op_key(rsc->id, op->task, 0);
 	possible_matches = find_actions(rsc->actions, op_key, NULL);
 	
 	crm_debug_2("Creating notificaitons for: %s (%s->%s)",
 		    op->uuid, role2text(rsc->role), role2text(rsc->next_role));
 
 	if(rsc->role == rsc->next_role) {
 		register_state(rsc, next_node, n_data);
 	}
 	
 	slist_iter(
 		local_op, action_t, possible_matches, lpc,
 
 		local_op->notify_keys = n_data->keys;
 		if(local_op->optional == FALSE) {
 			registered = TRUE;
 			register_activity(rsc, task, local_op->node, n_data);
 		}		
 		);
 
 	/* stop / demote */
 	if(rsc->role != RSC_ROLE_STOPPED) {
 		if(task == stop_rsc || task == action_demote) {
 			slist_iter(
 				current_node, node_t, rsc->running_on, lpc,
 				pe_pre_notify(rsc, current_node, op, n_data, data_set);
 				if(task == action_demote || registered == FALSE) {
 					pe_post_notify(rsc, current_node, op, n_data, data_set);
 				}
 				);
 		}
 	}
 	
 	/* start / promote */
 	if(rsc->next_role != RSC_ROLE_STOPPED) {	
 		CRM_CHECK(next_node != NULL,;);
 
 		if(next_node == NULL) {
 			pe_proc_err("next role: %s", role2text(rsc->next_role));
 			
 		} else if(task == start_rsc || task == action_promote) {
 			if(task != start_rsc || registered == FALSE) {
 				pe_pre_notify(rsc, next_node, op, n_data, data_set);
 			}
 			pe_post_notify(rsc, next_node, op, n_data, data_set);
 		}
 	}
 	
 	crm_free(op_key);
 	pe_free_shallow_adv(possible_matches, FALSE);
 }
 
 
 static void dup_attr(gpointer key, gpointer value, gpointer user_data)
 {
 	char *meta_key = crm_concat(CRM_META, key, '_');
 	g_hash_table_replace(user_data, meta_key, crm_strdup(value));
 }
 
 static action_t *
 pe_notify(resource_t *rsc, node_t *node, action_t *op, action_t *confirm,
 	  notify_data_t *n_data, pe_working_set_t *data_set)
 {
 	char *key = NULL;
 	action_t *trigger = NULL;
 	const char *value = NULL;
 	const char *task = NULL;
 	
 	if(op == NULL || confirm == NULL) {
 		crm_debug_2("Op=%p confirm=%p", op, confirm);
 		return NULL;
 	}
 
 	CRM_CHECK(node != NULL, return NULL);
 
 	if(node->details->online == FALSE) {
 		crm_info("Skipping notification for %s", rsc->id);
 		return NULL;
 	}
 	
 	value = g_hash_table_lookup(op->meta, "notify_type");
 	task = g_hash_table_lookup(op->meta, "notify_operation");
 
 	crm_debug_2("Creating actions for %s: %s (%s-%s)",
 		    op->uuid, rsc->id, value, task);
 	
 	key = generate_notify_key(rsc->id, value, task);
 	trigger = custom_action(rsc, key, op->task, node,
 				op->optional, TRUE, data_set);
 	g_hash_table_foreach(op->meta, dup_attr, trigger->extra);
 	trigger->notify_keys = n_data->keys;
 
 	/* pseudo_notify before notify */
 	crm_debug_3("Ordering %s before %s (%d->%d)",
 		op->uuid, trigger->uuid, trigger->id, op->id);
 
 	order_actions(op, trigger, pe_ordering_manditory);
 	
 	value = g_hash_table_lookup(op->meta, "notify_confirm");
 	if(crm_is_true(value)) {
 		/* notify before pseudo_notified */
 		crm_debug_3("Ordering %s before %s (%d->%d)",
 			    trigger->uuid, confirm->uuid,
 			    confirm->id, trigger->id);
 
 		order_actions(trigger, confirm, pe_ordering_manditory);
 	}	
 	return trigger;
 }
 
 void
 pe_pre_notify(resource_t *rsc, node_t *node, action_t *op,
 	      notify_data_t *n_data, pe_working_set_t *data_set)
 {
 	crm_debug_2("%s: %s", rsc->id, op->uuid);
 	pe_notify(rsc, node, op->pre_notify, op->pre_notified,
 		  n_data, data_set);
 }
 
 void
 pe_post_notify(resource_t *rsc, node_t *node, action_t *op, 
 	       notify_data_t *n_data, pe_working_set_t *data_set)
 {
 	action_t *notify = NULL;
 
 	CRM_CHECK(op != NULL, return);
 	CRM_CHECK(rsc != NULL, return);
 	
 	crm_debug_2("%s: %s", rsc->id, op->uuid);
 	notify = pe_notify(rsc, node, op->post_notify, op->post_notified,
 			   n_data, data_set);
 
 	if(notify != NULL) {
 		notify->priority = INFINITY;
 	}
 	
 	notify = op->post_notified;
 	if(notify != NULL) {
 		notify->priority = INFINITY;
 		slist_iter(
 			mon, action_t, rsc->actions, lpc,
 
 			const char *interval = g_hash_table_lookup(mon->meta, "interval");
 			if(interval == NULL || safe_str_eq(interval, "0")) {
 				crm_debug_3("Skipping %s: interval", mon->uuid); 
 				continue;
 			} else if(safe_str_eq(mon->task, "cancel")) {
 				crm_debug_3("Skipping %s: cancel", mon->uuid); 
 				continue;
 			}
 
 			order_actions(notify, mon, pe_ordering_optional);
 			);
 	}
 }
 
 
 void
 NoRoleChange(resource_t *rsc, node_t *current, node_t *next,
 	     pe_working_set_t *data_set)
 {
 	action_t *start = NULL;
 	action_t *stop = NULL;
 	GListPtr possible_matches = NULL;
 
 	crm_debug("Executing: %s (role=%s)",rsc->id, role2text(rsc->next_role));
 
 	if(current == NULL || next == NULL) {
 		return;
 	}
 
 	/* use StartRsc/StopRsc */
 	
 	if(safe_str_neq(current->details->id, next->details->id)) {
 		crm_notice("Move  resource %s\t(%s -> %s)", rsc->id,
 			   current->details->uname, next->details->uname);
 
 		stop = stop_action(rsc, current, FALSE);
 		start = start_action(rsc, next, FALSE);
 
 		possible_matches = find_recurring_actions(rsc->actions, next);
 		slist_iter(match, action_t, possible_matches, lpc,
 			   if(match->optional == FALSE) {
 				   crm_err("Found bad recurring action: %s",
 					   match->uuid);
 				   match->optional = TRUE;
 			   }
 			);
 			
 		if(data_set->remove_after_stop) {
 			DeleteRsc(rsc, current, data_set);
 		}
 		
 	} else {
 		if(rsc->failed) {
 			crm_notice("Recover resource %s\t(%s)",
 				   rsc->id, next->details->uname);
 			stop = stop_action(rsc, current, FALSE);
 			start = start_action(rsc, next, FALSE);
 /* 			/\* make the restart required *\/ */
 /* 			order_stop_start(rsc, rsc, pe_ordering_manditory); */
 			
 		} else if(rsc->start_pending) {
 			start = start_action(rsc, next, TRUE);
 			if(start->runnable) {
 				/* wait for StartRsc() to be called */
 				rsc->role = RSC_ROLE_STOPPED;
 			} else {
 				/* wait for StopRsc() to be called */
 				rsc->next_role = RSC_ROLE_STOPPED;
 			}
 			
 		} else {
 			stop = stop_action(rsc, current, TRUE);
 			start = start_action(rsc, next, TRUE);
 			stop->optional = start->optional;
 			
 			if(start->runnable == FALSE) {
 				rsc->next_role = RSC_ROLE_STOPPED;
 
 			} else if(start->optional) {
 				crm_notice("Leave resource %s\t(%s)",
 					   rsc->id, next->details->uname);
 
 			} else {
 				crm_notice("Restart resource %s\t(%s)",
 					   rsc->id, next->details->uname);
 			}
 		}
 	}
 }
 
 
 gboolean
 StopRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
 {
 	action_t *stop = NULL;
 	
 	crm_debug_2("Executing: %s", rsc->id);
 	
 	slist_iter(
 		current, node_t, rsc->running_on, lpc,
 		crm_notice("  %s\tStop %s", current->details->uname, rsc->id);
 		stop = stop_action(rsc, current, FALSE);
 
 		if(data_set->remove_after_stop) {
 			DeleteRsc(rsc, current, data_set);
 		}
 		);
 	
 	return TRUE;
 }
 
 
 gboolean
 StartRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
 {
 	action_t *start = NULL;
 	
 	crm_debug_2("Executing: %s", rsc->id);
 	start = start_action(rsc, next, TRUE);
 	if(start->runnable) {
 		crm_notice(" %s\tStart %s", next->details->uname, rsc->id);
 		start->optional = FALSE;
 	}		
 	return TRUE;
 }
 
 gboolean
 PromoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
 {
 	char *key = NULL;
 	gboolean runnable = TRUE;
 	GListPtr action_list = NULL;
 	crm_debug_2("Executing: %s", rsc->id);
 
 	CRM_CHECK(rsc->next_role == RSC_ROLE_MASTER, return FALSE);
 
 	key = start_key(rsc);
 	action_list = find_actions_exact(rsc->actions, key, next);
 	crm_free(key);
 
 	slist_iter(start, action_t, action_list, lpc,
 		   if(start->runnable == FALSE) {
 			   runnable = FALSE;
 		   }
 		);
 
 	if(runnable) {
 		promote_action(rsc, next, FALSE);
 		crm_notice("%s\tPromote %s", next->details->uname, rsc->id);
 		return TRUE;
 	} 
 
 	crm_debug("%s\tPromote %s (canceled)", next->details->uname, rsc->id);
 
 	key = promote_key(rsc);
 	action_list = find_actions_exact(rsc->actions, key, next);
 	crm_free(key);
 
 	slist_iter(promote, action_t, action_list, lpc,
 		   promote->runnable = FALSE;
 		);
 	
 	return TRUE;
 }
 
 gboolean
 DemoteRsc(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
 {
 	crm_debug_2("Executing: %s", rsc->id);
 
 /* 	CRM_CHECK(rsc->next_role == RSC_ROLE_SLAVE, return FALSE); */
 	slist_iter(
 		current, node_t, rsc->running_on, lpc,
 		crm_notice("%s\tDeomote %s", current->details->uname, rsc->id);
 		demote_action(rsc, current, FALSE);
 		);
 	return TRUE;
 }
 
 gboolean
 RoleError(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
 {
 	crm_debug("Executing: %s", rsc->id);
 	CRM_CHECK(FALSE, return FALSE);
 	return FALSE;
 }
 
 gboolean
 NullOp(resource_t *rsc, node_t *next, pe_working_set_t *data_set)
 {
 	crm_debug("Executing: %s", rsc->id);
 	return FALSE;
 }
 
 
 gboolean
 native_create_probe(resource_t *rsc, node_t *node, action_t *complete,
 		    gboolean force, pe_working_set_t *data_set) 
 {
 	char *key = NULL;
 	char *target_rc = NULL;
 	action_t *probe = NULL;
 	node_t *running = NULL;
 
 	CRM_CHECK(node != NULL, return FALSE);
 
 	if(rsc->orphan) {
 		crm_debug_2("Skipping orphan: %s", rsc->id);
 		return FALSE;
 	}
 	
 	running = pe_find_node_id(rsc->known_on, node->details->id);
 	if(force == FALSE && running != NULL) {
 		/* we already know the status of the resource on this node */
 		crm_debug_3("Skipping active: %s", rsc->id);
 		return FALSE;
 	}
 
 	key = generate_op_key(rsc->id, CRMD_ACTION_STATUS, 0);
 	probe = custom_action(rsc, key, CRMD_ACTION_STATUS, node,
 			      FALSE, TRUE, data_set);
 	probe->priority = INFINITY;
 
 	running = pe_find_node_id(rsc->running_on, node->details->id);
 	if(running == NULL) {
 		target_rc = crm_itoa(EXECRA_NOT_RUNNING);
 		add_hash_param(probe->meta, XML_ATTR_TE_TARGET_RC, target_rc);
 		crm_free(target_rc);
 	}
 	
 	crm_notice("%s: Created probe for %s", node->details->uname, rsc->id);
 	
 	custom_action_order(rsc, NULL, probe, rsc, NULL, complete,
 			    pe_ordering_manditory, data_set);
 
 	return TRUE;
 }
 
 static void
 native_start_constraints(
 	resource_t *rsc,  action_t *stonith_op, gboolean is_stonith,
 	pe_working_set_t *data_set)
 {
 	gboolean is_unprotected = FALSE;
 	gboolean run_unprotected = TRUE;
 
 	if(is_stonith) {
 		char *key = start_key(rsc);
 		crm_debug_2("Ordering %s action before stonith events", key);
 		custom_action_order(
 			rsc, key, NULL,
 			NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
 			pe_ordering_optional, data_set);
 
 	} else {
 		slist_iter(action, action_t, rsc->actions, lpc2,
 			   if(action->needs != rsc_req_stonith) {
 				   crm_debug_3("%s doesnt need to wait for stonith events", action->uuid);
 				   continue;
 			   }
 			   crm_debug_2("Ordering %s after stonith events", action->uuid);
 			   if(stonith_op != NULL) {
 				   custom_action_order(
 					   NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
 					   rsc, NULL, action,
 					   pe_ordering_manditory, data_set);
 				   
 			   } else if(run_unprotected == FALSE) {
 				   /* mark the start unrunnable */
 				   action->runnable = FALSE;
 				   
 			   } else {
 				   is_unprotected = TRUE;
 			   }   
 			);
 	}
 	
 	if(is_unprotected) {
 		pe_err("SHARED RESOURCE %s IS NOT PROTECTED:"
 		       " Stonith disabled", rsc->id);
 	}
 
 }
 
 static void
 native_stop_constraints(
 	resource_t *rsc,  action_t *stonith_op, gboolean is_stonith,
 	pe_working_set_t *data_set)
 {
 	char *key = NULL;
 	GListPtr action_list = NULL;
 	node_t *node = stonith_op->node;
 
 	key = stop_key(rsc);
 	action_list = find_actions(rsc->actions, key, node);
 	crm_free(key);
 
 	/* add the stonith OP as a stop pre-req and the mark the stop
 	 * as a pseudo op - since its now redundant
 	 */
 	
 	slist_iter(
 		action, action_t, action_list, lpc2,
 		if(node->details->online == FALSE || rsc->failed) {
 			resource_t *parent = NULL;
 			crm_warn("Stop of failed resource %s is"
 				 " implict after %s is fenced",
 				 rsc->id, node->details->uname);
 			/* the stop would never complete and is
 			 * now implied by the stonith operation
 			 */
 			action->pseudo = TRUE;
 			action->runnable = TRUE;
 			if(is_stonith) {
 				/* do nothing */
 				
 			} else {
 				custom_action_order(
 					NULL, crm_strdup(CRM_OP_FENCE),stonith_op,
 					rsc, start_key(rsc), NULL,
 					pe_ordering_manditory, data_set);
 			}
 			
 			/* find the top-most resource */
 			parent = rsc->parent;
 			while(parent != NULL && parent->parent != NULL) {
 				parent = parent->parent;
 			}
 			
 			if(parent) {
 				crm_info("Re-creating actions for %s",
 					 parent->id);
 				parent->cmds->create_actions(parent, data_set);
 			}
 			
 		} else if(is_stonith == FALSE) {
 			crm_info("Moving healthy resource %s"
 				 " off %s before fencing",
 				 rsc->id, node->details->uname);
 			
 			/* stop healthy resources before the
 			 * stonith op
 			 */
 			custom_action_order(
 				rsc, stop_key(rsc), NULL,
 				NULL,crm_strdup(CRM_OP_FENCE),stonith_op,
 				pe_ordering_manditory, data_set);
 		}
 		);
 	
 	key = demote_key(rsc);
 	action_list = find_actions(rsc->actions, key, node);
 	crm_free(key);
 	
 	slist_iter(
 		action, action_t, action_list, lpc2,
 		if(node->details->online == FALSE || rsc->failed) {
 			crm_info("Demote of failed resource %s is"
 				 " implict after %s is fenced",
 				 rsc->id, node->details->uname);
 			/* the stop would never complete and is
 			 * now implied by the stonith operation
 			 */
 			action->pseudo = TRUE;
 			action->runnable = TRUE;
 			if(is_stonith == FALSE) {
 				custom_action_order(
 					NULL, crm_strdup(CRM_OP_FENCE), stonith_op,
 					rsc, demote_key(rsc), NULL,
 					pe_ordering_manditory, data_set);
 			}
 		}
 		);	
 }
 
 void
 native_stonith_ordering(
 	resource_t *rsc,  action_t *stonith_op, pe_working_set_t *data_set)
 {
 	gboolean is_stonith = FALSE;
 	const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 
 	if(rsc->is_managed == FALSE) {
 		crm_debug_3("Skipping fencing constraints for unmanaged resource: %s", rsc->id);
 		return;
 	} 
 
 	if(stonith_op != NULL && safe_str_eq(class, "stonith")) {
 		is_stonith = TRUE;
 	}
 	
 	/* Start constraints */
 	native_start_constraints(rsc,  stonith_op, is_stonith, data_set);
  
 	/* Stop constraints */
 	native_stop_constraints(rsc,  stonith_op, is_stonith, data_set);
 }
 
diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c
index 424bb03e5e..caa9f2866c 100644
--- a/crm/pengine/utils.c
+++ b/crm/pengine/utils.c
@@ -1,300 +1,366 @@
 /* $Id: utils.c,v 1.147 2006/07/05 14:20:02 andrew Exp $ */
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <crm/msg_xml.h>
 #include <allocate.h>
 #include <utils.h>
 #include <lib/crm/pengine/utils.h>
 
 /* only for rsc_colocation constraints */
 rsc_colocation_t *
 invert_constraint(rsc_colocation_t *constraint) 
 {
 	rsc_colocation_t *inverted_con = NULL;
 
 	crm_debug_3("Inverting constraint");
 	if(constraint == NULL) {
 		pe_err("Cannot invert NULL constraint");
 		return NULL;
 	}
 
 	crm_malloc0(inverted_con, sizeof(rsc_colocation_t));
 
 	if(inverted_con == NULL) {
 		return NULL;
 	}
 	
 	inverted_con->id = constraint->id;
 	inverted_con->score = constraint->score;
 
 	/* swap the direction */
 	inverted_con->rsc_lh = constraint->rsc_rh;
 	inverted_con->rsc_rh = constraint->rsc_lh;
 	inverted_con->state_lh = constraint->state_rh;
 	inverted_con->state_rh = constraint->state_lh;
 
 	crm_action_debug_3(
 		print_rsc_colocation("Inverted constraint", inverted_con, FALSE));
 	
 	return inverted_con;
 }
 
 
 gint sort_cons_strength(gconstpointer a, gconstpointer b)
 {
 	const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a;
 	const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b;
 
 	if(a == NULL) { return 1; }
 	if(b == NULL) { return -1; }
   
 	if(rsc_constraint1->score > rsc_constraint2->score) {
 		return 1;
 	}
 	
 	if(rsc_constraint1->score < rsc_constraint2->score) {
 		return -1;
 	}
 	return 0;
 }
 
 void
 print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details)
 { 
 	if(cons == NULL) {
 		crm_debug_4("%s%s: <NULL>",
 		       pre_text==NULL?"":pre_text,
 		       pre_text==NULL?"":": ");
 		return;
 	}
 	crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:",
 		    pre_text==NULL?"":pre_text,
 		    pre_text==NULL?"":": ",
 		    "rsc_to_node",
 		    cons->id, cons,
 		    g_list_length(cons->node_list_rh));
 
 	if(details == FALSE) {
 		crm_debug_4("\t%s (node placement rule)",
 			  safe_val3(NULL, cons, rsc_lh, id));
 
 		slist_iter(
 			node, node_t, cons->node_list_rh, lpc,
 			print_node("\t\t-->", node, FALSE)
 			);
 	}
 }
 
 void
 print_rsc_colocation(const char *pre_text, rsc_colocation_t *cons, gboolean details)
 { 
 	if(cons == NULL) {
 		crm_debug_4("%s%s: <NULL>",
 		       pre_text==NULL?"":pre_text,
 		       pre_text==NULL?"":": ");
 		return;
 	}
 	crm_debug_4("%s%s%s Constraint %s (%p):",
 	       pre_text==NULL?"":pre_text,
 	       pre_text==NULL?"":": ",
 	       XML_CONS_TAG_RSC_DEPEND, cons->id, cons);
 
 	if(details == FALSE) {
 
 		crm_debug_4("\t%s --> %s, %d",
 			  safe_val3(NULL, cons, rsc_lh, id), 
 			  safe_val3(NULL, cons, rsc_rh, id), 
 			  cons->score);
 	}
 } 
 
 void
 pe_free_ordering(GListPtr constraints) 
 {
 	GListPtr iterator = constraints;
 	while(iterator != NULL) {
 		order_constraint_t *order = iterator->data;
 		iterator = iterator->next;
 
 		crm_free(order->lh_action_task);
 		crm_free(order->rh_action_task);
 		crm_free(order);
 	}
 	if(constraints != NULL) {
 		g_list_free(constraints);
 	}
 }
 
 
 void
 pe_free_rsc_to_node(GListPtr constraints)
 {
 	GListPtr iterator = constraints;
 	while(iterator != NULL) {
 		rsc_to_node_t *cons = iterator->data;
 		iterator = iterator->next;
 
 		pe_free_shallow(cons->node_list_rh);
 		crm_free(cons);
 	}
 	if(constraints != NULL) {
 		g_list_free(constraints);
 	}
 }
 
 
 rsc_to_node_t *
 rsc2node_new(const char *id, resource_t *rsc,
 	     int node_weight, node_t *foo_node, pe_working_set_t *data_set)
 {
 	rsc_to_node_t *new_con = NULL;
 
 	if(rsc == NULL || id == NULL) {
 		pe_err("Invalid constraint %s for rsc=%p", crm_str(id), rsc);
 		return NULL;
 	}
 
 	crm_malloc0(new_con, sizeof(rsc_to_node_t));
 	if(new_con != NULL) {
 		new_con->id           = id;
 		new_con->rsc_lh       = rsc;
 		new_con->node_list_rh = NULL;
 		new_con->role_filter = RSC_ROLE_UNKNOWN;
 		
 		if(foo_node != NULL) {
 			node_t *copy = node_copy(foo_node);
 			copy->weight = node_weight;
 			new_con->node_list_rh = g_list_append(NULL, copy);
 		} else {
 			CRM_CHECK(node_weight == 0, return NULL);
 		}
 		
 		data_set->placement_constraints = g_list_append(
 			data_set->placement_constraints, new_con);
 		rsc->rsc_location = g_list_append(
 			rsc->rsc_location, new_con);
 	}
 	
 	return new_con;
 }
 
 
 const char *
 ordering_type2text(enum pe_ordering type)
 {
 	const char *result = "<unknown>";
 	switch(type)
 	{
 		case pe_ordering_manditory:
 			result = "manditory";
 			break;
 		case pe_ordering_restart:
 			result = "restart";
 			break;
 		case pe_ordering_recover:
 			result = "recover";
 			break;
 		case pe_ordering_optional:
 			result = "optional";
 			break;
 		case pe_ordering_postnotify:
 			result = "post_notify";
 			break;
 	}
 	return result;
 }
 
 
 gboolean
 can_run_resources(const node_t *node)
 {
 	if(node->details->online == FALSE
 	   || node->details->shutdown
 	   || node->details->unclean
 	   || node->details->standby) {
 		crm_debug_2("%s: online=%d, unclean=%d, standby=%d",
 			    node->details->uname, node->details->online,
 			    node->details->unclean, node->details->standby);
 		return FALSE;
 	}
 	return TRUE;
 }
 
 /* return -1 if 'a' is more preferred
  * return  1 if 'b' is more preferred
  */
 gint sort_node_weight(gconstpointer a, gconstpointer b)
 {
 	const node_t *node1 = (const node_t*)a;
 	const node_t *node2 = (const node_t*)b;
 
 	int node1_weight = 0;
 	int node2_weight = 0;
 	
 	if(a == NULL) { return 1; }
 	if(b == NULL) { return -1; }
 
 	node1_weight = node1->weight;
 	node2_weight = node2->weight;
 	
 	if(can_run_resources(node1) == FALSE) {
 		node1_weight  = -INFINITY; 
 	}
 	if(can_run_resources(node2) == FALSE) {
 		node2_weight  = -INFINITY; 
 	}
 
 	if(node1_weight > node2_weight) {
 		crm_debug_3("%s (%d) > %s (%d) : weight",
 			    node1->details->uname, node1_weight,
 			    node2->details->uname, node2_weight);
 		return -1;
 	}
 	
 	if(node1_weight < node2_weight) {
 		crm_debug_3("%s (%d) < %s (%d) : weight",
 			    node1->details->uname, node1_weight,
 			    node2->details->uname, node2_weight);
 		return 1;
 	}
 
 	crm_debug_3("%s (%d) == %s (%d) : weight",
 		    node1->details->uname, node1_weight,
 		    node2->details->uname, node2_weight);
 	
 	/* now try to balance resources across the cluster */
 	if(node1->details->num_resources
 	   < node2->details->num_resources) {
 		crm_debug_3("%s (%d) < %s (%d) : resources",
 			    node1->details->uname, node1->details->num_resources,
 			    node2->details->uname, node2->details->num_resources);
 		return -1;
 		
 	} else if(node1->details->num_resources
 		  > node2->details->num_resources) {
 		crm_debug_3("%s (%d) > %s (%d) : resources",
 			    node1->details->uname, node1->details->num_resources,
 			    node2->details->uname, node2->details->num_resources);
 		return 1;
 	}
 	
 	crm_debug_4("%s = %s", node1->details->uname, node2->details->uname);
 	return 0;
 }
 
+
+gboolean
+native_assign_node(resource_t *rsc, GListPtr nodes, node_t *chosen)
+{
+	int multiple = 0;
+	CRM_ASSERT(rsc->variant == pe_native);
+	
+	if(chosen == NULL) {
+		crm_debug("Could not allocate a node for %s", rsc->id);
+		rsc->next_role = RSC_ROLE_STOPPED;
+		return FALSE;
+
+	} else if(chosen->details->unclean
+		  || chosen->details->standby
+		  || chosen->details->shutdown) {
+		crm_debug("All nodes for color %s are unavailable"
+			  ", unclean or shutting down", rsc->id);
+		rsc->next_role = RSC_ROLE_STOPPED;
+		return FALSE;
+		
+	} else if(chosen->weight < 0) {
+		crm_debug_2("Even highest ranked node for color %s, had weight %d",
+			  rsc->id, chosen->weight);
+		rsc->next_role = RSC_ROLE_STOPPED;
+		return FALSE;
+	}
+
+	if(rsc->next_role == RSC_ROLE_UNKNOWN) {
+		rsc->next_role = RSC_ROLE_STARTED;
+	}
+	
+	slist_iter(candidate, node_t, nodes, lpc, 
+		   crm_debug("Color %s, Node[%d] %s: %d", rsc->id, lpc,
+			       candidate->details->uname, candidate->weight);
+		   if(chosen->weight > 0
+		      && candidate->details->unclean == FALSE
+		      && candidate->weight == chosen->weight) {
+			   multiple++;
+		   } else {
+			   break;
+		   }
+		);
+
+	if(multiple > 1) {
+		int log_level = LOG_INFO;
+		char *score = score2char(chosen->weight);
+		if(chosen->weight >= INFINITY) {
+			log_level = LOG_WARNING;
+		}
+		
+		crm_log_maybe(log_level, "%d nodes with equal score (%s) for"
+			      " running the listed resources (chose %s):",
+			      multiple, score, chosen->details->uname);
+		crm_free(score);
+	}
+	
+	/* todo: update the old node for each resource to reflect its
+	 * new resource count
+	 */
+
+	crm_debug("Assigning %s to %s", chosen->details->uname, rsc->id);
+	rsc->allocated_to = node_copy(chosen);
+	chosen->details->num_resources++;
+	chosen->count++;
+	return TRUE;
+}
diff --git a/crm/pengine/utils.h b/crm/pengine/utils.h
index 639f288996..4916f11fd9 100644
--- a/crm/pengine/utils.h
+++ b/crm/pengine/utils.h
@@ -1,55 +1,56 @@
 /* $Id: utils.h,v 1.3 2006/07/05 14:20:02 andrew Exp $ */
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #ifndef PENGINE_AUTILS__H
 #define PENGINE_AUTILS__H
 
 /* Constraint helper functions */
 extern rsc_colocation_t *invert_constraint(rsc_colocation_t *constraint);
 
 extern rsc_to_node_t *copy_constraint(rsc_to_node_t *constraint);
 
 extern void print_rsc_to_node(
 	const char *pre_text, rsc_to_node_t *cons, gboolean details);
 
 extern void print_rsc_colocation(
 	const char *pre_text, rsc_colocation_t *cons, gboolean details);
 
 extern rsc_to_node_t *rsc2node_new(
 	const char *id, resource_t *rsc, int weight, node_t *node,
 	pe_working_set_t *data_set);
 
 extern void pe_free_rsc_to_node(GListPtr constraints);
 extern void pe_free_ordering(GListPtr constraints);
 
 extern const char *ordering_type2text(enum pe_ordering type);
 
 extern gboolean rsc_colocation_new(
 	const char *id, int score,
 	resource_t *rsc_lh, resource_t *rsc_rh,
 	const char *state_lh, const char *state_rh);
 
 extern rsc_to_node_t *generate_location_rule(
 	resource_t *rsc, crm_data_t *location_rule, pe_working_set_t *data_set);
 
 extern gint sort_cons_strength(gconstpointer a, gconstpointer b);
 extern gint sort_node_weight(gconstpointer a, gconstpointer b);
 
 extern gboolean can_run_resources(const node_t *node);
+extern gboolean native_assign_node(resource_t *rsc, GListPtr candidates, node_t *chosen);
 
 #endif
diff --git a/include/crm/pengine/status.h b/include/crm/pengine/status.h
index 2db302dafe..61ca86cab1 100644
--- a/include/crm/pengine/status.h
+++ b/include/crm/pengine/status.h
@@ -1,215 +1,216 @@
 /* $Id: status.h,v 1.3 2006/06/21 14:48:01 andrew Exp $ */
 /* 
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  * 
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #ifndef PENGINE_STATUS__H
 #define PENGINE_STATUS__H
 
 #include <glib.h>
 #include <crm/common/iso8601.h>
 #include <crm/pengine/common.h>
 
 typedef struct node_s node_t;
 typedef struct action_s action_t;
 typedef struct resource_s resource_t;
 typedef struct action_wrapper_s action_wrapper_t;
 
 typedef enum no_quorum_policy_e {
 	no_quorum_freeze,
 	no_quorum_stop,
 	no_quorum_ignore
 } no_quorum_policy_t;
 
 enum node_type {
 	node_ping,
 	node_member
 };
 
 enum pe_restart {
 	pe_restart_restart,
 	pe_restart_ignore
 };
 
 typedef struct pe_working_set_s 
 {
 		crm_data_t *input;
 		ha_time_t *now;
 
 		/* options extracted from the input */
 		char *transition_idle_timeout;
 		char *dc_uuid;
 		node_t *dc_node;
 		gboolean have_quorum;
 		gboolean stonith_enabled;
 		const char *stonith_action;
 		gboolean symmetric_cluster;
 		gboolean is_managed_default;
 
 		gboolean remove_after_stop;
 		gboolean stop_rsc_orphans;
 		gboolean stop_action_orphans;
 
 		int default_resource_stickiness;
 		int default_resource_fail_stickiness;
 		no_quorum_policy_t no_quorum_policy;
 
 		GHashTable *config_hash;
 		
 		GListPtr nodes;
 		GListPtr resources;
 		GListPtr placement_constraints;
 		GListPtr ordering_constraints;
 		
 		GListPtr actions;
 
 		/* stats */
 		int num_synapse;
 		int max_valid_nodes;
 		int order_id;
 		int action_id;
 
 		/* final output */
 		crm_data_t *graph;
 
 } pe_working_set_t;
 
 struct node_shared_s { 
 		const char *id; 
 		const char *uname; 
 		gboolean online;
 		gboolean standby;
 		gboolean unclean;
 		gboolean shutdown;
 		gboolean expected_up;
 		gboolean is_dc;
 		int	 num_resources;
 		GListPtr running_rsc;	/* resource_t* */
 		
 		GHashTable *attrs;	/* char* => char* */
 		enum node_type type;
 }; 
 
 struct node_s { 
 		int	weight; 
 		gboolean fixed;
+		int      count;
 		struct node_shared_s *details;
 };
 
 #include <crm/pengine/complex.h>
 
 struct resource_s { 
 		char *id; 
 		char *clone_name; 
 		char *long_name; 
 		crm_data_t *xml; 
 		crm_data_t *ops_xml; 
 
 		resource_t *parent;
 		void *variant_opaque;
 		enum pe_obj_types variant;
 		resource_object_functions_t *fns;
  		resource_alloc_functions_t  *cmds;
 
 		enum rsc_recovery_type recovery_type;
 		enum pe_restart        restart_type;
 
 		int	 priority; 
 		int	 stickiness; 
 		int	 fail_stickiness;
 		int	 effective_priority; 
 
 		gboolean notify;
 		gboolean is_managed;
 		gboolean starting;
 		gboolean stopping;
 		gboolean runnable;
 		gboolean provisional;
 		gboolean globally_unique;
 		gboolean is_allocating;
 		
 		gboolean failed;
 		gboolean start_pending;
 		
 		gboolean orphan;
 		
 		GListPtr rsc_cons;         /* rsc_colocation_t* */
 		GListPtr rsc_location;     /* rsc_to_node_t*    */
 		GListPtr actions;	   /* action_t*         */
 
 		node_t *allocated_to;
 		GListPtr running_on;       /* node_t*   */
 		GListPtr known_on;	   /* node_t* */
 		GListPtr allowed_nodes;    /* node_t*   */
 
 		enum rsc_role_e role;
 		enum rsc_role_e next_role;
 
 		GHashTable *meta;	   
 		GHashTable *parameters;	   
 };
 
 struct action_s 
 {
 		int         id;
 		int         priority;
 		resource_t *rsc;
 		void       *rsc_opaque;
 		node_t     *node;
 		const char *task;
 
 		char *uuid;
 		crm_data_t *op_entry;
 		
 		gboolean pseudo;
 		gboolean runnable;
 		gboolean optional;
 		gboolean failure_is_fatal;
 
 		enum rsc_start_requirement needs;
 		enum action_fail_response  on_fail;
 		enum rsc_role_e fail_role;
 		
 		gboolean dumped;
 		gboolean processed;
 
 		action_t *pre_notify;
 		action_t *pre_notified;
 		action_t *post_notify;
 		action_t *post_notified;
 		
 		int seen_count;
 
 		GHashTable *meta;
 		GHashTable *extra;
 		GHashTable *notify_keys;  /* do NOT free */
 		
 		GListPtr actions_before; /* action_warpper_t* */
 		GListPtr actions_after;  /* action_warpper_t* */
 };
 
 struct action_wrapper_s 
 {
 		enum pe_ordering type;
 		action_t *action;
 };
 
 gboolean cluster_status(pe_working_set_t *data_set);
 extern void set_working_set_defaults(pe_working_set_t *data_set);
 extern void cleanup_calculations(pe_working_set_t *data_set);
 extern resource_t *pe_find_resource(GListPtr rsc_list, const char *id_rh);
 
 #endif