public void EnumerateDevices(UnrealTargetConstraint Constraint, Func <ITargetDevice, bool> Predicate)
        {
            lock (LockObject)
            {
                List <ITargetDevice> Selection = new List <ITargetDevice>();

                // randomize the order of all devices that are of this platform
                var MatchingProvisionedDevices   = AvailableDevices.Where(D => Constraint.Check(D)).ToList();
                var MatchingUnprovisionedDevices = UnprovisionedDevices.Where(D => D.Platform == Constraint.Platform && Constraint.IsIdentity()).ToList();

                bool OutOfDevices      = false;
                bool ContinuePredicate = true;

                do
                {
                    // Go through all our provisioned devices to see if these fulfill the predicates
                    // requirements

                    ITargetDevice NextDevice = MatchingProvisionedDevices.FirstOrDefault();

                    while (NextDevice != null && ContinuePredicate)
                    {
                        Log.Verbose("Checking {0} against predicate", NextDevice.Name);
                        MatchingProvisionedDevices.Remove(NextDevice);
                        ContinuePredicate = Predicate(NextDevice);

                        NextDevice = MatchingProvisionedDevices.FirstOrDefault();
                    }

                    if (ContinuePredicate)
                    {
                        // add more devices if possible
                        OutOfDevices = MatchingUnprovisionedDevices.Count() == 0;

                        DeviceDefinition NextDeviceDef = MatchingUnprovisionedDevices.FirstOrDefault();

                        if (NextDeviceDef != null)
                        {
                            Log.Verbose("Provisioning device {0} for the pool", NextDeviceDef.Name);

                            // try to create a device. This can fail, but if so we'll just end up back here
                            // on the next iteration
                            ITargetDevice NewDevice = CreateAndRegisterDeviceFromDefinition(NextDeviceDef);

                            MatchingUnprovisionedDevices.Remove(NextDeviceDef);
                            UnprovisionedDevices.Remove(NextDeviceDef);

                            if (NewDevice != null)
                            {
                                MatchingProvisionedDevices.Add(NewDevice);
                                Log.Verbose("Added device {0} to pool", NewDevice.Name);
                            }
                            else
                            {
                                Log.Info("Failed to provision {0}", NextDeviceDef.Name);
                                // track this
                                if (FailedProvisions.Contains(NextDeviceDef) == false)
                                {
                                    FailedProvisions.Add(NextDeviceDef);
                                }
                            }
                        }
                        else
                        {
                            Log.Info("Pool ran out of devices of type {0}!", Constraint);
                            OutOfDevices = true;
                        }
                    }
                } while (OutOfDevices == false && ContinuePredicate);
            }
        }
 /// <summary>
 /// Returns the number of available devices of the provided type. This includes unprovisioned devices but not reserved ones
 /// Note: unprovisioned devices are currently only returned when device is not constrained
 /// </summary>
 public int GetTotalDeviceCount(UnrealTargetConstraint Constraint, Func <ITargetDevice, bool> Validate = null)
 {
     lock (LockObject)
     {
         return(AvailableDevices.Union(ReservedDevices).Where(D => Validate == null ? Constraint.Check(D) : Validate(D)).Count() +
                UnprovisionedDevices.Where(D => D.Platform == Constraint.Platform && Constraint.IsIdentity()).Count());
     }
 }