Hello, my name is Cody Freitag. Today I'll be talking about SPARCs, which are succinct, parallelizable arguments of knowledge. To start off, I wanna talk about the notion of succinct arguments for NP, which have been studied for quite a while now. So these are protocols where there's a prover who is interacting with a verifier for some statements X and whether or not it's in the language L. And so because this is an NP statement, we provide the prover additionally with some witness helping it prove this fact. And what we require from succinct arguments is first that of completeness, which says if the statement X, which is given as input to the protocol, is in the language, then the verifier will accept. Second, the standard soundness notion says that if X is not in the language, then no cheating prover P star can convince V, at least with noticeable probability. And in this work, we'll actually consider a stronger notion, which is that of arguments of knowledge, which says in fact, if the prover can convince V, then it must know a witness. And you can formalize this using an extractor, but this won't be the focus of the talk today. So I won't get into that. Just know that this is the notion we're using and requiring in this work. But the most kind of important or interesting aspect of succinct arguments that I wanna talk about is that of efficiency. In particular, the verifier here is supposed to run in time, which is polylogarithmic and a time bound T, where you can think of as T is the time to verify just the original NP statement. So if the prover just sends the witness over, this is the time it would take the verifier to check it. But in this interactive succinct case, we require that the verifier runs in polylogarithmic in this time bound T. And additionally, the communication is also polylog in this time bound T. And together you can think these are very good. So polylog in T is essentially independent of T and usually is going to be much more efficient than just running the NP verification procedure itself. On the other hand, we usually require that the prover runs in time, which is polynomial in this time bound T, where this could be some arbitrary polynomial. And really, this arbitrary polynomial is a huge bottleneck in making succinct arguments actually useful and practical in everyday scenarios. So as a running example, I want to consider the task of delegation. So this is where some client computer needs to perform some expensive computational task. And instead of computing it itself, it's going to ask a server to compute it for it. So it says AWS, please compute this function M on input X. So AWS comes back with an output. However, being the cryptographers we are, we don't trust Amazon, we don't trust AWS. And this by itself requires us to do that. Instead, we trust in kind of mathematical proofs. And so this creates this idea that first AWS is going to compute the function and then prove that it's correct. And how it does this is it, for this proof it uses a succinct argument or the statements that this machine, however it's represented on input X, outputs some value Y. And this is why it's usually in this kind of, let's first compute the output Y and then prove this very clear, nice statement. But the problem is that if this overhead, as I said before, is some arbitrary polynomial, even T squared, this is essentially useless in practice. As a concrete example, if this computation took, say, two to the 40 steps, this will take about an hour to do on most computers. Whereas squaring this, doing two to the 80 steps, will take nearly 400 million years. So there's just, it's not worth it to trust in the math at that point if it just has such a huge overhead. So what do we know as far as proof efficiency goes? So in this, again, I wanna emphasize, I'm considering this general NP regime where there's just an arbitrary prover with some witness who's interacting possibly over many rounds with a verifier. And so in the setting, what we know for proof efficiency, well, first it seems that it's been solved at least from a theory point of view. And why is this? Well, we have solutions which are essentially T times some polylog team factor. And this is the overhead you can think of computing a proof in this delegation setting. And at a high level, these follow from efficient constructions of PCPs, which are essentially these long strings, which even in the efficient case have size T times polylog T, but the verifier can efficiently check these proofs. And then these can be compiled down into succinct arguments using a collision resistance and kind of general cryptographic techniques, which is kind of known as Pylian's argument which I'll refer to it as. But the problem is that even though this is really nice, beautiful line of work from the theory side of things, in practice this is not the most efficient. So these polylog T factors may be a factor of say a thousand or more in practice. So like, if you're taking an hour long computation and it takes a thousand hours to prove it, maybe it's not worth it. And even so, it seems like this approach is just inherently a problem because we've been studying these PCPs for over 30 years now. And it would be a huge open problem if we could get these PCPs to have overhead which is only linear as opposed to this T times polylog T overhead. So even if we could solve this problem, I claim it's not even enough for a lot of practical scenarios because even if we have a delegation scheme where the overhead is just a factor of two more, this might be too much. So a week long computation, proving it in an extra week, maybe just isn't worth it. And so one way around this problem, and again at least in this theory land is by parallelizing these PCPs. So if the argument is that you can't, it takes too long to compute them, let's try to do it as much as we can in parallel. And so this work by BCGT in 2013, they give these efficient size PCPs. So kind of the best we know size PCPs of size T times polylog T, where after computing the computation, you can compute the whole PCP and only polylog T depth. And when you translate this into an argument, this gives an argument where the parallel time or the depth is only T plus polylog T. So you can think this is essentially T whenever T is large. However, it requires roughly T processors. Again, if T is something like two to the 40 for an hour long computation, this number of processors just is not reasonable for any practical setting. So just to recap the landscape of a proof of efficiency that I've discussed. So on the X axis here, we have kind of the additive overhead. You can think the extra time it takes to computer proof. And on the Y axis, we have the number of processors required to do so. And so first we have these original kind of polynomial time PCPs from the work of BFLS in 91. And then these can be compiled into succinct arguments, either via Killian's protocol or analogously Macaulay's protocol, which gives a non-interactive succinct argument or CS proofs. And then as the kind of landscapes of PCP improve, so did the landscapes of proof of efficiency into succinct arguments. And this work in 2005 by Bencison and Sudan, they give quasi-linear overhead PCPs. And again, for both of these works, you can think they just require a single processor. And in these regimes, having slightly more doesn't give any benefits. And then this work of BCGT in 2013, they show how you can kind of trade off this time to compute the PCP using a linear number of processors. So this is what gives these succinct arguments with essentially no additive overhead. So a t-time computation can be proved in essentially t-time, but it requires roughly t processors. So what I wanna kind of look towards in this work and strive towards is kind of getting the best of both worlds. Can we get essentially t-time proofs? So no overhead using very few processors. And this is what I want to introduce with this notion of sparks, which recall our succinct, paralyzable arguments of knowledge. And so in this new paradigm, I wanna say that let's forget the old method of let's first compute the output and then prove this clean statement. Instead, try to focus on computing the proof in parallel to the computation itself. I wonder what I mean by this. I mean, we have the same interactive arguments regime from before, but the input will only have a statement, a function M with input X and a time bound T. And the point is that the prover should compute the output and the proof while maintaining the other succinct argument of knowledge properties where the prover's efficiency is this t plus polylog t parallel time. So for t-time computations, again, this is essentially t-time, but we allow the prover to use some polylog rhythmic number of processors. So this is what we require for a succinct paralyzable argument of knowledge or sparks. And what we show in this work, first is that assuming only collision resistant hash functions, there actually exists four round sparks. So very round efficient sparks that also preserve the time complexity of the underlying computation. And seconds, assuming a little more, so if we assume kind of quasi-linear succinct non-interactive arguments of knowledge, so snarks, then we actually construct non-interactive sparks. And underlying both of these results is a somewhat generic transformation from any quasi-linear succinct argument of knowledge. So this is a succinct argument of knowledge where the prover overhead is this t-times polylog t factor. And we take that and we transform it and get a spark. And this assumes only collision resistance. And how I want you to think of this is in our transformation, you can think we have some t-times polylog t overhead succinct arguments, which maybe means for an hour long computation it takes 1,000 hours to prove. And we're transforming this to say, instead we're gonna take this hour long computation and using say around 1,000 processors, prove it in exactly an hour, while also computing this. And so how we get the above theorems is in the first one, we're just plugging in Killian's argument with an efficient PCP into our construction, which gives a four round spark. So it preserves the round complexity of Killian's argument. And in the second case, we start with just any quasi-linear snark. And the resulting thing we achieve is a non-interactive spark. And the focus of this talk will be on this transformation going from this quasi-linear succinct arguments to sparks. But before I get into that, I wanna briefly talk about some of the applications of sparks. So first is kind of what I alluded to before of getting these really efficient delegation protocols, which we'll call time tight. So this is where the client gives a task to a server and the server for the proof can just use some say non-interactive spark to do this proof. And the high level idea is that sparks give a way to take any function and make it verifiable. And in particular, this is really interesting when you start considering maybe some specific functions of interest. For example, if you start with a verify, if you start with a sequential function, so this is a function that takes a long time to compute and can't be computed much quicker with a lot of parallelism. If you take a sequential function and you append a non-interactive spark, this immediately gives a VDF. And VDFs have been hugely influential in the last two years in blockchain applications. They can be used for kind of a distributed and decentralized randomness generation process, among other things. And I wanna emphasize that previously we only knew such generic constructions of VDFs, assuming iterated sequential functions. Think of like repeated hashing or repeated squaring in a group of unknown order. And what we show in this work is that actually we have a transformation that works for any starting function. So any sequential function essentially gives a VDF. And why this is interesting is if the sequential function satisfies some other hardness motion, for example, if it's memory hard, then our transformation preserves this hardness. So start with some memory hard function or memory hard sequential function, apply a non-interactive spark and we get a memory hard VDF. And these memory hard functions are, I don't wanna define it formally. In fact, there are many different ways to define this notion, but I wanna just keep it a high level. This says that the bottleneck in computing this function is actually the memory accesses needed to make. And such functions are actually known to exist, at least are secure in the random oracle model. This is under various definitions. And why these are important is they give a way to compute functions where kind of the best architecture, we know how to compute them is just standard computer architecture. So they give kind of an ASIC resistance property where there's no benefit in buying specialized hardware to compute these certain functions, which is a lot of interest in these blockchain applications. So I wanna continue in the rest of the talk to focus on this construction from quasi linear overhead to synced arguments to sparks. And I'm gonna make a few simplifying assumptions for this talk. The first is I'm only gonna consider the non-interactive regime. And the second is I'm only gonna consider sequential RAM computation. But in the full version of the paper, we show how to deal with both of these. So as a warmup, I wanna consider sparks, the synced parallelizable arguments of knowledge. Whenever we start with a computation, which has small space, and this is actually based on these original VDFs works that get these kind of VDFs with almost no overhead or tight VDFs. And so what we have here is kind of on the horizontal axis, I have kind of time plotted from zero to T. And we know that this machine, this function M on input X with witness W takes T steps to output some value Y. And what we wanna do is we wanna compute a proof in parallel to this computation that finishes in essentially time T. So the observation made in these works is well, what if we had a snark that for T time computation, so any T time computation only takes T extra time. So in total, it'll take two times T time. So in this setting, the conclusion is well, we can start off just by taking the first half of the computation, so the first T over two steps, and we can prove it and finish the proof by time T. So this is kind of in some sense, the most we can do given the tools we have. So this two times T snark, this is the most we can do with just a single processor. However, at time T over two, we can then recursively compute and prove more using this idea. So at time T over two, we then see, well, if we compute T over four steps, we can compute this and then prove it and finish by time T. And at time three, T over four, we can do T over eight more steps and prove by time T, and we keep continuing until we get down to some base case, where T over two to the M is like a constant. And at this point, we know the output Y, and by putting all these proofs together, we can prove the overall computation. So this results in kind of a logarithmic and T number of proofs. And when you consider this as a full argument, this gives a log T factor increase in the complexity of the prover verifier in communication, roughly because the prover has to generate these log T proofs and the verifiers to check all of them, as well as kind of make sure they all fit together properly. And if we started instead with a snark with some general overhead, say A times T instead of two times T, then the number of protocols we'll need here is just A times log T. And what's nice is that if we start with quasi linear overhead, this A value I talked about is just a polylog factor in T. So our resulting argument will still be succinct. So why doesn't this approach work? Well, as I said before, this only works for small space computations because our intermediate statements that we need to prove are of the form starting with some space, some configuration of the machine, running the machine for case steps results in some final space. And the problem here is that the statements actually grow with the space of the computation. So for a T time computation, the space might be even size T. And so the verifier will need to read these intermediate statements in order to verify the computation. And so there's no hope of getting the verifier to be polylog T, to have polylog T complexity when it has to read statements which may be of much larger size. So the first attempt to fix this is let's just hash down the space. So our intermediate statements, instead of including the space, will include kind of a hash or digest of the space. And what the prover needs to prove is that there exists some initial space and final space consistent with these digests, such that starting with the space running the machine results in this final space. And here you should think of this initial and final space is the witness that the prover needs to use in this sub-proof, in the sub-protocol. And the problem we have is that, essentially we've just taken the problem before and pushed it into the witness, but this will actually increase the complexity of the prover. So while this fixes the communication and verifier complexity in the resulting arguments, the prover will still be inefficient. So this is kind of what we need to solve now. How do we make the prover efficient in this kind of main idea? And what we'll use here is updatable hash functions. So if we use updatable hash functions, we can have the exact same statements, but the prover now will prove a different relation to convince the verifier of these statements. Specifically, it'll prove there exists some sequence of updates, such that the machine specifies these updates, these K updates for these K steps, and starting with this initial digest, applying the updates results in this final digest. So this is what I mean by an updatable hash function. And here, the key observation is that, now this witness that the prover needs to compute for each sub protocol scales only with the steps and not with the space of the computation. So there's some hope to kind of efficiently computing these and the question remains, can we compute these actually in parallel to the computation? And for this, the tool we use is kind of this new idea for Merkel trees of actually using pipeline to Merkel trees. So again, we have the same statements, the same proof, but we're gonna use Merkel trees to compute these digests and we're gonna, these Merkel trees provide these kind of local updates properties to get these updatable hash functions. And if we just pipeline these updates as they come by, and the idea is that we can just perform each level, each axes needed at each level in the Merkel tree at a time, then this will satisfy the efficiency property we need. In other words, we can compute these updates completely in parallel to the computation. So putting it all together, what does this look like? So we start with some initial digest, which you can just think of hashing the empty database or the empty space the prover might need to use. We run the protocol for, we run the computation for K1 steps, where I'll talk about what K1 is in a little bit. And in parallel to doing these steps, we can compute the updates. Here, we're just kind of throwing all of these updates at a Merkel tree and pipelining them as efficiently as possible. And this will give some overhead, but the key is that it's only an additive overhead, whereas naively, if you just did all of these updates sequentially, it would give a polylogarithmic overhead to compute all of these updates. But by pipelining them, we're really leveraging the fact that this only results in a small overhead over the original computation. Then, given kind of this witness we've computed, we can prove the statements that M on input X running for K1 steps goes from this initial digest to the next digest. And how we choose this number of steps K1 is just, we say, what's the largest number of steps we can compute and then prove and finish by time T. So as I said before, we can just recursively apply this idea. So now we have some other number of steps we compute, steps that we can compute and prove them by time T and we just keep recursively applying this idea. And so, as I said before, if we start with a snark with quasi linear overhead, the number of sub protocols we'll need here is only polylogarithmic and T. And we've guaranteed that everything finishes in parallel time, which is essentially T. So it only has an additive polylog T overhead. And the spark complexity we get is essentially M times that of the underlying snark and all the other parameters of interest pretty much. And because M is polylog, this preserves the succinctness and efficiency properties we need. And briefly, I wanna say for argument of knowledge, it's a little non-trivial in the fact that we have to actually compose the underlying extractors when proving argument of knowledge, but we show the full details of that in the paper. So to conclude, I wanna just recap what we've shown. So sparks, which are succincts, paralyzable arguments of knowledge, they allow computing and proving RAM computations where the parallel time is essentially T and we only incur kind of a polylogarithmic overhead and the number of processors we need to use. And we do this via this generic transformation from these succinct arguments with quasi-linear overhead to sparks assuming only collision resistance. And one reason these are so cool is they give a way to take any function, apply a non-interactive spark and you get a verifiable version of that function, which in particular can be used to construct the first candidate memory hard verifiable delay functions. And I wanna leave a final thought, which is saying that we kind of view this work as a theoretical feasibility result for now. There are a lot of interesting open problems on how do you take this, implement it in a way that preserves all these things. So working in the RAM model doesn't exactly translate to how computers actually work. But I think this leaves a bunch of exciting open questions of how do we kind of take this nice theoretical results and make it practical and hopefully get to that kind of ideal delegation sort of protocol that I mentioned earlier in the talk. So yeah, thank you for your time.


