private static LinkIO[] IOLinks(Item2D[] brains, Item2D[] io, SortedList<Tuple<int, int>, double> allBrainLinks, IOLinkupPriority ioLinkupPriority, double brainLinkResistanceMult)
            {
                // Look for brains that are really close together, treat those as single brains
                Set2D[] brainSets = Worker2D_Voronoi.IOLinks_PreMergeBrains(brains, allBrainLinks);

                #region Brain-IO Distances

                // Figure out the distances between io and brains
                var distancesIO = Enumerable.Range(0, io.Length).
                    Select(o => new
                    {
                        IOIndex = o,
                        BrainDistances = Enumerable.Range(0, brainSets.Length).
                            Select(p => Tuple.Create(p, (brainSets[p].Center - io[o].Position).Length)).        //Item1=BrainIndex, Item2=DistanceToBrain
                            OrderBy(p => p.Item2).      // first brain needs to be the shortest distance
                            ToArray()
                    });

                switch (ioLinkupPriority)
                {
                    case IOLinkupPriority.ShortestDistFirst:
                        distancesIO = distancesIO.OrderBy(o => o.BrainDistances.First().Item2);
                        break;

                    case IOLinkupPriority.LongestDistFirst:
                        distancesIO = distancesIO.OrderByDescending(o => o.BrainDistances.First().Item2);
                        break;

                    case IOLinkupPriority.RandomOrder:
                        //TODO: Come up with a less expensive way of doing this
                        //.Select(o => new { Orig=o, Key=Guid.NewGuid }).OrderBy(o => o.Key).Select(o => o.Orig)
                        Random rand = StaticRandom.GetRandomForThread();
                        distancesIO = distancesIO.
                            Select(o => new { Orig = o, Key = rand.Next(int.MaxValue) }).
                            OrderBy(o => o.Key).
                            Select(o => o.Orig);
                        break;

                    default:
                        throw new ApplicationException("Unknown IOLinkupPriority: " + ioLinkupPriority.ToString());
                }

                distancesIO = distancesIO.ToArray();

                #endregion

                // Brain-Brain Distances
                var distancesBrain = BrainBrainDistances(brainSets, brainLinkResistanceMult);

                // Link IO to brains
                BrainBurden[] links = Enumerable.Range(0, brainSets.Length).Select(o => new BrainBurden(o, brainSets, io)).ToArray();

                foreach (var distanceIO in distancesIO)
                {
                    int ioIndex = distanceIO.IOIndex;
                    int closestBrainIndex = distanceIO.BrainDistances[0].Item1;

                    AddIOLink(links, ioIndex, io[ioIndex].Size, closestBrainIndex, distancesBrain[closestBrainIndex]);
                }

                // Build the return
                List<LinkIO> retVal = new List<LinkIO>();
                foreach (BrainBurden brain in links)
                {
                    foreach (int ioIndex in brain.IOLinks)
                    {
                        retVal.Add(new LinkIO(brain.Brain, ioIndex, io));
                    }
                }

                return retVal.ToArray();
            }
            public static void GetLinks(out LinkBrain2D[] brainLinks, out LinkIO[] ioLinks, Item2D[] brains, Item2D[] io, IOLinkupPriority ioLinkupPriority = IOLinkupPriority.ShortestDistFirst, double brainLinkResistanceMult = 10)
            {
                if (brains == null || brains.Length == 0)
                {
                    brainLinks = null;
                    ioLinks = null;
                    return;
                }
                else if (brains.Length == 1)
                {
                    brainLinks = null;
                    ioLinks = Enumerable.Range(0, io.Length).Select(o => new LinkIO(0, o, brains, io)).ToArray();
                    return;
                }

                // Link brains:brains
                SortedList<Tuple<int, int>, double> allBrainLinks;
                Worker2D_Voronoi.BrainLinks(out allBrainLinks, out brainLinks, brains);

                // Link brains:io
                ioLinks = IOLinks(brains, io, allBrainLinks, ioLinkupPriority, brainLinkResistanceMult);
            }