private bool ExactChangeOnly()
        {
            var availableProductPrices = DispenserChannels
                                         .Where(i => i.Inventory > 0)
                                         .Select(i => i.Price)
                                         .Distinct();

            var acceptedCoinValues = CoinTubes
                                     .Select(i => i.Spec.Value)
                                     .Distinct()
                                     .OrderBy(i => i);

            var smallestAcceptedCoinValue = acceptedCoinValues.Min();
            var largestAcceptedCoinValue  = acceptedCoinValues.Max();

            // There is a product that is being sold for a multiple of a
            // smaller denomination than the smallest accepted denomination
            if (availableProductPrices.Any(i => i % smallestAcceptedCoinValue > 0))
            {
                return(true);
            }

            foreach (var price in availableProductPrices)
            {
                foreach (var coinValue in acceptedCoinValues)
                {
                    if (price % coinValue > 0 && !CanDispenseCoins(price % coinValue))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        public CoinSpecification IdentifyCoin(double massGrams, double diameterMillimeters)
        {
            foreach (var coinSpec in CoinTubes.Select(i => i.Spec).Distinct())
            {
                if (coinSpec.MassGrams == massGrams && coinSpec.DiameterMillimeters == diameterMillimeters)
                {
                    return(coinSpec);
                }
            }

            return(null);
        }