Thanks, Gail. One clarification of what Gail said related to ClinGen. I'm on the Actionability Committee and while we love to have clinical guidelines or gene reviews, that's not a requirement. We have, in fact, reviewed things that don't have those. They just get a lower evidence scoring. So this is on behalf of my co-chairs, Hawken, Hawken-Arson, and Josh Peterson, who are both here. The mission statement of the Outcomes Working Group is to develop cross-site outcomes to track implementation and impact of Emerge 3 sequencing, or focusing on answering the overarching question of whether returned Emerge 3-generated genomic results impact healthcare utilization and outcomes of importance to patients and families. Now, I want to take just a little bit of a time, since maybe not everybody is familiar with this sort of rubric that we're using. I should have put them in red since I said rubric, but we'll ignore that color challenge here. So the example I'm going to use is an MLH1-associated variant associated with Lynch syndrome. When we think about outcomes, we think about them in three different ways. There are process outcomes, and that is a potential change in healthcare utilization related to returning genetic information. So, for example, if we return to a pathogenic variant in MLH1, we might order a colonoscopy. That would be a process outcome. Was a colonoscopy ordered based on the recommendation from the outcome? Most everything that's done in medicine and quality focuses on process outcomes because they're easy to measure, or at least easier to measure. But as Einstein once said, not everything that counts can be counted, and not everything that can be counted counts. So this is an issue where this is quite a ways away from the proximate of clinical outcomes that we'll get to. Now, there are intermediate or surrogate outcomes, which would be a biomarker or something else indicating that benefit or harm is more likely. So, again, using a colorectal cancer example here, if a fecal occult blood test was performed and it was positive, that would be an intermediate outcome. They would indicate that there is, in fact, a higher probability that this individual may, in fact, have incident disease related to this variant. And then there would also be adherence to the recommendation, would be an intermediate outcome. So we ordered the colonoscopy, did the patient actually get it? And if they did get it, then that moves us closer towards the clinical outcomes, which is the actual measurement of benefits or harms to a patient who receives an intervention. So if the colonoscopy was ordered and if the colonoscopy was performed, if we saw that there were adenomatous polyps that were removed as a consequence, that is a clinical outcome. Because we know that these are pre-cancerous lesions, and as a consequence, this is a positive clinical outcome. Now, what I've just presented there is what we also call a chain of evidence, which is if we choose to use a process outcome or an intermediate outcome, how confident are we that measuring that outcome actually relates to the health outcome of interest? So for colonoscopy, an intermediate outcome and colorectal cancer, there's a very strong chain of evidence that indicates that performing the colonoscopy, removing polyps that are found, has a very dramatic impact on reducing the incident rate of colorectal cancer. We also have a very good chain of evidence that if an LDL cholesterol of under 100 milligrams per deciliter, which is an intermediate biomarker outcome, relates to the risk for coronary artery disease. There are some that have intermediate levels of evidence, such as prescribing a beta blocker, which is a process outcome, and sudden cardiac death in individuals that have one of the inherited arrhythmic disorders. But you can really only count this as an intermediate outcome if you measure adherence. So it's all well and good for me to order the beta blocker for the patient. It never fills the prescription. It doesn't take the prescription. Then we don't have evidence that this would improve the health outcome. And then there are ones that have very weak evidence, for instance, CEA 125, which would be an intermediate outcome, an ovarian cancer, or total body MR, again, an intermediate outcome, and leaf romani associated cancer mortality. So as we think about what outcomes we're going to choose to measure, we have to understand what type of an outcome is it and what is the evidence to support its relationship to a health outcome of interest, which is ultimately what patients and family members care about. So what we've been doing in anticipation of returning of results is to develop standardized outcome measurements that include process intermediate and health outcomes across all the different conditions that will be returned as part of eMERGE 3. There is a general intake form that all patients, participants who will be getting results, will be filled out by the site that is returning those results. And then we have a whole series of these. And you can see that these vary from very simple ones. So for ornithine transcarb amylase deficiency, for example, there's only six outcome measures that need to be captured. Whereas for aortopathy, there are 67 outcomes that need to be captured. So there's all of these are placed into a red cap database, so that's a standard space collection across all of the different sites. So we will in fact be able to collect the data, correlate the data, and analyze the data collectively. Challenges. As Gail pointed out, the return of results is occurring late in the process. So we are heavily reliant on process and intermediate outcomes because of the length of the project. This means that the evidence that we have in terms of association with outcomes is much lower. We have a one time point of assessment for outcomes. Again, pragmatically, we just had to say we have to measure outcomes. We don't have adequate time to measure them over time, which is what we prefer. So we will measure them once at six months post return of result. This wasn't picked randomly. There's some evidence that suggests that when you return a result, it takes a certain amount of time for the patient participant to process that result and act on it. So rather than measuring at a one month time frame or a three month time frame, we thought six months would be a bit more robust. So the timing of sequencing and report has been comment on. Another thing that is very difficult is how do you attribute that outcome to the return result? So in other words, you return that pathogenic variant in MLH1 and the patient has a colonoscopy. It would be great to say, oh, well, we returned the result, a colonoscopy was done great. That's a win. But if that patient had already been scheduled for a colonoscopy prior to the return of the result, then we really didn't improve that outcome. So what we're trying to do here is to get a little bit of increased confidence about whether or not the return result actually led to the outcome of interest. And we're relying on assertion by a site. In other words, as I look at it, and I say, yeah, I think that this was related to the return of results versus no, I don't think it was. It's not the most robust way to go about doing it. So if we think about opportunities for measuring health outcomes, if we follow the model that has been followed from emerges one through three, perhaps there is the potential to follow some of these participants into Emerge 4. But this is much less straightforward than the phenotyping algorithms and the GWAS efforts that have been followed across these three funding cycles. We could identify conditions or genomic results. This gets to the prioritization piece that was brought up earlier, where health outcomes are more likely to accrue within that four-year time frame. Or for which there's a very strong chain of evidence that a process outcome is related to a health outcome of interest. So things that I had kind of thought about were pharmacogenomics for common drugs. We actually did a little bit of that in Emerge 2. That's an area where, again, I think at least for some of the pharmacogenomic returns, you could see something within a four-year time frame. I think a huge issue is unrecognized genetic disorders. I think there's been a lot of criticism, and in my view, perhaps my personal bias as a clinical geneticist, that, well, you're only focusing on Mendelian disorders. You know, there's rare. Why don't you do something important like cure diabetes? Well, good luck with that. The reality is that Mendelian disorders are in aggregate common. In our data, it's 3.5 to 4% of the population. That's not an insignificant number. We can identify these people with high confidence, and we know what to do with them. So the impact is actually quite high, even though the number is relatively low. And what we've been seeing, and I think which we are also beginning to see in Emerge, is that there are people out there that have genetic disorders that have no clue that they have a genetic disorder. In looking at our data in CFTR variants, we find individuals that have two pathogenic variants in CFTR. They have diagnoses in their chart, like bronchiectasis or chronic obstructive pulmonary disease. They don't have cystic fibrosis as their diagnosis. There are metabolic disorders like ornithine transcarbamylase that can have adult onset, milder forms, but can lead to morbidity and mortality. And Dan will note that I added renal disease and dialysis patients. He emailed about that earlier today, so I figured I'd just throw that in there to throw him a bone. So just to know that somebody's paying attention, Dan. And FH is a huge opportunity. This is a major, this is a Tier 1 conditions defined by CDC for genetics. LDL cholesterol is a very good surrogate marker. We have very good treatments. This is, I think, very important. Thanks, Sharon. Just about done. Getting sequencing results faster to allow for longer follow-up has been mentioned, and then developing and testing methods to attribute outcomes. Challenges, outcome collection approaches are still site-specific. In contrast to phenotypes where we use the same approach and we have manual processes that are required. This is very inefficient. I referenced this earlier, so I won't go into great detail about it, but I think if we take an implementation science approach, we can learn from this. I referenced this R01, a dissemination of implementation of Lynch syndrome screening, not to be self-serving, but to note that this is the first genomic project that was funded through the NIH's dissemination implementation science program. And it, I think, there are lessons to be learned that could be applied into Emerge 4. Same thing here. Collaboration with the pragmatic trials in Ignite 2 around certain conditions. Now, we don't know what those trials are going to be yet, but we will know, and we should certainly look at how we can do that, because now we'll have two different ways to accumulate evidence. A pragmatic trial methodology and a more of an observational cohort methodology. And those two could be synergized, but we have to have standard outcome measures to be able to do that. And then the public health impact of Cascade testing makes this a point of emphasis to develop and test methods, and that could include a legal and policy emphasis to inform novel approaches of contacting at risk relatives, not using the typical approach of contact in the patient themselves. Economic outcomes have been referenced. Again, there is an NIH-funded, NHGRI-funded R01 from Vanderbilt University, Washington, and Geisinger that is looking to develop and test models to understand which outcomes would drive cost effectiveness. This model can identify which outcomes are most important to capture, and we can design Emerge 4 to prioritize those outcomes. And with that, I'll stop. Thank you. So, Eric Boerwinkel is going to give the response.


