text:
.NET Tips and Tricks
The Data Science Lab
Practical .NET
The Practical Client
Data Driver
PDF Back Issues
HTML Issue Archive
Agile/Scrum
Cross-Platform C#
Mobile Corner
Live! Video
C#/VB
Xamarin/Mobile
TypeScript/Blazor/ASP.NET
Search & Destroy Bugs
Learn how to write programs that not only protect themselves from bugs, but that also seek them out and destroy them.
By Rod Stephens
Technology Toolbox: VB .NET
Like death and taxes, bugs are inevitable. It probably isn't possible to prove in a scientific sense that that any non-trivial program contains bugs, but it's good practice to assume bugs exist, and to program accordingly. Doing so enables you protect against them more easily and more completely.
In this article, I'll walk you through the process of designing your apps to minimize bugs, testing for them, and, finally, eradicating them. Debugging code is a three-part process. First, you can prevent bugs by understanding the code as thoroughly as possible. Use clear, uncomplicated code with good comments, and no sneaky tricks. Second, write code that looks for bugs aggressively. Use Debug.Assert and #If DEBUG to look for bugs in debug builds without affecting performance in release builds. You should use an abundance of tests, so you can detect bugs as close as possible to the code that caused them. Finally, you need to take care to fix the bugs you find carefully. Consider the consequences of your actions before you start ripping the code apart and slapping on patches. Test the code after you make changes. Then learn from the bugs you find. Add new offensive code to catch these types of bugs in the future. Every programmer creates bugs once in a while. Good programmers don't let the same bug bite them again and again.
You might be unable to find and remove every bug in a large (or even not so large) application, but you can use the approaches I'll lay out to make your code robust enough so that users might never know about their existence. Unfortunately many developers take the approach that their programs work correctly until proven otherwise. This sounds like a crazy approach when stated so bluntly, but it's an easy trap to fall into. When you write a small piece of code, it's natural to assume it contains no bugs. After all, if you knew there was a problem in the code, you would have fixed it. So why waste time looking for non-existent bugs that you "know" aren't there when you could be adding functionality that makes your application better?
A bug represents a misunderstanding, a mismatch between what the programmer wants the program to do and what it actually does. This can be as simple as the programmer initializing a variable incorrectly or as complex as writing an incorrect scheduling algorithm, but it's not really the program's fault. The computer does exactly what it is told to do, except in extreme cases such as floating point math bugs and so on. It's nearly always the developer's imperfect understanding of what he or she thinks the code will do versus what the code actually does that causes the problem.
It might also be the case that a programmer doesn't understand what the program is supposed to do or how other pieces of the program fit together. All these problems boil down to the same thing: the programmer doesn't understand completely how the program and its environment interact together.
At a high level, the solution to these problems is simple: Give the programmer a better understanding. In this article, I don't discuss requirements gathering and validation or architectural design; I assume the programmer has a decent understanding of what the code is supposed to do. Instead, I focus on techniques for better understanding the code.
Comment Often and Well
The first, most essential thing to keep in mind when you write code is that you're writing code for people, not just for the computer (Sidebar, "Top 10 Tips for Writing for People, Not Computers").
Top 10 Tips for Writing for People, not Computers
A computer does exactly what the code tells it to do, and it doesn't care what the code looks like. It doesn't care about alignment, comments, or documentation. In fact, it doesn't care whether you're writing in Visual Basic, C#, Java, or assembly. At some level, all of the code gets interpreted or compiled into machine code, and that's what the computer executes. If you were writing code for the computer, you would write in machine code.
At the same time, it's easy to forget that you write code for people, not computers. Ultimately, you are satisfying the requirements of a user somewhere, not just writing text that will execute on a computer. It's also easy to forget that you aren't writing code in a vacuum. In a development environment of any size, the code you write will be reviewed and or maintained by other people, so you need to make sure that you are clear about your intentions. Poorly commented code can make it enormously hard for other people to figure out what your app is supposed to do, much less how it is supposed to go about doing it.
Following these ten steps and keeping in mind you're writing code for people, not computers, can help you reduce the number of bugs in your code significantly.
Use an abundance of comments to explain what the code is doing and why. The reader should never need to guess what the code is doing. Debugging code should be a simple matter of comparing the code's purpose to its behavior, not an IQ test.
Use good variable names. Use Hungarian notation if required, but make the rest of the name meaningful. Good names basically give you "free" comments.
Use constants or enumerated types instead of magic numbers and hard-coded strings. The best part about this approach: It's another way for you to incorporate free comments.
Plan before you code. Many developers just sit down and start typing, but it's always better to at least sketch out a design before you code. Designing and programming can help you think about the code in two different ways, essentially giving you two perspectives on the code.
Make sure code lines up nicely to show its structure. The IDE helps but it can still do some weird things, particularly on continued lines.
Avoid sneaky tricks. If you need to use a complicated piece of code, comment it thoroughly. For example, some developers like to maximize performance, even to the extent of relying on undocumented features of the OS, and so on. But this code is often the most troublesome code to maintain because your super-fast algorithm for handling something can also be extremely fragile. Sometimes things are undocumented for a reason, and when the OS changes, your code will blow up. It's also the case that extremely complicated code is more fragile and more error-prone by nature. If you must use such code, give the person who maintains the app a chance to rectify problems if the code fails at a later time, for whatever reason.
Make routines small and with a well-defined purpose. If you can't describe a routine's purpose in one or two sentences, break it up into smaller pieces. Keeping routines compact and discrete makes it easier to return to the code later and make adjustments.
Keep lines of code small enough to read without scrolling far to the right. If a line is too long, continue it on the next line.
Limit variable scope. The more limited a variable's scope, the easier it is to see what it is doing.
Minimize side effects. Routines that modify their parameters can be extremely confusing because the change is not obvious from the outside. Modify parameters as seldom as possible, and use comments to make it obvious whenever you do so.
You can make understanding your code easier by adding insightful comments. These not only help others understand your code, but they help you clarify your ides as you write the code. They can also help you understand the code later if you need to modify or fix it.
It is well known that the longer a bug remains in the code, the harder it is to fix. One reason for this: The longer it's been since you wrote the code, the less you remember how it works. To fix the bug without breaking anything else, you need to regain the understanding you had when you originally wrote the code. Comments can make that easier.
I've heard developers argue that any comment that isn't essential is distracting and should therefore be removed. However, comments aren't most important when you are trying to understand what the code is supposed to do. They are most important when something is wrong and you need to compare in detail what the code is supposed to do against what it actually does. In that case, explicit, and detailed comments are critical. It's easier to add extra comments and ignore them when you don't need them, rather than skimping on comments and trying to figure out exactly where the code is going wrong without them.
Consider the approach taken on one project I worked on. We commented the code as normal, but, way off to the right, so the comments didn't distract you during normal reading, we added extra comments explaining what every non-trivial line of code did. You couldn't even see those comments unless you made the screen really big or scrolled to the right,. They were there if you needed them for debugging, however.
After development, we transferred the project to a maintenance group that had the philosophy that any comment that was not absolutely necessary was not allowed, and they removed all the extra comments. About six months later, they discovered that the code was not maintainable because they couldn't figure out how it worked. They'd make a change and the code would break. I'll give you three guesses as to why.
The relatively new XML comments and attributes such as Description and Category serve as comments for other developers, which makes it easier to understand your code's usage. You can use these features to help other developers understand your code better.
So far, I've covered ways to help make your code more understandable to other developers. Working in teams is one of the best ways possible to reduce the number of bugs in your code. For example, pair programming makes two developers look at the code. Two sets of eyes looking at the code are more likely to find trouble spots and help each other understand the code better.
Code reviews perform a similar function, ensuring that more than one person reads the code. It's fairly easy to breeze through a routine and see what you think it does, instead of what's actually there. It's much harder to explain the code to someone else if it doesn't do what you think it does. In fact, just preparing for a code review makes a programmer think about the code differently, and this process often exposes potential bugs.
Detect Bugs More Easily
Suppose you've followed good design practices, made a plan before coding, had design and code reviews, and you've written code for humans, rather than the computer. The bugs are still there. They are fewer in number than if you hadn't followed these practices, but you can bet there are a few still lurking about, waiting to pounce under the right circumstances.
Now your goal is to find as many of those bugs as possible, as quickly as possible, and as close as possible to the code that's causing them. All too often, the first indication that a problem exists with an application comes in the form of a bug report from a user or customer. By the time a bug is detected, thousands of lines of code might have fiddled with the data, so the source of the problem can be hard to pin down.
Some of the techniques you can use to find bugs as quickly as possible include offline testing and offensive coding.
You should test new code as soon as you write it. You should also test it as thoroughly as possible before you release it for integration with the rest of the application. It is surprising how many developers release their code with little or no testing. Sometimes this is partly due to management or cultural issues. It's natural to want to move on to write new code and achieve more milestones, but it's better to spend a little extra time now, so you don't have to spend a lot of time debugging later.
There are several different kinds of tests you can use to flush out bugs in your code. In exhaustive testing, you feed every possible input to a routine and verify the outputs. Unfortunately the number of legal inputs for most real applications is so huge this isn't practical.
In black box testing, you pretend you know nothing about how the code works. You dump a bunch of inputs into the routine and verify the outputs. To ensure that the tests find as many bugs as possible, you need to use a wide variety of inputs. Try a variety of valid and invalid inputs to make sure the code behaves as expected. Look for "natural trouble points" such as empty arrays, null references, and missing values.
In white box testing, you are allowed to peek at the code inside the routine and design test inputs to try to break the code. If you know that the code uses a particular data structure, try to pick inputs that won't fit into it easily.
Finally, try a bunch of randomly generated inputs if possible. Sometimes it can be hard to verify the results from random inputs (for example, verifying a face recognition algorithm might require you to review images manually). But if you can, write a program to generate random inputs and verify the results. Then you can run thousands of tests.
These different testing methods work best against different kinds of bugs, so it makes sense to use all of them. Write test modules that parallel code modules and keep them around for later use in case you need to retest the code.
Try Offensive Coding
The idea of defensive coding has been around for at least 30 years. The idea is to make the code use the fewest assumptions possible about its data, so the program doesn't crash if the data is wrong.
For example, assume the variable shirt_size should have one of the enumerated values Sizes.Small, Sizes.Medium, or Sizes.Large. The following code shows a defensive Select Case statement that examines the variable. The first two Case statements check explicitly for Small and Medium, and the Case Else statement handles Large (as the comment notes):
Select Case shirt_size
Case Sizes.Small
Case Sizes.Medium
Case Else ' Sizes.Large.
The Case Else section also handles any unexpected values that might sneak into the data. If you add the new value ExtraLarge to the enumerated values, but forget to update the Select Case statement, at least the program won't crash. Similarly if a bug in some other routine sets shirt_size to a numeric value outside of the enumeration's bounds, the program still won't crash.
This code does something with unexpected values, but it doesn't necessarily do the right thing with them. The program won't crash, but it might do something stupid, such as shipping a Large shirt when the customer ordered ExtraLarge or charging the Large price for an ExtraLarge shirt.
Worse, the program gives you no hint that anything is wrong. The error could go unfixed for a long time, during which time you are undercharging customers and sending them the wrong sizes. When a customer does complain, and you realize that there's a problem somewhere, you have no indication that this Select Case statement is causing trouble. You'll have to start a long debugging session, stepping through the code to figure out where things are going wrong.
A better approach is what I call offensive programming. Instead of making the code depend as little as possible on the data, it depends as much as possible on the data. It goes out of its way to look for trouble, trying to find data that doesn't fit its assumptions. If it finds a value that doesn't make sense, the code immediately brings it to the developer's attention. Instead of sweeping the problem under the rug as defensive programming does, offensive programming shines a spotlight on it.
This code illustrates an offensive version of the previous Select Case statement. If you add ExtraLarge to the Sizes enumeration, this code throws an error the first time it sees the new value. That gives developers a much better idea of where the problem first occurred, so tracking down the bug is much easier:
Case Sizes.Large
Throw New ArgumentException( _
"Unexpected shirt_size value")
Defensive programming does have the advantage of not allowing the program to crash, however, and that's still a worthwhile goal. Throwing an exception is useful for developers, but not so useful to end-users.
This code shows a compromise between the two approaches.
#If DEBUG Then
' Take some default action...
#End If
Instead of always throwing an exception when it encounters an unexpected value, this code checks the DEBUG environment variable to see if it is running in a debug or release build. If this is a debug build, the code throws the exception. If this is a release build, the code takes pity on the poor user and performs some default action. This should include notifying the developers of the bug somehow, perhaps by e-mailing a bug report, and possibly telling the user that the size they want is not currently available.
To set the DEBUG environment variable, open Visual Studio's Build menu and select the Configuration Manager. In the "Active solution configuration" dropdown, select Debug or Release.
Verify Data
Even offensive coding doesn't always find bugs as quickly as possible. In the previous example, the variable shirt_size might have been set incorrectly much earlier in the program and only detected when the program reached the Select Case statement. In the worst case, shirt_size might have been set incorrectly by another routine a long time ago in an unrelated code module or library. In that case, it could take you a while to trace the bad data back to its source.
You can localize bugs further by adding extra data checking code instead of waiting until the program needs to use the data. You could place this code just about anywhere, but you should focus on places where the data is likely to be modified.
One natural place to put data checking code is at routine entry and exit points. For example, when a subroutine starts, it can validate its input parameters, any other data that it will need to use, and any assumptions it needs to make.
As is the case with offensive programming, you might want the program to react differently at debug time and release time. For example, you might want it to throw an error if it sees suspicious data while you are developing the program. However, you might want the program to take some default action and continue anyway when you release the program to customers.
To make the program behave differently in debug and release versions, you can use #If DEBUG statements, as before. For simple validations, you can also use the Debug class's Assert method. Debug.Assert checks a Boolean condition and throws an exception if the condition is false. For example, this code illustrates how a routine might verify that the shirt_size parameter is between Sizes.Small and Sizes.Large in Visual Basic:
Debug.Assert( _
shirt_size >= Sizes.Small AndAlso shirt_size <= _
Sizes.Large, "Invalid shirt_size parameter.")
In debug builds, Debug.Assert performs its check normally. Calls to Debug.Assert are omitted from release builds, so they won't stop the program when end-users run it, don't increase the program's size, and don't affect the program's performance.
You can still use compiler directives such as #If DEBUG to manage more complicated tests. For instance, if you want the code to verify that the items in a large array are sorted, you can surround the code with an #If DEBUG statement so that validation is skipped in release builds.
Developers often avoid this kind of exhaustive validation by claiming it affects performance. By using Debug.Assert and conditional compilation directives, you can have your test—and performance, too.
It's also easy to claim that these checks are unnecessary because you tested the code before using it (assuming that's even true). If all of the code is tested properly, why should you keep verifying that the results are correct? The answer is that bugs are inevitable. Even if the code was correct at one time, there's no guarantee that it will remain correct. The more often you validate the data, the faster you will catch and fix bugs when they arise.
Eradicate Bugs
Once you know a bug has occurred, how do you figure out exactly what caused it? If you're lucky, offensive coding and data verification detected the problem close to its source. You can backtrack and the most recent statement that modified the data is usually the culprit.
If you're less lucky, you might have to step through a lot of code looking for the bug. Usually this happens when your offensive coding and data verification tests are not specific enough and missed the corrupt data. For example, you might have verified that a group of order numbers was sorted correctly, but perhaps you didn't notice that they were all the same.
In the short term, you can step through the code, examining the data until you stumble across the code that changed the data incorrectly. Visual Studio includes terrific tools for stepping through the code, examining data (IntelliSense even lets you drill down into complex data structures), changing variable values, calling routines, setting properties, and generally nosing around, looking for trouble.
Learning how to use these tools is largely a matter of finding out what they can do and practice, so I won't cover them in depth in this article. To learn more, check out the Visual Studio online help and experiment with the IDE, particularly the commands in the Debug menu. Note that there are two tools that are underused significantly by many developers: watch windows and breakpoints.
Watch windows let you display the values in key variables as you step through the code. Simply right-click on a variable and select Add Watch. Often, stepping through the code while watching a key variable can show you exactly where the problem is. The Locals and Autos windows (look in the Debug menu's Windows submenu) also let you view variable values easily as you step through the code.
No doubt, you know how to set a breakpoint on a line of code. However, you might not realize that you can place conditions on a breakpoint so it stops execution only under certain circumstances.
Let's give this a try. Set a breakpoint as usual (for example, click on the margin to the left of a line of code). Next, right-click on the breakpoint symbol to see options for modifying the breakpoint. Use the Condition command to make the breakpoint depend on some condition. For example, the breakpoint might stop execution at a particular line only if a variable holds a certain value or if its value has changed. If you design conditions properly, breakpoints can pinpoint the bug for you.
Use the Hit Count command to make the breakpoint stop execution when the line of code is reached a certain number of times or a multiple of some number of times (for example, every five times it is reached). This command also lets you reset the line's count. The When Hit command lets you make the breakpoint display a message or run a macro when it fires instead of simply stopping execution.
Plan Your Bug Fixes
After you have located a bug, don't blithely change the code to fix it. First, make a plan and think about the consequences of your changes. Make sure you understand how the code is supposed to work, how it actually works, and how it will work after you make the change. Remember that bugs are caused by not understanding the code. Make sure you understand the situation before you act. Changes to old code are far more likely to introduce new bugs than writing new code is, so think before you make matters worse.
After you fix the bug, test all the code! It's amazing how many programmers change code to fix a bug, possibly verify that the particular error condition is now accounted for, but don't test other cases to make sure nothing else is broken.
Rerun the tests that you wrote for this code originally. Then think about the bug you fixed and how you might detect it in the future. Add new tests to the code using either Debug.Assert or #If DEBUG to uncover that particular type of bug should it arise again. If you found a breakpoint useful in finding the bug, consider making it permanent with more tests that use either Debug.Assert or #If DEBUG. Add similar test code to other pieces of code where similar bugs might arise. It's bad enough to spend time fixing a bug once, but it's far worse to have to waste time finding the same kind of bug over and over again.
Taken as a whole, the steps I've laid out in this article can help you reduce the number of bugs that make their way into your application. More importantly, these steps can help you catch and eradicate the bugs that do get introduced more easily. Proper commenting practices are also important when someone needs to overhaul your application two or three years from now, if not further down the road, and at a time when you might not be available to answer questions or issues that come up. Designing your app properly can make a significant difference in how long it can continue to fulfill its role after you've released it into the wild—well, to IT, at any rate.
.NET Core Ranks High Among Frameworks in New Dev Survey
.NET Core placed high in a web-dominated ranking of development frameworks published by CodinGame, which provides a tech hiring platform.
Here's a One-Stop Shop for .NET 5 Improvements
Culled from reams of Microsoft documentation, here's a high-level summary of what's new for performance, networking, diagnostics and more, along with links to the nitty-gritty details for those wanting to dig in more.
Azure SQL Database Ranked Among Top 3 Databases of 2020
Microsoft touted the inclusion of Azure SQL Database among the top three databases of 2020 in a popularity ranking by DB-Engines, which collects and manages information about database management systems, updating its lists monthly.
Time Tracker Says VS Code Is No. 1 Editor for Devs, Some Working 15+ Hours Per Day
WakaTime, which does time tracking for programmers, released data for 2020 showing that Visual Studio Code is by far the top editor/IDE used by its coders, some of whom are hacking away for more than 15 hours per day.
How Does .NET 5 Do XAML? By Decoupling It from Windows with WinUI 3, C#/WinRT and More
.NET Insight
What's Ahead for .NET Development in 2021: Half-Day Virtual Summit
The MSIX Journey: What have we learned?
Hottest Third Party .NET Tools
How Blazor Changes Web Development
Training Seminar: San Francisco
Visual Studio Live! Virtual Training
Visual Studio Live! Microsoft HQ
August 9-13 2021
Visual Studio Live! San Diego
Live! 360 Orlando


Thank you to the photographers that are providing the use of their photos to assist in showing who we are as a People and as an organization. Thank you, Brian Adams, Amos Oxereok, Mary Sage, Jacqueline Cleveland, and Kelly Eningowuk.
Please note: all photos throughout this website are the sole property of the respective photographer, thereby all photographers retain copyright to their photos. No photographs or any portion thereof may be reproduced or used in any manner whatsoever.


text:
package io.netty.handler.codec.http2;

import io.netty.buffer.ByteBufAllocator;
import io.netty.handler.codec.UnsupportedValueConverter;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpMessage;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.AsciiString;
import io.netty.util.internal.InternalThreadLocalMap;
import io.netty.util.internal.UnstableApi;

import java.net.URI;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaderNames.COOKIE;
import static io.netty.handler.codec.http.HttpHeaderNames.TE;
import static io.netty.handler.codec.http.HttpHeaderValues.TRAILERS;
import static io.netty.handler.codec.http.HttpResponseStatus.parseLine;
import static io.netty.handler.codec.http.HttpScheme.HTTP;
import static io.netty.handler.codec.http.HttpScheme.HTTPS;
import static io.netty.handler.codec.http.HttpUtil.isAsteriskForm;
import static io.netty.handler.codec.http.HttpUtil.isOriginForm;
import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
import static io.netty.handler.codec.http2.Http2Exception.connectionError;
import static io.netty.handler.codec.http2.Http2Exception.streamError;
import static io.netty.util.AsciiString.EMPTY_STRING;
import static io.netty.util.AsciiString.contentEqualsIgnoreCase;
import static io.netty.util.AsciiString.indexOf;
import static io.netty.util.AsciiString.trim;
import static io.netty.util.ByteProcessor.FIND_COMMA;
import static io.netty.util.ByteProcessor.FIND_SEMI_COLON;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import static io.netty.util.internal.StringUtil.isNullOrEmpty;
import static io.netty.util.internal.StringUtil.length;
import static io.netty.util.internal.StringUtil.unescapeCsvFields;

/**
 * Provides utility methods and constants for the HTTP/2 to HTTP conversion
 */
@UnstableApi
public final class HttpConversionUtil {
    /**
     * The set of headers that should not be directly copied when converting headers from HTTP to HTTP/2.
     */
    private static final CharSequenceMap<AsciiString> HTTP_TO_HTTP2_HEADER_BLACKLIST =
            new CharSequenceMap<AsciiString>();
    static {
        HTTP_TO_HTTP2_HEADER_BLACKLIST.add(CONNECTION, EMPTY_STRING);
        @SuppressWarnings("deprecation")
        AsciiString keepAlive = HttpHeaderNames.KEEP_ALIVE;
        HTTP_TO_HTTP2_HEADER_BLACKLIST.add(keepAlive, EMPTY_STRING);
        @SuppressWarnings("deprecation")
        AsciiString proxyConnection = HttpHeaderNames.PROXY_CONNECTION;
        HTTP_TO_HTTP2_HEADER_BLACKLIST.add(proxyConnection, EMPTY_STRING);
        HTTP_TO_HTTP2_HEADER_BLACKLIST.add(HttpHeaderNames.TRANSFER_ENCODING, EMPTY_STRING);
        HTTP_TO_HTTP2_HEADER_BLACKLIST.add(HttpHeaderNames.HOST, EMPTY_STRING);
        HTTP_TO_HTTP2_HEADER_BLACKLIST.add(HttpHeaderNames.UPGRADE, EMPTY_STRING);
        HTTP_TO_HTTP2_HEADER_BLACKLIST.add(ExtensionHeaderNames.STREAM_ID.text(), EMPTY_STRING);
        HTTP_TO_HTTP2_HEADER_BLACKLIST.add(ExtensionHeaderNames.SCHEME.text(), EMPTY_STRING);
        HTTP_TO_HTTP2_HEADER_BLACKLIST.add(ExtensionHeaderNames.PATH.text(), EMPTY_STRING);
    }

    /**
     * This will be the method used for {@link HttpRequest} objects generated out of the HTTP message flow defined in [RFC 7540], Section 8.1
     */
    public static final HttpMethod OUT_OF_MESSAGE_SEQUENCE_METHOD = HttpMethod.OPTIONS;

    /**
     * This will be the path used for {@link HttpRequest} objects generated out of the HTTP message flow defined in [RFC 7540], Section 8.1
     */
    public static final String OUT_OF_MESSAGE_SEQUENCE_PATH = "";

    /**
     * This will be the status code used for {@link HttpResponse} objects generated out of the HTTP message flow defined
     * in [RFC 7540], Section 8.1
     */
    public static final HttpResponseStatus OUT_OF_MESSAGE_SEQUENCE_RETURN_CODE = HttpResponseStatus.OK;

    /**
     * [RFC 7540], 8.1.2.3 states the path must not
     * be empty, and instead should be {@code /}.
     */
    private static final AsciiString EMPTY_REQUEST_PATH = AsciiString.cached("/");

    private HttpConversionUtil() {
    }

    /**
     * Provides the HTTP header extensions used to carry HTTP/2 information in HTTP objects
     */
    public enum ExtensionHeaderNames {
        /**
         * HTTP extension header which will identify the stream id from the HTTP/2 event(s) responsible for
         * generating an {@code HttpObject}
         *

         * {@code "x-http2-stream-id"}
         */
        STREAM_ID("x-http2-stream-id"),
        /**
         * HTTP extension header which will identify the scheme pseudo header from the HTTP/2 event(s) responsible for
         * generating an {@code HttpObject}
         *

         * {@code "x-http2-scheme"}
         */
        SCHEME("x-http2-scheme"),
        /**
         * HTTP extension header which will identify the path pseudo header from the HTTP/2 event(s) responsible for
         * generating an {@code HttpObject}
         *

         * {@code "x-http2-path"}
         */
        PATH("x-http2-path"),
        /**
         * HTTP extension header which will identify the stream id used to create this stream in an HTTP/2 push promise
         * frame
         *

         * {@code "x-http2-stream-promise-id"}
         */
        STREAM_PROMISE_ID("x-http2-stream-promise-id"),
        /**
         * HTTP extension header which will identify the stream id which this stream is dependent on. This stream will
         * be a child node of the stream id associated with this header value.
         *

         * {@code "x-http2-stream-dependency-id"}
         */
        STREAM_DEPENDENCY_ID("x-http2-stream-dependency-id"),
        /**
         * HTTP extension header which will identify the weight (if non-default and the priority is not on the default
         * stream) of the associated HTTP/2 stream responsible responsible for generating an {@code HttpObject}
         *

         * {@code "x-http2-stream-weight"}
         */
        STREAM_WEIGHT("x-http2-stream-weight");

        private final AsciiString text;

        ExtensionHeaderNames(String text) {
            this.text = AsciiString.cached(text);
        }

        public AsciiString text() {
            return text;
        }
    }

    /**
     * Apply HTTP/2 rules while translating status code to {@link HttpResponseStatus}
     *
     * @param status The status from an HTTP/2 frame
     * @return The HTTP/1.x status
     * @throws Http2Exception If there is a problem translating from HTTP/2 to HTTP/1.x
     */
    public static HttpResponseStatus parseStatus(CharSequence status) throws Http2Exception {
        HttpResponseStatus result;
        try {
            result = parseLine(status);
            if (result == HttpResponseStatus.SWITCHING_PROTOCOLS) {
                throw connectionError(PROTOCOL_ERROR, "Invalid HTTP/2 status code '%d'", result.code());
            }
        } catch (Http2Exception e) {
            throw e;
        } catch (Throwable t) {
            throw connectionError(PROTOCOL_ERROR, t,
                            "Unrecognized HTTP status code '%s' encountered in translation to HTTP/1.x", status);
        }
        return result;
    }

    /**
     * Create a new object to contain the response data
     *
     * @param streamId The stream associated with the response
     * @param http2Headers The initial set of HTTP/2 headers to create the response with
     * @param alloc The {@link ByteBufAllocator} to use to generate the content of the message
     * @param validateHttpHeaders

     *
{@code true} to validate HTTP headers in the http-codec

     *
{@code false} not to validate HTTP headers in the http-codec

     *

     * @return A new response object which represents headers/data
     * @throws Http2Exception see {@link #addHttp2ToHttpHeaders(int, Http2Headers, FullHttpMessage, boolean)}
     */
    public static FullHttpResponse toFullHttpResponse(int streamId, Http2Headers http2Headers, ByteBufAllocator alloc,
                                                      boolean validateHttpHeaders)
                    throws Http2Exception {
        HttpResponseStatus status = parseStatus(http2Headers.status());
        // HTTP/2 does not define a way to carry the version or reason phrase that is included in an
        // HTTP/1.1 status line.
        FullHttpResponse msg = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, alloc.buffer(),
                                                           validateHttpHeaders);
        try {
            addHttp2ToHttpHeaders(streamId, http2Headers, msg, false);
        } catch (Http2Exception e) {
            msg.release();
            throw e;
        } catch (Throwable t) {
            msg.release();
            throw streamError(streamId, PROTOCOL_ERROR, t, "HTTP/2 to HTTP/1.x headers conversion error");
        }
        return msg;
    }

    /**
     * Create a new object to contain the request data
     *
     * @param streamId The stream associated with the request
     * @param http2Headers The initial set of HTTP/2 headers to create the request with
     * @param alloc The {@link ByteBufAllocator} to use to generate the content of the message
     * @param validateHttpHeaders

     *
{@code true} to validate HTTP headers in the http-codec

     *
{@code false} not to validate HTTP headers in the http-codec

     *

     * @return A new request object which represents headers/data
     * @throws Http2Exception see {@link #addHttp2ToHttpHeaders(int, Http2Headers, FullHttpMessage, boolean)}
     */
    public static FullHttpRequest toFullHttpRequest(int streamId, Http2Headers http2Headers, ByteBufAllocator alloc,
                                                boolean validateHttpHeaders)
                    throws Http2Exception {
        // HTTP/2 does not define a way to carry the version identifier that is included in the HTTP/1.1 request line.
        final CharSequence method = checkNotNull(http2Headers.method(),
                "method header cannot be null in conversion to HTTP/1.x");
        final CharSequence path = checkNotNull(http2Headers.path(),
                "path header cannot be null in conversion to HTTP/1.x");
        FullHttpRequest msg = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(method
                        .toString()), path.toString(), alloc.buffer(), validateHttpHeaders);
        try {
            addHttp2ToHttpHeaders(streamId, http2Headers, msg, false);
        } catch (Http2Exception e) {
            msg.release();
            throw e;
        } catch (Throwable t) {
            msg.release();
            throw streamError(streamId, PROTOCOL_ERROR, t, "HTTP/2 to HTTP/1.x headers conversion error");
        }
        return msg;
    }

    /**
     * Create a new object to contain the request data.
     *
     * @param streamId The stream associated with the request
     * @param http2Headers The initial set of HTTP/2 headers to create the request with
     * @param validateHttpHeaders

     *
{@code true} to validate HTTP headers in the http-codec

     *
{@code false} not to validate HTTP headers in the http-codec

     *

     * @return A new request object which represents headers for a chunked request
     * @throws Http2Exception see {@link #addHttp2ToHttpHeaders(int, Http2Headers, FullHttpMessage, boolean)}
     */
    public static HttpRequest toHttpRequest(int streamId, Http2Headers http2Headers, boolean validateHttpHeaders)
                    throws Http2Exception {
        // HTTP/2 does not define a way to carry the version identifier that is included in the HTTP/1.1 request line.
        final CharSequence method = checkNotNull(http2Headers.method(),
                "method header cannot be null in conversion to HTTP/1.x");
        final CharSequence path = checkNotNull(http2Headers.path(),
                "path header cannot be null in conversion to HTTP/1.x");
        HttpRequest msg = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(method.toString()),
                path.toString(), validateHttpHeaders);
        try {
            addHttp2ToHttpHeaders(streamId, http2Headers, msg.headers(), msg.protocolVersion(), false, true);
        } catch (Http2Exception e) {
            throw e;
        } catch (Throwable t) {
            throw streamError(streamId, PROTOCOL_ERROR, t, "HTTP/2 to HTTP/1.x headers conversion error");
        }
        return msg;
    }

    /**
     * Create a new object to contain the response data.
     *
     * @param streamId The stream associated with the response
     * @param http2Headers The initial set of HTTP/2 headers to create the response with
     * @param validateHttpHeaders

     *
{@code true} to validate HTTP headers in the http-codec

     *
{@code false} not to validate HTTP headers in the http-codec

     *

     * @return A new response object which represents headers for a chunked response
     * @throws Http2Exception see {@link #addHttp2ToHttpHeaders(int, Http2Headers,
     *         HttpHeaders, HttpVersion, boolean, boolean)}
     */
    public static HttpResponse toHttpResponse(final int streamId,
                                              final Http2Headers http2Headers,
                                              final boolean validateHttpHeaders) throws Http2Exception {
        final HttpResponseStatus status = parseStatus(http2Headers.status());
        // HTTP/2 does not define a way to carry the version or reason phrase that is included in an
        // HTTP/1.1 status line.
        final HttpResponse msg = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status, validateHttpHeaders);
        try {
            addHttp2ToHttpHeaders(streamId, http2Headers, msg.headers(), msg.protocolVersion(), false, false);
        } catch (final Http2Exception e) {
            throw e;
        } catch (final Throwable t) {
            throw streamError(streamId, PROTOCOL_ERROR, t, "HTTP/2 to HTTP/1.x headers conversion error");
        }
        return msg;
    }

    /**
     * Translate and add HTTP/2 headers to HTTP/1.x headers.
     *
     * @param streamId The stream associated with {@code sourceHeaders}.
     * @param inputHeaders The HTTP/2 headers to convert.
     * @param destinationMessage The object which will contain the resulting HTTP/1.x headers.
     * @param addToTrailer {@code true} to add to trailing headers. {@code false} to add to initial headers.
     * @throws Http2Exception If not all HTTP/2 headers can be translated to HTTP/1.x.
     * @see #addHttp2ToHttpHeaders(int, Http2Headers, HttpHeaders, HttpVersion, boolean, boolean)
     */
    public static void addHttp2ToHttpHeaders(int streamId, Http2Headers inputHeaders,
                    FullHttpMessage destinationMessage, boolean addToTrailer) throws Http2Exception {
        addHttp2ToHttpHeaders(streamId, inputHeaders,
                addToTrailer ? destinationMessage.trailingHeaders() : destinationMessage.headers(),
                destinationMessage.protocolVersion(), addToTrailer, destinationMessage instanceof HttpRequest);
    }

    /**
     * Translate and add HTTP/2 headers to HTTP/1.x headers.
     *
     * @param streamId The stream associated with {@code sourceHeaders}.
     * @param inputHeaders The HTTP/2 headers to convert.
     * @param outputHeaders The object which will contain the resulting HTTP/1.x headers..
     * @param httpVersion What HTTP/1.x version {@code outputHeaders} should be treated as when doing the conversion.
     * @param isTrailer {@code true} if {@code outputHeaders} should be treated as trailing headers.
     * {@code false} otherwise.
     * @param isRequest {@code true} if the {@code outputHeaders} will be used in a request message.
     * {@code false} for response message.
     * @throws Http2Exception If not all HTTP/2 headers can be translated to HTTP/1.x.
     */
    public static void addHttp2ToHttpHeaders(int streamId, Http2Headers inputHeaders, HttpHeaders outputHeaders,
            HttpVersion httpVersion, boolean isTrailer, boolean isRequest) throws Http2Exception {
        Http2ToHttpHeaderTranslator translator = new Http2ToHttpHeaderTranslator(streamId, outputHeaders, isRequest);
        try {
            translator.translateHeaders(inputHeaders);
        } catch (Http2Exception ex) {
            throw ex;
        } catch (Throwable t) {
            throw streamError(streamId, PROTOCOL_ERROR, t, "HTTP/2 to HTTP/1.x headers conversion error");
        }

        outputHeaders.remove(HttpHeaderNames.TRANSFER_ENCODING);
        outputHeaders.remove(HttpHeaderNames.TRAILER);
        if (!isTrailer) {
            outputHeaders.setInt(ExtensionHeaderNames.STREAM_ID.text(), streamId);
            HttpUtil.setKeepAlive(outputHeaders, httpVersion, true);
        }
    }

    /**
     * Converts the given HTTP/1.x headers into HTTP/2 headers.
     * The following headers are only used if they can not be found in from the {@code HOST} header or the
     * {@code Request-Line} as defined by rfc7230
     *

     *
{@link ExtensionHeaderNames#SCHEME}

     *

     * {@link ExtensionHeaderNames#PATH} is ignored and instead extracted from the {@code Request-Line}.
     */
    public static Http2Headers toHttp2Headers(HttpMessage in, boolean validateHeaders) {
        HttpHeaders inHeaders = in.headers();
        final Http2Headers out = new DefaultHttp2Headers(validateHeaders, inHeaders.size());
        if (in instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) in;
            URI requestTargetUri = URI.create(request.uri());
            out.path(toHttp2Path(requestTargetUri));
            out.method(request.method().asciiName());
            setHttp2Scheme(inHeaders, requestTargetUri, out);

            if (!isOriginForm(requestTargetUri) && !isAsteriskForm(requestTargetUri)) {
                // Attempt to take from HOST header before taking from the request-line
                String host = inHeaders.getAsString(HttpHeaderNames.HOST);
                setHttp2Authority((host == null || host.isEmpty()) ? requestTargetUri.getAuthority() : host, out);
            }
        } else if (in instanceof HttpResponse) {
            HttpResponse response = (HttpResponse) in;
            out.status(response.status().codeAsText());
        }

        // Add the HTTP headers which have not been consumed above
        toHttp2Headers(inHeaders, out);
        return out;
    }

    public static Http2Headers toHttp2Headers(HttpHeaders inHeaders, boolean validateHeaders) {
        if (inHeaders.isEmpty()) {
            return EmptyHttp2Headers.INSTANCE;
        }

        final Http2Headers out = new DefaultHttp2Headers(validateHeaders, inHeaders.size());
        toHttp2Headers(inHeaders, out);
        return out;
    }

    private static CharSequenceMap<AsciiString> toLowercaseMap(Iterator<? extends CharSequence> valuesIter,
                                                               int arraySizeHint) {
        UnsupportedValueConverter<AsciiString> valueConverter = UnsupportedValueConverter.<AsciiString>instance();
        CharSequenceMap<AsciiString> result = new CharSequenceMap<AsciiString>(true, valueConverter, arraySizeHint);

        while (valuesIter.hasNext()) {
            AsciiString lowerCased = AsciiString.of(valuesIter.next()).toLowerCase();
            try {
                int index = lowerCased.forEachByte(FIND_COMMA);
                if (index != -1) {
                    int start = 0;
                    do {
                        result.add(lowerCased.subSequence(start, index, false).trim(), EMPTY_STRING);
                        start = index + 1;
                    } while (start < lowerCased.length() &&
                             (index = lowerCased.forEachByte(start, lowerCased.length() - start, FIND_COMMA)) != -1);
                    result.add(lowerCased.subSequence(start, lowerCased.length(), false).trim(), EMPTY_STRING);
                } else {
                    result.add(lowerCased.trim(), EMPTY_STRING);
                }
            } catch (Exception e) {
                // This is not expect to happen because FIND_COMMA never throws but must be caught
                // because of the ByteProcessor interface.
                throw new IllegalStateException(e);
            }
        }
        return result;
    }

    /**
     * Filter the {@link HttpHeaderNames#TE} header according to the
     * special rules in the HTTP/2 RFC.
     * @param entry An entry whose name is {@link HttpHeaderNames#TE}.
     * @param out the resulting HTTP/2 headers.
     */
    private static void toHttp2HeadersFilterTE(Entry<CharSequence, CharSequence> entry,
                                               Http2Headers out) {
        if (indexOf(entry.getValue(), ',', 0) == -1) {
            if (contentEqualsIgnoreCase(trim(entry.getValue()), TRAILERS)) {
                out.add(TE, TRAILERS);
            }
        } else {
            List<CharSequence> teValues = unescapeCsvFields(entry.getValue());
            for (CharSequence teValue : teValues) {
                if (contentEqualsIgnoreCase(trim(teValue), TRAILERS)) {
                    out.add(TE, TRAILERS);
                    break;
                }
            }
        }
    }

    public static void toHttp2Headers(HttpHeaders inHeaders, Http2Headers out) {
        Iterator<Entry<CharSequence, CharSequence>> iter = inHeaders.iteratorCharSequence();
        // Choose 8 as a default size because it is unlikely we will see more than 4 Connection headers values, but
        // still allowing for "enough" space in the map to reduce the chance of hash code collision.
        CharSequenceMap<AsciiString> connectionBlacklist =
            toLowercaseMap(inHeaders.valueCharSequenceIterator(CONNECTION), 8);
        while (iter.hasNext()) {
            Entry<CharSequence, CharSequence> entry = iter.next();
            final AsciiString aName = AsciiString.of(entry.getKey()).toLowerCase();
            if (!HTTP_TO_HTTP2_HEADER_BLACKLIST.contains(aName) && !connectionBlacklist.contains(aName)) {
                // https://tools.ietf.org/html/rfc7540#section-8.1.2.2 makes a special exception for TE
                if (aName.contentEqualsIgnoreCase(TE)) {
                    toHttp2HeadersFilterTE(entry, out);
                } else if (aName.contentEqualsIgnoreCase(COOKIE)) {
                    AsciiString value = AsciiString.of(entry.getValue());
                    // split up cookies to allow for better compression
                    // https://tools.ietf.org/html/rfc7540#section-8.1.2.5
                    try {
                        int index = value.forEachByte(FIND_SEMI_COLON);
                        if (index != -1) {
                            int start = 0;
                            do {
                                out.add(COOKIE, value.subSequence(start, index, false));
                                // skip 2 characters "; " (see https://tools.ietf.org/html/rfc6265#section-4.2.1)
                                start = index + 2;
                            } while (start < value.length() &&
                                    (index = value.forEachByte(start, value.length() - start, FIND_SEMI_COLON)) != -1);
                            if (start >= value.length()) {
                                throw new IllegalArgumentException("cookie value is of unexpected format: " + value);
                            }
                            out.add(COOKIE, value.subSequence(start, value.length(), false));
                        } else {
                            out.add(COOKIE, value);
                        }
                    } catch (Exception e) {
                        // This is not expect to happen because FIND_SEMI_COLON never throws but must be caught
                        // because of the ByteProcessor interface.
                        throw new IllegalStateException(e);
                    }
                } else {
                    out.add(aName, entry.getValue());
                }
            }
        }
    }

    /**
     * Generate an HTTP/2 {code :path} from a URI in accordance with
     * rfc7230, 5.3.
     */
    private static AsciiString toHttp2Path(URI uri) {
        StringBuilder pathBuilder = new StringBuilder(length(uri.getRawPath()) +
                length(uri.getRawQuery()) + length(uri.getRawFragment()) + 2);
        if (!isNullOrEmpty(uri.getRawPath())) {
            pathBuilder.append(uri.getRawPath());
        }
        if (!isNullOrEmpty(uri.getRawQuery())) {
            pathBuilder.append('?');
            pathBuilder.append(uri.getRawQuery());
        }
        if (!isNullOrEmpty(uri.getRawFragment())) {
            pathBuilder.append('#');
            pathBuilder.append(uri.getRawFragment());
        }
        String path = pathBuilder.toString();
        return path.isEmpty() ? EMPTY_REQUEST_PATH : new AsciiString(path);
    }

    // package-private for testing only
    static void setHttp2Authority(String authority, Http2Headers out) {
        // The authority MUST NOT include the deprecated "userinfo" subcomponent
        if (authority != null) {
            if (authority.isEmpty()) {
                out.authority(EMPTY_STRING);
            } else {
                int start = authority.indexOf('@') + 1;
                int length = authority.length() - start;
                if (length == 0) {
                    throw new IllegalArgumentException("authority: " + authority);
                }
                out.authority(new AsciiString(authority, start, length));
            }
        }
    }

    private static void setHttp2Scheme(HttpHeaders in, URI uri, Http2Headers out) {
        String value = uri.getScheme();
        if (value != null) {
            out.scheme(new AsciiString(value));
            return;
        }

        // Consume the Scheme extension header if present
        CharSequence cValue = in.get(ExtensionHeaderNames.SCHEME.text());
        if (cValue != null) {
            out.scheme(AsciiString.of(cValue));
            return;
        }

        if (uri.getPort() == HTTPS.port()) {
            out.scheme(HTTPS.name());
        } else if (uri.getPort() == HTTP.port()) {
            out.scheme(HTTP.name());
        } else {
            throw new IllegalArgumentException(":scheme must be specified. " +
                    "see https://tools.ietf.org/html/rfc7540#section-8.1.2.3");
        }
    }

    /**
     * Utility which translates HTTP/2 headers to HTTP/1 headers.
     */
    private static final class Http2ToHttpHeaderTranslator {
        /**
         * Translations from HTTP/2 header name to the HTTP/1.x equivalent.
         */
        private static final CharSequenceMap<AsciiString>
            REQUEST_HEADER_TRANSLATIONS = new CharSequenceMap<AsciiString>();
        private static final CharSequenceMap<AsciiString>
            RESPONSE_HEADER_TRANSLATIONS = new CharSequenceMap<AsciiString>();
        static {
            RESPONSE_HEADER_TRANSLATIONS.add(Http2Headers.PseudoHeaderName.AUTHORITY.value(),
                            HttpHeaderNames.HOST);
            RESPONSE_HEADER_TRANSLATIONS.add(Http2Headers.PseudoHeaderName.SCHEME.value(),
                            ExtensionHeaderNames.SCHEME.text());
            REQUEST_HEADER_TRANSLATIONS.add(RESPONSE_HEADER_TRANSLATIONS);
            RESPONSE_HEADER_TRANSLATIONS.add(Http2Headers.PseudoHeaderName.PATH.value(),
                            ExtensionHeaderNames.PATH.text());
        }

        private final int streamId;
        private final HttpHeaders output;
        private final CharSequenceMap<AsciiString> translations;

        /**
         * Create a new instance
         *
         * @param output The HTTP/1.x headers object to store the results of the translation
         * @param request if {@code true}, translates headers using the request translation map. Otherwise uses the
         *        response translation map.
         */
        Http2ToHttpHeaderTranslator(int streamId, HttpHeaders output, boolean request) {
            this.streamId = streamId;
            this.output = output;
            translations = request ? REQUEST_HEADER_TRANSLATIONS : RESPONSE_HEADER_TRANSLATIONS;
        }

        void translateHeaders(Iterable<Entry<CharSequence, CharSequence>> inputHeaders) throws Http2Exception {
            // lazily created as needed
            StringBuilder cookies = null;

            for (Entry<CharSequence, CharSequence> entry : inputHeaders) {
                final CharSequence name = entry.getKey();
                final CharSequence value = entry.getValue();
                AsciiString translatedName = translations.get(name);
                if (translatedName != null) {
                    output.add(translatedName, AsciiString.of(value));
                } else if (!Http2Headers.PseudoHeaderName.isPseudoHeader(name)) {
                    // https://tools.ietf.org/html/rfc7540#section-8.1.2.3
                    // All headers that start with ':' are only valid in HTTP/2 context
                    if (name.length() == 0 || name.charAt(0) == ':') {
                        throw streamError(streamId, PROTOCOL_ERROR,
                                "Invalid HTTP/2 header '%s' encountered in translation to HTTP/1.x", name);
                    }
                    if (COOKIE.equals(name)) {
                        // combine the cookie values into 1 header entry.
                        // https://tools.ietf.org/html/rfc7540#section-8.1.2.5
                        if (cookies == null) {
                            cookies = InternalThreadLocalMap.get().stringBuilder();
                        } else if (cookies.length() > 0) {
                            cookies.append("; ");
                        }
                        cookies.append(value);
                    } else {
                        output.add(name, value);
                    }
                }
            }
            if (cookies != null) {
                output.add(COOKIE, cookies.toString());
            }
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
package org.gradle.play.internal.spec;

import org.gradle.api.reporting.components.internal.AbstractBinaryRenderer;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.play.PlayApplicationBinarySpec;

import javax.inject.Inject;

public class PlayApplicationBinaryRenderer extends AbstractBinaryRenderer<PlayApplicationBinarySpec> {
    @Inject
    public PlayApplicationBinaryRenderer(ModelSchemaStore schemaStore) {
        super(schemaStore);
    }

    @Override
    public Class<PlayApplicationBinarySpec> getTargetType() {
        return PlayApplicationBinarySpec.class;
    }
}


text:
Metro Transportation News & Reviews
Los Angeles' Amanda Gorman makes history as inaugural poet
by Steve Hymon , January 21, 2021
Los Angeles' own Amanda Gorman made history at age 22 on Wednesday when she delivered her poem, "The Hill We Climb" at the inauguration of President Joe Biden and Vice President Kamala Harris. Her deeply moving performance has been lauded by some of the nation's most influential luminaries, including Lin-Manuel Miranda, Michelle Obama, Oprah Winfrey and Hillary Clinton.
Gorman — the first National Youth Poet Laureate — also recently wrote an original poem, commissioned by Metro, that reflects on transit in Los Angeles. The poem will be included in a forthcoming Metro Art publication featuring works by several artists who are connected to the neighborhoods along the future Crenshaw/LAX light rail line.
This is not the first time an artist commissioned by Metro has received national recognition in the early days of their career.
•In 2017, Kehinde Wiley, a Metro Art Young Artists program alum, was selected by the Smithsonian's National Portrait Gallery to create the official portrait of former President Barack Obama. At the age of 17, Wiley was one of 14 young artists selected to participate in Metro's Young Artists program and he created a large-scale mural that was reproduced and placed in 2,000 Metro buses.
•In 2013, while working on a commission titled "Artist Educators" on the E Line's (Expo) Palms Station, artist Shizu Saldamando was honored as a member of the nation's artistic elite at the White House Historical Association Arts Reception, hosted by then-First Lady Michelle Obama.
•Jazz artist and Los Angeles native Kamasi Washington — who in 2015 performed at Union Station as part of Metro Art Presents — has gone on to play at the world's most prominent music festivals such as Coachella, Glastonbury and Bonnaroo. He was included in the prestigious 2017 Whitney Biennial, featured in a major NY Times profile in 2016 as a "jazz celebrity," and even served as a guest on the Tavis Smiley Show.
Metro works closely with arts professionals throughout Los Angeles County to find talent from emerging to established artists. Our goal is build and operate transit projects that are both aesthetically-pleasing and which build and enhance communities.
"It is a significant honor to see many artists that we have worked with in the early stages of their careers receive well-deserved recognition, including some of our country's highest accolades," said Maya Emsden, Deputy Executive Officer, Arts & Design. "We believe art has the power to inspire, transform and bring people together in the public sphere."
With nearly 11,000 employees and an annual budget north of $6 billion, Metro runs the nation's third-busiest transit system. Beyond Metro Art, many former associates and employees have enjoyed great success elsewhere.
"Our role at LA Metro goes beyond running buses and trains — we're trying to rebuild communities and provide housing, create beautiful public spaces and connect people to jobs and opportunities and all the things that make life worth living — such as the arts," said Metro CEO Phillip A. Washington. "And on Inauguration Day it was wonderful to see someone connected to Los Angeles County Metro encourage all Americans to help this country reach its full potential."
Share the Source:
Categories: Transportation News
Tagged as: Amanda Gorman, art, Crenshaw/LAX Transit Project, culture, design, E Line, Inauguration, Joe Biden, Kamala Harris, Kamasi Washington, Maya Emsden, Metro Art, Palms Station, Phil Washington, Shizu Saldamando
Surge in COVID-19 poses challenge to Metro Rail projects
Metro Micro expands Monday to three new service zones: Compton/Artesia, El Monte and North Hollywood/Burbank
Copyright © 2023 | Metro - Los Angeles County Metropolitan Transportation Authority - The Source

redpajama_set_name: RedPajamaCommonCrawl


Stocks opened sharply lower and continued declining to end the day near session lows. The Dow Jones Industrial Average lost 392 points, or 2.3%, and the S&P 500 gave up 47 points, or 2.4%. Both indexes are down 5% so far this week.
Today's slump followed a sharp drop in the Chinese stock market, which fell by 7% overnight before trading was halted just 30 minutes into the session. Meanwhile, the U.S. economic calendar was light heading into tomorrow's key employment report that's expected to show that 200,000 jobs were created in December as the unemployment rate held steady at 5%.
As for individual stocks, department store chainMacy's and alcohol giantConstellation Brands were two of the best performers in the market today.
Macy's cost cuts Macy's avoided the strong negative tide, rising 2% after the retailer announced two important updates on its operations.
The first was on the subject of sales growth. Macy's revealed that comparable-store sales slumped by 5.2% over the key holiday shopping months of November and December versus a 3.6% drop in the third quarter, which management attributed mainly to unusually high temperatures in many parts of the country that held back sales of cold weather items like jackets and gloves.
"We were particularly disadvantaged by the historically warm weather in northern climate zones where Macy's and Bloomingdale's are especially well-represented," CEO Terry Lundgren said in a press release. The company also lowered its forecast for fourth quarter sales, down to a 5% loss from the prior guidance of between a 2% and 3% drop.
Yet investors responded positively to Macy's second announcement, which outlined plans for ramped-up store closings and cost cuts in the year ahead. The company is also looking into ways to generate cash from its real estate portfolio, including on flagship locations in Manhattan, San Francisco, Chicago, and Minneapolis. "We are making adjustments to become more efficient and productive in our operations," Lundgren said.
Constellation brands' beer celebrationConstellation Brands also rose 4% today on heavy trading volume. Shares of the global wine, beer, and spirits giant touched a new all-time high in the wake of its fiscal third quarter earnings announcement. Sales in the period rose 6% to $1.6 billion, as profit improved to $1.42 per share. Both figures easily beat consensus estimates.
The company is finding its beer business to be incredibly profitable these days. In fact, the term that management used was "remarkable", and it's not hard to see why.
Beer revenue improved by 8% on strength in the Corona, Modelo, and Pacifico brands. However, profits leapt even higher by 20% as prices moved up, and costs trended down. That was a big reason why Constellation Brands saw its operating margin jump to 29% of sales from 27% last year. The company's net income spiked 16% higher to $289 million.
CEO Rob Sands and his executive team raised their sales outlook for the full year. They also announced firm plans to add a new beer brewery in Mexico and expand production at an existing factory there, "to support the significant growth opportunity we see for our beer business over the long-term." The added capacity should help the company earn as much as $5.40 per share in fiscal 2016, up 22% from the $4.44 per share it generated last year.
The article Why Macys Inc. and Constellation Brands Inc. Rose on a Terrible Day for Stocks originally appeared on Fool.com.


text:
Joilson Melo Explains How to Become a Prominent Lawyer in a Country Like Brazil
By Evan Arroyo By Evan Arroyo | August 4, 2021 |
The lawyer profession is becoming popular among Brazilians, but becoming one is not easy. If you find the job of a lawyer lucrative and want to become one, then this article is perfect for you. In this article, we will outline the process to become a lawyer in Brazil. We have Joilson Melo as an ideal example to describe the potential of a lawyer.
Lawyers in Brazil
Brazil is noted for its national level of training for lawyers. Lawyers in Brazil go through a rigorous process before starting their education, during their law graduation, and after their education. After being involved in many national-level law activities, Joilson has learned that being a lawyer is challenging mentally, financially, and personally. A lawyer needs to deal with various types of cases during his career and proceed accordingly.
Joilson Melo is a unique example of what Brazil's most prominent and rising lawyers look like. He works to eradicate the misuse of the legal system by an influential set of people. At present, Joilson is a law student at Fasip College. Besides his education, he actively works to raise objections to prevalent illegitimate and malpractices in Brazil. Furthermore, he wants to become a talented and knowledgeable lawyer in the law community. He is famous for his fearless approach towards injustice and misuse of powers by influential people. Joilson Melo wants to enhance the citizen involvement to make them aware enough to request action against a cruel practice that can be expelled from society.
How to Become a Lawyer in BrazilThere are three steps you need to follow to become a lawyer in Brazil.
● Pass Vestibular
● Get a Graduation Degree
● Pass the National Bar Examination
For admission into a law school, the students must complete "Vestibular" to get access. The rule was amended so that students can now be admitted through a national exam known as "Exame Nacional do Ensino Médio."
Once the student has cleared either Vestibular or ENEM, the university education starts. Generally, the duration of a law degree is five years. Joilson Melo states that one should pursue a law degree from a university accredited by the National Commission of Legal Education of the OAB Federal Council and follow the Federal Ministry of Education regulations.
Significance of Internship
Joilson Melo believes that a law student should do an internship to understand the basic nuances at ground level. A student can work as an intern at Law firms, companies, or other organizations.
Set of Mandatory Subjects
To maintain the uniformity and quality of education, the National Council of Education has prescribed some mandatory subjects that need to be part of every law education curriculum.
Primary Education Axis has subjects linked to Law, political sciences, economics, sociology, and philosophy.
Professional Education Axis includes constitutional Law, Administrative Law, and International Law, etc.
Practical Education Axis blends all the aspects of the first two axes. This axis needs 300 hours of mandatory vocational training and 250 hours of complementary activities.
OAB & Brazilian Bar Examination
It is a pan-Brazil examination that occurs 2-3 times a year, usually in January, March, and September. The OAB Exam has two sections:
● The first part has 80 MCQs, which are to be answered. A student must answer at least 40 questions correctly to be eligible to appear for the next section.
● This step is based on the candidate's preferences, such as administrative Law, finance law, corporate Law, constitutional Law, or Civil Law. The candidate must pass the 2nd step with 60% marks.
The Brazilian legal system is statutory and complex. Joilson Melo considers that a person should take a lawyer's job as a revolutionary weapon towards change for the better, not just an earning profession. Joilson Melo is very active in legal activities that could bring development to society. He envisions bridging the gap between the poor and the influential people. Joilson Melo is contributing to several legal cases in Brazil.
He strives to bring a change by his disruptive knowledge of Law and the legal system. The country needs more young lawyers like Joilson as he aims to ensure equity in terms of justice. Joilson wants to open a law firm exclusively to provide justice to thousands of people and eliminate malpractices in Brazil.
Tags: sponsored
Photography by: Joilson Melo


text:
> 0.2 ACRES – 3 Story Commercial Building In Quepos With Surf And Marina Views!!!!
https://vivatropical.com/property/listing/874283/ Quepos Arco Iris Castle has a long history as one of the most iconic nightclubs in the Central Pacific Area for over 20 years. As you enter the town of Quepos, this 3 story building immediately stands out with its peculiar architecture, mirroring a castle with its own river crossing beneath the entrance. Despite not working as a disco club anymore, Quepos Arco Iris Castle boasts vibrant ocean views that make it a great business opportunity for anyone trying to invest in the heart of Quepos. Quepos Arco Iris Castle's ground level can be accessed from both the main entrance of Quepos and Manuel Antonio, as well as a secondary public road. There's a caretaker apartment within the grounds, a covered BBQ area alongside the main building, and, naturally, the main structures that used to host the nightclub. These latter can be easily repurposed for a restaurant, a food court, a shopping plaza, or a renewed bar. The possibilities are quite endless. The property has a second level that can be accessed through two grand staircases leading up from both sides. This is where the disco's exclusive area was hosted, but it can be modified to an independent office space, apartment, or storage facility. The third and final level offers two studio apartments with marvelous views of the Marina Pez Vela and the beach, alongside an open-air terrace that presents plenty of opportunities for further expansion or development. You'll be hard-pressed to find a better location in Quepos, as virtually every tourist and resident of Manuel Antonio and Quepos has to cross this spot on their way in or out of town. If you take into account the existing infrastructure, the unparalleled location, and the amazing views, this is truly a once-in-a-lifetime opportunity for commercial development in one of Costa Rica's hottest and most famous markets.
0.2 ACRES – 3 Story Commercial Building In Quepos With Surf And Marina Views!!!!
Quepos Arco Iris Castle has a long history as one of the most iconic nightclubs in the Central Pacific Area for over 20 years. As you enter the town of Quepos, this 3 story building immediately stands out with its peculiar architecture, mirroring a castle with its own river crossing beneath the entrance. Despite not working as a disco club anymore, Quepos Arco Iris Castle boasts vibrant ocean views that make it a great business opportunity for anyone trying to invest in the heart of Quepos.
Quepos Arco Iris Castle's ground level can be accessed from both the main entrance of Quepos and Manuel Antonio, as well as a secondary public road. There's a caretaker apartment within the grounds, a covered BBQ area alongside the main building, and, naturally, the main structures that used to host the nightclub. These latter can be easily repurposed for a restaurant, a food court, a shopping plaza, or a renewed bar. The possibilities are quite endless.
The property has a second level that can be accessed through two grand staircases leading up from both sides. This is where the disco's exclusive area was hosted, but it can be modified to an independent office space, apartment, or storage facility. The third and final level offers two studio apartments with marvelous views of the Marina Pez Vela and the beach, alongside an open-air terrace that presents plenty of opportunities for further expansion or development.
You'll be hard-pressed to find a better location in Quepos, as virtually every tourist and resident of Manuel Antonio and Quepos has to cross this spot on their way in or out of town. If you take into account the existing infrastructure, the unparalleled location, and the amazing views, this is truly a once-in-a-lifetime opportunity for commercial development in one of Costa Rica's hottest and most famous markets.


BOSTON (AP) Arizona Coyotes forward Alexander Burmistrov was taken off on a stretcher after a hit from Bruins defenseman Colin Miller on Tuesday night left him motionless on the ice for several minutes.
Burmistrov received a pass and had just sent the puck along when Miller came into him sideways and knocked him down. Burmistrov landed on his back and rolled partially onto his side, but otherwise did not move as first the Coyotes and then the Bruins medical staffs came out to tend to him.
Miller was immediately set upon by Arizona defenseman Jakob Chychrun, but the officials broke in before it could get too far.
Miller was given five minutes for charging and thrown out of the game, and Chychrun was given two minutes for roughing. The Bruins got a short-handed goal to make it 2-1 and took a 4-1 lead before the period was over.
Burmistrov, 25, is a 2010 first-round draft pick from Russia who has one goal and 10 assists this season.


We have years of experience in areas of audit, accounting, bookkeeping services, company formations, preparation of legal documents, service tax registration procedure, accounting outsourcing services, private limited company registration, partnership registration, VAT/CST and income tax services. We aim to create a good bond with our clients and help them understand their financial situations better and guide them in their business and help achieve results which are goal oriented by monitoring them continuously. We are committed to keep up to the highest standards of professionalism, quality, honesty and integrity and hence work on becoming the best chartered accountants in Delhi.
We provide all kind of services related to income tax. Being one of the leading income tax consultants in Delhi, our experienced team are experts in developing efficient, cost effective and quality tax strategies that help our client's manage accordingly to the current tax laws under the government guidelines. We provide quality income tax consultancy to corporate, foreign companies, partnership firms, individuals (residents and non residents) and person of Indian Origin (POI). Along with this we do offer income tax services that include taxation on the earned income in a financial year as per the tax rates that particular year.


Planned Parenthood is the largest distributor of services that inhibit human rights in the United States of America.Through God's good grace, your donations, the hard work and dedication of all of us, and virtually nonstop prayer, the Women's Pavilion, Dr. Klopfer's abortion clinic, was shut down. The question that I am sure many of you are asking is this: is that it? Is our work done? The answer is, unfortunately, no. But what happens now?
So let us direct our attention to the Merrillville abortion clinic and the Planned Parenthood on Grape Road. The devil is still persuading people to walk the wide, popular path that leads to perdition.


text:
Postdoctoral Research Scholar in Neurogenic Language Disorders
hallowel at ohio.edu hallowel at ohio.edu
Thu Nov 5 21:25:44 UTC 2009
Previous message: 2nd Call for Papers: CADAAD 2010
Next message: Dear funknet at listserv.linguistlist.org 72% 0FF on Pfizer.
Dear colleague:
Please share the announcement below with anyone you know who may be seeking a postdoctoral research
position in the area of acquired neurogenic language disorders in adults. The new position entails
personalized mentorship in scholarly career development and exceptional opportunities for hands-on
experience in technology transfer using eye-tracking technology.
The position requires a completed Ph.D. and strong interests in aphasia and other acquired
neurogenic language disorders in adults.  Applicants may be from any disciplinary background.
Brooke Hallowell (hallowel at ohio.edu)
School of Hearing, Speech and Language Sciences, College of Health and Human Services, Ohio
Position Description: Postdoctoral scholars are invited to apply for a twelve-month appointment in
a thriving research laboratory group dedicated to acquired neurogenic language disorders in adults.
The position is funded through the National Institutes of Health (NIH) National Institute on
Deafness and other Communication Disorders (NIDCD) and the Ohio University Technology Gap Fund.
Responsibilities include: (a) coordination, recruitment and scheduling of research participants
(controls and adults with aphasia) for experiments, (b) coordination of data collection involving
people with and without aphasia, (c) development of research databases, (d) assistance with data
analysis, and (e) contribution to scholarly manuscripts for publications based on results. Strong
teamwork is essential. The successful applicant will be encouraged to take advantage of
personalized mentorship in scholarly career development, including research processes, publication,
and grant writing. Additionally, the position entails exceptional opportunities for hands-on
experience in technology transfer and commercialization of research.
The Ohio University Neurolinguistics Laboratory: Directed by Dr. Brooke Hallowell, the Ohio
University Neurolinguistics Laboratory is dedicated to the study of acquired neurogenic language
disorders in adults.  Disorders under study include aphasia and aspects of brain injury, dementia,
stroke, and diabetes that affect people's cognitive and communicative abilities. New technologies
are under development to address problems of assessment of language comprehension, working memory,
attention, and other areas of linguistic and cognitive processing. In addition to its on-campus
research space in Grover Center, the Neurolinguistics Laboratory has multiple affiliated clinical
research sites, including the Cleveland Hearing and Speech Center (Cleveland, OH), the Ohio
University Clinical Research Site in Columbus (Columbus, OH), the University of West Virginia
School of Medicine (Morgantown, VA), the Stroke Comeback Center (Oakton, VA), and the Moscow
Federal Center of Speech Pathology and Neurorehabilitation (Moscow, Russia). Research is also
active with collaborators in the United Kingdom, India, China, and Korea. Current extramural
funding sources include the National Institutes of Health and the National Science Foundation.
Neurolinguistics Laboratory members demonstrate ongoing excellent success with research awards and
peer-reviewed research publications and conference presentations.
The School of Hearing, Speech and Language Sciences (HSLS): The School is one of the oldest and
largest academic programs in communication sciences and disorders in the world. HSLS offers five
degree programs: BS in Hearing, Speech and Language Sciences, MA in Speech-Language Pathology, AuD
(Clinical Doctorate in Audiology), PhD in Speech and Language Science, and PhD in Hearing Science.
The School has a solid commitment to international collaboration and ample external clinical
research sites throughout the US and internationally. The School has a rich track record of active
interdisciplinary engagement. Faculty, graduate student and postdoctoral scholar backgrounds
represent a rich array of credentials, education and experience in diverse areas.
The School is one of six schools in the College of Health and Human Services. The College is housed
in Grover Center, a recently remodeled academic facility housing offices and research laboratories
for faculty, "smart" classrooms, a fitness/wellness center, and a spacious state-of-the-art
Hearing, Speech and Language Clinic.  The clinic includes ample diagnostic and treatment materials
and clinical technology.   Additional information about the school and community may be accessed
at: http://www.hhs.ohiou.edu/hsls/. Ohio University is a state-assisted Doctoral Research-Extensive
university with 20,000 students on its picturesque Athens campus and 8,500 students on five
regional campuses.
Qualifications: A Ph.D. and strong interests in aphasia and other neurogenic communication
disorders in adults are required. Demonstrated educational and research background in one or more
of the following areas is desired: communication sciences and disorders, speech-language pathology,
cognitive science, linguistics, psychology, and/or biomedical engineering.
Starting Date: Negotiable. Desired start date is January 1, 2010.
Salary and Benefits: Salary is commensurate with qualifications and experience.  The position is
for a twelve-month appointment, with possible renewal.  Postdoctoral scholars are provided office
space and access to the Ohio University Neurolinguistics Laboratory. University benefits include
tuition for employee plus qualified dependents, a comprehensive insurance package (prescription
plan, vision benefits, dental plan, and life insurance), and a retirement program.
Application:  A completed application includes: a curriculum vitae, a letter specifically
describing how qualifications and accomplishments fit the requirements of the position, and the
names, titles, addresses, and telephone numbers of three current references.  Candidates from
underrepresented groups are encouraged to apply.  All applicants must complete the on-line Quick
Application at: www.ohiouniversityjobs.com/applicants/Central?quickFind=55481
For additional information, contact Brooke Hallowell, Ph.D., Director, School of Hearing, Speech
and Language Sciences. E-mail: hallowel at ohio.edu Address: W218 Grover Center, Ohio University,
Athens, OH 45701 USA	Telephone: 740-593-1356 	Fax: 740-593-0287
Application Timeframe: Apply by November 30, 2009 for optimal consideration. Review begins
immediately and continues until position is filled.
Ohio University is an Equal Opportunity/Affirmative Action Employer
Brooke Hallowell, Ph.D., CCC-SLP, F-ASHA
Director, School of Hearing, Speech and Language Sciences
President Elect, Council of Academic Programs in Communication Sciences and Disorders
W218 Grover Center
Athens, OH  45701


Noise demonstration outside of Alameda County Jail raises ruckus in solidarity with SHU hunger strikers.
On July 1, 2011...thousands of other prisoners went on hunger strike to protest such draconian conditions. As reported in Truthout last year, for three weeks, at least 1,035 of the 1,111 inmates locked in the SHU refused food. In the SHU, which comprises half of California's Pelican Bay State Prison, prisoners are locked into their cells for at least 22 hours a day. Over 500 people have been confined in the SHU for over a decade, over 200 for more than 15 years and 78 for over 20 years. The only way that a person can be released from the SHU is to debrief, or provide information incriminating other prisoners. Even those who are eligible for parole have been informed that they will not be granted parole so long as they are in the SHU. "They are told they can debrief or die..." The Pelican Bay hunger strike spread to 13 other state prisons and, at its height, involved at least 6,600 people incarcerated throughout California.
Tonight, marchers played music, passed out informational flyers, wrote graffiti slogans and put up informational stickers, and upon reaching the jail on 7th and Clay streets, shot off fireworks for about 20 minutes. The fireworks lit up the night sky and prisoners responded by throwing up raised fists in the window and turning lights on and off to let those know outside that they could hear them. Someone spray painted in large letters across the front of the building, "Fire to the Prisons!" After the fireworks had been shot off, people returned to the plaza and held the intersection of 14th and Broadway for about 20 minutes before dispersing.