Another worker in a South China plant has been hospitalized with avian flu, raising official concerns tonight that a bird flu pandemic has begun. Good evening, I'm Todd Glickman. A new report from the Chinese government confirms that a second worker at the Jilin electronics plant in South China has been diagnosed with avian flu. This news comes less than 24 hours after the death of Hei Wang, the 22-year-old woman who also worked in the Jilin factory and was diagnosed with a lethal H5N1 strain of the virus. A second case of bird flu in the same Chinese factory is raising concerns that the virus is now spreading from human to human. While some experts warn that this could be the start of a global epidemic, government officials are calling for calm, emphasizing that there is still no evidence that the two cases are linked and certainly no proof of a pandemic. The China National Influenza Laboratory in Beijing says it is still waiting for blood test results for the second Jilin worker. Meanwhile, U.S. Human Services Secretary Joan Smith is asking the public to remain calm, saying, quote, we must wait for the outcome of these tests. And even if the two cases are connected, we are still a long way from a pandemic. So what if there is an outbreak of bird flu that can be transmitted from human to human? Experts have said that such an outbreak could trigger a pandemic capable of killing millions of people worldwide. For evidence, these experts point to history. The Spanish flu pandemic of 1918 caused an estimated 50 million fatalities, and the most recent global epidemic was in 1968, when the Hong Kong flu killed about a million people. Experts say we would face different challenges in 2006. Our disease detection systems and medications are much better today. However, there's been explosive growth in the number of people traveling internationally, making it much easier for a virus to spread around the globe. And now a new concern is emerging. Birds and people may not be the only carriers of the deadly virus. A new report claims that the avian flu may arrive in packages inside freight containers. The study published today by the Institute for the Study of Pandemic Control suggests that the H5N1 virus can survive for as long as 36 hours on plastic surfaces. This means, for example, that a new PC being shipped from Asia could be a carrier. The report is based on a two-year study of several viruses, including bird flu. However, many experts are disputing the claim. The Global Virus Laboratory in Brussels, Belgium has called the study inconclusive. They point to past research, which has shown that viruses cannot survive for long periods on inert surfaces. When we come back, a look at how local hospitals are gearing up for a possible pandemic. You're watching CTL News.


All righty, so let's finish up this grouping tool by actually performing the grouping action. We've got our UI all up and running, and we've got hotkey launching this particular editor here. So, Control Shift and G. We can enter a name, and we can fire off some code with this button right here. All right. So, before I actually get going, one thing I did want to show you guys that I haven't shown yet, is how to give your scripts a custom icon. So, what I want to do is create a new folder here, and I'm just going to call this icon. And you have to do this. If you want this particular icon to be assigned to these scripts, it's got to be within that editor folder, so just it goes with the tool when you go and make this into a package. All right. So, what I want to do is just import the IndiePixel icon here. So, let's go and let's go back to IndiePixel, actually desktop here, and I'll roll through all my stuff here. So, branding, logo. So, let's get the 32 pixel icon. So, now that I've got this inside of my project here, what I can do is I can literally just go click on the script and hit this little drop-down right here on the script icon, and hit the Other button and select the icon. And then I'm going to click off of that. It'll compile for a second or two, and then you'll notice that the C-sharp icon switches over to your custom icon. Really cool way to identify what type of script this is. So, you could do it by who created the script, so if that person has their own logo or something like that. You can also create custom icons based off of what type of script this is. Since these are editor tools, maybe you want an editor tool icon. It just helps you be able to identify what your script is a lot faster. Also makes it just really neat and clean and professional. So, all right, so with that, let's go and get the tool here actually grouping some stuff and firing up or assigning the game object that particular name. So, one thing I want to do is keep track of what or how many current selected objects we have. So, this is going to be an int. We'll call this current selection count. It's a long name for a tiny number. It could actually be a large number. So, one thing I want to do is up here. So, this current selection count is going to be inside of this code at the very top here. It's going to be equal to selection, not the election, selection.active and it's .gameObjects. There we go. So, this returns for us an array of the game objects, which is actually a good thing to do. So, let me actually finish this for you. So, you'll notice it returns an array of game objects. So, what we could do is we could say .length, all right, now we'll populate this. But I do want to be able to access that, the game object. So, what we're going to do is create a private array of game objects like so. We'll call this selected, okay. And what we can do then is assign everything from our selection.gameObjects method here, okay. And we don't want the length anymore. And then we'll just take the current selection count is equal to selected.length. All right, so let's go back and test this out now. It's under the editor. And we also need to be able to display that information as well. So, I lied. Let's go back up here. So, what we're going to do is we're going to say editor, editor, GUI layout.label field, all right. We're going to say selection count like so. And we'll add on the current selection count.toString like so. All right. And then I'm going to want a little bit of space between all this. So, let me show you another way to do spaces. So, we can do a GUI layout.space. The cool thing about this one is that we can actually provide it a pixel value. Whereas the editor GUI layout space, if I were to look at the arguments, has no arguments, no overrides either. So, I use this one to give something like five pixel space between all this stuff here. So, let's put one also between the button. Cool. And we'll make this one a little bit less. We'll say like two. Cool. All righty. So, now you can see that our selection count isn't changing. But we are selecting objects. And that is just because you'll notice now it updated. We're not repainting our tool. And so, what we need to do is constantly update this on GUI. So, at the very bottom here, what we do is just do a repaint like so. So, now this will actually be real time. All right.  You can see that now we're getting the real time selection. Cool. So, let me go and make two boxes here. Let's make a... Well, let's do two spheres then actually. All right. So, let me put in two spheres here. We'll just make one a little bit bigger. Okay. So, what I want to do is be able to select both these objects here. And I just want to give it a name. So, I want to give it like a sphere. And I'm going to automatically add the underscore group to the end of this. And when I hit this button, it'll actually parent to these spheres underneath an empty game object. Okay. So, let's go in and do that. So, to do that, I'm going to create another custom method over here. We're just going to do a void. And we'll say group selected objects. All right. Cool. And so, the first step into getting this to run is to call it from our button over here. Okay. So, we're going to say group selected objects. And the first thing we want to do in our method over here is check to see if selected.length is greater than zero. All right. Cool. We should probably initialize selected there. So, let's just do a new game object array with nothing in it like so. Cool. So, if we have more than, well, if we have anything selected really, we should go and create a new game object. So, this game object is going to be called group Geo. That's what I usually like to call it. And this is going to be equal to our new game object. And you'll notice that what we can do is we can provide a name to it right off the bat and a bunch of components that you might want to attach to it. We're just going to use this string name for right now. And our name is going to be whatever the user typed into this particular text field. So, this wanted name. All right. But we don't want to just leave it with enter name. So, what we need to do is we need to first do a check right after all this here. So, what I'm going to do is I'm going to say if the wanted name does not equal enter name like so. All right. So, if it doesn't equal that, that means it's something different, which means somebody typed something into it. Otherwise, if it does equal that, then we should do a little bit of an error dialog for the user just to tell them that they need to actually put something in there. So, we can do the editor utility dot display dialog like so. And this takes the title. So, we'll just say group grouper message or something like that. You can put in whatever you want. And we'll say, what's the message? So, the message is going to be you must provide a name for your group. And then for the button, we'll just say okay. Like so. Perfect. All right. So, let's just go make sure that that works. So, I'm going to close this down and relaunch it with my hotkey and hit group selected. And you'll notice that because I didn't change the name, it says you must provide a name for your group. Perfect. So, if I were to type in sphere and say group selected, we get a new game object up here. All right. And that's just because we haven't named it yet. So, we'll give it a name. So, over here, we're going to give it our wanted name plus underscore grp. All right, because I just don't like to have to type that in all the time. And sometimes I mistype it, then I have to go and fix it. And that's like 20 seconds of my time taken up when I have lots to do. So, that's how we write tools and we automate things for ourselves. Cool. So, now we have the name assigned to our group. All right. And then what we want to do is we want to take all of the selected objects and we want to parent them underneath our group. So, what we'll do is we'll just come over here and we'll do a for each. So, let's say for each transform, actually, it's going to be game object. So, for each game object, right? Because this stores a whole bunch of game objects. We'll call this Kerr-GO in selected, like so. All right. So, we're going to loop through each of the game objects that's stored in the selected array. And we're going to say that the Kerr-GO, whichever current child we're working on, or current object in the array here, dot transform, dot set parent. All right. So, the parent is going to be our group, GO dot transform. Okay. So, let's talk about that here really quick. So, this set parent method is attached to or part of the transform class. All right. And it takes a transform. So, we have to access the transform of the current group that we just created up here. And so, that basically assigns that to the group. So, let's go and test it out. So, for each game object that we currently have selected, it'll get parented to our new group, GO. Just like that. Okay. So, let's just select these two guys. And we'll hit group selected. And voila. There we go. We now have these objects grouped. Perfect. And that, my friends, is how we do that. All right. So, a good upgrade to this would be to add in a ungroup selected. All right. So, you can go in here and basically ungroup all these guys. But I'll let you guys, you know, work on that. Let me know if you guys have any questions. Thanks so much.


I just hit the lock button to get saved. That's it, go Hallie, good Amber, good Amber. Just a great feeling, you know, to be able to be back to back champions. And to do it with this special group of girls, these girls have worked hard all year. And nobody's took more swings in a batting case than our team. And we've just gelled at the right time and just super proud of them. Great effort, they've worked hard again all year. And anytime you win a regional tournament and get to go to a state tournament, it's exciting. We've got a lot of preparation to make, you know, where the tournament ran a little late. With the rain delays and so forth, we've got a lot of work to do to get ready, get settled and ready to go, but we've done it before, so that won't be a problem. Just so super proud of these girls, just a great team effort. And I just couldn't be any more proud. And, you know, being my last year in education and coached all those years, it's certainly exciting and just a great way to go out.