Java Forum / General / July 2006
Recommendations for a web application framework?
Alan Meyer - 05 Jul 2006 22:18 GMT We're starting a new project to put an interactive data entry and publishing system on the web. Users will enter inputs of many types and will get back responses from a database depending on their inputs. The system will be developed using Linux, Java, JSP, and MySQL.
There are a number of Java based web application frameworks that look like they might reduce the total effort involved in the task. Some that I've briefly looked at include:
Struts "classic" (currently version 1.2.8) Struts Shale (currently 1.2.9) Webwork (currently 2.2.2 and eventually to become Struts 2.0) Spring (currently 1.2.8 but 2.0 in release candidate form)
There are others too, including one called Tapestry, that I have not looked at.
My impressions so far are:
Struts "classic" is far and away the most used of the frameworks, but also the oldest technology and development appears to be slowing down or ending.
Webwork is thought by the Struts team to be better than Struts, which is why they are switching to it.
Spring is second in popularity. It appears to included component parts that are sometimes selected out and used with other frameworks.
Shale is the most "different" of the group.
The whole Struts heritage - classic, Shale, and Webwork - is in a state of some confusion. It is not clear where the majority of Struts users will go and which of the projects will have long term continued support.
My criteria for selection are:
1. Robustness. We don't want to fight a lot of bugs in the code.
2. Community support. We would like an active user and developer community and hope that the framework doesn't become obsolete and abandoned.
3. Power. We want something that saves us development time.
4. Flexibility. We want a framework that allows us to do whatever needs to be done, even if it turns out that the original framework designers didn't contemplate doing this thing.
5. AJAX support. We're very interested in this new technology and would like the package we select to both integrate well with it and make it easy to use.
Does anyone have recommendations for us - either for or against any particular package?
Thanks.
Alan
Danno - 05 Jul 2006 22:30 GMT > We're starting a new project to put an interactive data entry and > publishing system on the web. Users will enter inputs of many [quoted text clipped - 59 lines] > > Alan I like what stripes is offering as far as what you need, it is lightweight and flexible, and you don't need to marry another technology or thought.
Alan Meyer - 06 Jul 2006 01:04 GMT > ... > I like what stripes is offering as far as what you need, it is > lightweight and flexible, and you don't need to marry another > technology or thought. Yipes! Stripes!
I didn't even know that one existed. But I'll probably stay more mainstream. Trying to evaluate everything takes more effort than I can afford.
Thanks.
Alan
Timo Stamm - 06 Jul 2006 08:43 GMT Alan Meyer schrieb:
>> ... >> I like what stripes is offering as far as what you need, it is [quoted text clipped - 6 lines] > mainstream. Trying to evaluate everything takes more effort > than I can afford. There are several dozens of java web frameworks, and they are all different. It would take you months to get to know them all.
I recommend having a look at Wicket (http://wicket.sourceforge.net). It's features are:
- Very clean separation of HTML and Java code - the HTML can be edited with WYSIWYG editors without any side-effects.
- Component-oriented - very good reusability.
- Plain old Java - no XML configuration files, no programming in XML.
Chris Smith - 05 Jul 2006 23:01 GMT > There are a number of Java based web application frameworks that > look like they might reduce the total effort involved in the [quoted text clipped - 7 lines] > There are others too, including one called Tapestry, that I have > not looked at. Tapestry is popular, but there's a far more important option that you've left off, and that's plain JSF. JSF is a very powerful framework for developing web applications, and is quite competitive with all of the options above.
A few notes about Shale: (Note: this is contentious and admittedly exaggerated.) Essentially, Shale is an ego-trip by a few people who had the courage to understand that JSF is a powerful framework that meets most web application development needs, but then lapsed back into the past. It offers strange mixes of JSF with alternative designs, and the result is really rather a big mess. Essentially, you've got a core of JSF, plus:
1. ViewController backing beans, because we couldn't quite face the death of Action classes or understand event-based programming.
2. Dialog Manager, because we couldn't quite get our hands off the navigation system.
3. Tiles integration, because even though custom tag files have made Tiles irrelevant for new projects, Mr. Geary can't let go.
4. Application Manager, because we really need TWO different simultaneous request processing lifecycles. (Subtitle: also because some of us were just too attached to the Commons Chain project and thought it'd be fun to add another unnecessary dependency on an external project.)
5. Remoting: We wanted to say we support AJAX, but we haven't quite figured out how yet... and meanwhile, ajax4jsf has implemented a quite flexible JSF/AJAX framework, but we didn't know that was going to happen when we started.
6. Clay, because we decided we really don't like JSF too awfully much anyway.
And then there's the one useful feature, which is Commons Validator integration. At one point, it was possible to extract that out and use it without the rest of Shale... but I'm not quite sure about the current status of that approach.
So anyway, I'd look into JSF and the ajax4jsf project from SourceForge, both of which are thriving and quite a popular and fully-featured way to handle development of web applications.
> The whole Struts heritage - classic, Shale, and Webwork - is > in a state of some confusion. It is not clear where the > majority of Struts users will go and which of the projects > will have long term continued support. This is largely due to the influence of JSF, which is now a standard technology that's part of J2EE, available out of the box on all current versionsof application servers and freely available where it's not already there, and meets basically all of the major needs that drove people to these third-party frameworks in the past.
Nevertheless, there are definite advantages to some of the alternative frameworks. Spring-MVC is obviously going to integrate better with a Spring-based back end. Tapestry is a little lighter-weight in terms of its impact on your view layer development. I'd avoid Shale or Struts Classic. I don't know much about WebWork at this point.
 Signature Chris Smith - Lead Software Developer / Technical Trainer MindIQ Corporation
Alan Meyer - 06 Jul 2006 01:06 GMT Chris,
Thank you very much for the candid comments.
One of the problems we have in reading evaluations is that most writers bend over backwards to be fair to everyone - which is good in a way. But sometimes a little candor is more helpful.
Alan
jamespcooper@gmail.com - 06 Jul 2006 04:46 GMT Alan,
I would concur that JSF is definitely worth looking into. Be aware that JSF requires Javascript to be enabled on the client. If you turn off Javascript in your browser commandLink and commandButton controls (i.e. all JSF aware URLs and form submit buttons) will no longer work.
-- James
David Segall - 06 Jul 2006 15:23 GMT >We're starting a new project to put an interactive data entry and >publishing system on the web. Users will enter inputs of many [quoted text clipped - 13 lines] >There are others too, including one called Tapestry, that I have >not looked at. Did you have a reason for omitting Java Server Faces? I confess that I "chose" it because it is the required framework for using Sun's web application RAD tool <http://developers.sun.com/prodtech/javatools/jscreator/index.jsp>. However, it seems to be the framework of choice both at Sun <http://java.sun.com/javaee/javaserverfaces/index.jsp> and at Oracle <http://www.oracle.com/technology/obe/ADF_tutorial_1013/index.htm>.
Alan Meyer - 06 Jul 2006 20:21 GMT > ... > Did you have a reason for omitting Java Server Faces? I confess that I [quoted text clipped - 4 lines] > <http://java.sun.com/javaee/javaserverfaces/index.jsp> and at Oracle > <http://www.oracle.com/technology/obe/ADF_tutorial_1013/index.htm>. I did not have a good reason for omitting it. Since you're the second person recommending it, I am looking into it.
Do you or Chris think that using JSF is better than using, say, Webwork or Spring? Or perhaps that it's just another approach?
In your use of JSF, have you ever felt that it forbids you from doing something that you really think you should do?
Thanks.
Alan
Chris Smith - 06 Jul 2006 21:10 GMT > Do you or Chris think that using JSF is better than using, say, > Webwork or Spring? Or perhaps that it's just another approach? I definitely feel that JSF is a better idea than Spring-MVC. I don't know much about WebWork, but I'm pretty skeptical of new revolutionary web application frameworks these days. One huge advantage of JSF (in my view) that applies versus most anything else is that it is the standard framework for web application development with Java. As such, I would need a pretty good reason to switch away from it. I haven't seen anything else that really is such a good reason.
JSF does an excellent job of separation of concerns. Although this has been a major motivating goal of pretty much all major web application frameworks, all of them that I've seen have fallen short until JSF came around. With JSF, I can actually build my entire Java code without having to think about the view layer at all; and I can build the view layer while only worrying about the specific set of documented properties and methods of backing beans. In almost everything else, you have to do this naming convention junk between "form beans" and HTML forms, and the form beans are not really all that abstracted from basic HTTP parameter handling. With JSF, all that logic goes into the view layer, whether it's JSPs or component implementations, and properly converted and meaningful data is injected into backing beans from the view, which the application can then handle from appropriate event handlers. That's a HUGE advantage. Perhaps it sounds a tad trivial, but it eliminates the biggest pains of real-world application development when you no longer have to maintain simultaneous naming conventions between Java code and JSP pages.
> In your use of JSF, have you ever felt that it forbids you from doing > something that you really think you should do? There are three major disadvantages to JSF:
a) It is a bit too intrusive on the view layer. While views can be developed separately from application logic, they do need to be developed using JSF components instead of HTML tags. This means that if your model has been to have your graphic design department build HTML pages and then go make the minimal changes to incorporate them into the application, you'll have to change that a bit. Tapestry does a better job of being unobtrusive, but at the cost of complexity elsewhere.
b) It limits your potential technology support and your use of the full range of HTTP features. The two biggest limitations are that JSF currently doesn't work at all with GET-style HTTP requests (unless this has changed in 1.2), and that the JSP component bindings pretty well require that the client have JavaScript enabled.
c) The Java APIs are rather weak in abstraction. The implementation details of the container show through in a lot of places. This is unnecessary, and makes JSF code appear messy sometimes.
 Signature Chris Smith - Lead Software Developer / Technical Trainer MindIQ Corporation
Alan Meyer - 06 Jul 2006 22:43 GMT Thanks Chris. That's an excellent reply to my questions.
I appreciate your help.
Alan
Timo Stamm - 06 Jul 2006 23:37 GMT Chris Smith schrieb:
>> Do you or Chris think that using JSF is better than using, say, >> Webwork or Spring? Or perhaps that it's just another approach? [quoted text clipped - 8 lines] > > JSF does an excellent job of separation of concerns. Do you mean separation of HTML and Java or separation of business objects and view code? In my opinion, even PHP template libraries like TAL do a better job of separation in both respects than JSF.
> [...] With JSF, I can actually build my entire Java code without > having to think about the view layer at all; [...] In almost everything > else, you have to do this naming convention junk between "form beans" > and HTML forms, and the form beans are not really all that abstracted > from basic HTTP parameter handling. That's Struts. But Struts is the oldest (and most outdated) of all Java Web Frameworks I know. There are many Frameworks that hide HTTP entirely. With some, you don't even have to care about request-response cycles: Let's say that I want to display a number on a web page, and increase the number by 1 everytime the user clicks a link. Using Struts, you would probably store the value in the session.
In a more advanced framework, it might look like this:
Java code:
public class CounterPage extends WebPage {
public int counter = 0;
public CounterPage() { add(new Link("increase") {
public void onClick() { counter = counter + 1; } }); add(new Label("counter", new PropertyModel(this, "counter"))); } }
HTML:
<?xml version="1.0" encoding="UTF-8"?> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.sourceforge.net/"> <head> <title>Counter Page</title> </head> <body> <span wicket:id="counter">[counter value will appear here]</span> <a wicket:id="increase">increase counter</a> </body> </html>
Model and view are glued together by simple Classes. In this case, a OGNL expression is used.
JSF is just too complicated for my taste, but it certainly is the best choice for large applications because it is the official standard, has support of many vendors and a many available programmers.
Timo
Chris Smith - 07 Jul 2006 07:48 GMT > Do you mean separation of HTML and Java or separation of business > objects and view code? I meant separation of view code from application code. I try to avoid words like "business logic" or "business objects", but you could assume that we mean about the same thing. I did contribute some confusion, though, by saying "I can actually build my entire Java code..." when I really should have said that I can write the core application in a way independent of the user interface. JSF *does* include Java in the view module; but the interesting separation is between view and application logic, not between Java and JSP/HTML/etc.
> In my opinion, even PHP template libraries like > TAL do a better job of separation in both respects than JSF. I'm convinced, then, that we are talking about different things. TAL doesn't even get you halfway there. It's nothing more than an abbreviation language for encoding PHP control structures into special "tal:" attributes. It does nothing about the need to keep form parameter names in sync between code that uses them and HTML that generates them. It similarly does nothing about converting the data from weird HTML for encoding rules into reasonable high-level data structures in the web application. These are things that tie together application code and the view, and the manual maintenance is a huge source of hassles.
> That's Struts. But Struts is the oldest (and most outdated) of all Java > Web Frameworks I know. In a different form, it's also the Wicket example you posted, which has two id attributes in the page corresponding to the two components; and then a Java class representing that page, which again has to match the id attributes on components on the page. It's a little better than Struts, to be sure. Yet I still see this duality wherein there's a Java class representing the form.
> There are many Frameworks that hide HTTP > entirely. With some, you don't even have to care about request-response > cycles: For most common purposes, JSF could be included in that category. JSF does define a request processing lifecycle, but typical application code just defines event listeners and they get called at the right time. You have to know a few things (for example, say, that converters get called before validators) but this is more about the JSF model than HTTP request processing. The request processing lifecycle becomes more important when you're generating non-JSF content (such as dynamically generated images and such), or when you're pulling more advanced tricks such as when I wrote a JSF component to interact with JSF backing beans straight from JavaScript in a web page, and needed to prevent the rendering of an HTML response to that HTTP request. I wonder how I would have accomplished something like that if JSF hid the request processing lifecycle just a little more.
 Signature Chris Smith - Lead Software Developer / Technical Trainer MindIQ Corporation
Timo Stamm - 08 Jul 2006 14:23 GMT Chris Smith schrieb:
>> Do you mean separation of HTML and Java or separation of business >> objects and view code? > > I meant separation of view code from application code. I try to avoid > words like "business logic" or "business objects", but you could assume > that we mean about the same thing. I think so.
>> In my opinion, even PHP template libraries like >> TAL do a better job of separation in both respects than JSF. [quoted text clipped - 3 lines] > abbreviation language for encoding PHP control structures into special > "tal:" attributes. I admit that was an unjust exaggeration. TAL does a better job of separating the HTML Template from view code than JSP. But TAL certainly can't compete with JSF because it is just a template library, not a component oriented web framework.
>> That's Struts. But Struts is the oldest (and most outdated) of all Java >> Web Frameworks I know. [quoted text clipped - 5 lines] > Struts, to be sure. Yet I still see this duality wherein there's a Java > class representing the form. Unfortunately, you can not eliminate this duality if you want to use HTML templates and insert a value into a specific position in the template.
But with wicket, you could encapsulate the two components for the link and the output label into one component and you can use language features like inheritance to remove redundancy (yes, it works with HTML templates too because a HTML file is always associated with a java class).
>> There are many Frameworks that hide HTTP >> entirely. With some, you don't even have to care about request-response [quoted text clipped - 6 lines] > before validators) but this is more about the JSF model than HTTP > request processing. This is a major problem with JSF to me: You have to define a lot of classes and XML configuration files. You have to solve too many problems that are not part of the intrinsic problem, but are introduced by the framework that you utilize to solve the intrinsic problem.
The example I gave requires one additional class to represent the Application and one entry in the deployment descriptor to get it running. An implementation in JSF would probably require at least twice as many files. I feels like having to work for the framework instead of solving problems.
> The request processing lifecycle becomes more > important when you're generating non-JSF content (such as dynamically > generated images and such), or when you're pulling more advanced tricks > such as when I wrote a JSF component to interact with JSF backing beans > straight from JavaScript in a web page, and needed to prevent the > rendering of an HTML response to that HTTP request. Was that before JSF 1.2? As far as I understand, the "Avatar" Extension should make AJAX (forgive me using the buzzword) easier.
Timo
Chris Smith - 08 Jul 2006 17:21 GMT > > In a different form, it's also the Wicket example you posted, which has > > two id attributes in the page corresponding to the two components; and [quoted text clipped - 5 lines] > Unfortunately, you can not eliminate this duality if you want to use > HTML templates and insert a value into a specific position in the template. I think it is avoidable, and I think JSF does it.
To be perhaps a little clearer, what JSF does is ensure that the correspondence between identifiers and names in Java code and HTML content is one-way. That eliminates the really painful bit, which is to try and keep stuff in sync. I can actually write a JSF backing bean that encapsulates what I need to know in order to perform some task... and I really don't care whether the user interface gathers that information (a) with one component or another; (b) with a single HTML page or in a wizard-style interface across several pages; etc. Instead, I create and publish my interface in the form of a backing bean, and then the web design can be done along those lines. Those changes to the user interface part of the application are performed simply by binding different JSF components to different backing bean properties. The backing beans only need to be changed if there's a real change, such as the need to enter additional information that the application doesn't know how to handle yet.
> But with wicket, you could encapsulate the two components for the link > and the output label into one component and you can use language > features like inheritance to remove redundancy (yes, it works with HTML > templates too because a HTML file is always associated with a java class). It's exactly that -- an HTML file is always associated with a Java class -- that bothers me. I think that's a serious problem. My Java code shouldn't care what HTML files exist in the application.
> This is a major problem with JSF to me: You have to define a lot of > classes and XML configuration files. Hmm? In addition to the web application deployment descriptor, you have to add one XML file. I don't like XML for configuration too awfully much, but the actual information in that file is quite meaningful. It consists mainly of the navigation scheme between pages, and the model of information that is available to the pages. I actually wish these were in different files, since they express facts that are useful in different parts of the development process; but I imagine that didn't happen in order to avoid the issue of too many configuration files. In any case, you can still do things that way manually.
As for classes, I'm willing to wager that there are fewer classes involved in a JSF implementation of something that with anything that requires a Java class dual for each
Are you referring to the need to declare backing beans in faces-config.xml? That would be the key to avoiding the need for the class per web page model, in that it allows the view layer to access whatever data it needs based on declared interfaces; and conversely, the model layer to look in well-defined places for information regardless of what HTML page it came from.
> The example I gave requires one additional class to represent the > Application and one entry in the deployment descriptor to get it > running. An implementation in JSF would probably require at least twice > as many files. It would require:
1. WEB-INF/web.xml 2. WEB-INF/faces-config.xml 3. counter.jsp 4. WEB-INF/classes/.../CounterBean.java
Furthermore, none of these are really all that involved. web.xml would contain a mapping for the faces servlet, and possibly some configuration if you want to change the defaults. faces-config.xml would contain one navigation rule and one backing bean declaration for CounterBean. The counter.jsp file would contain the view code, and would bind the components to CounterBean via EL expressions. Finally, CounterBean would contain one method to increment the counter variable, and another to get the counter variable for display.
(The way I typically write JSF code, there would also be an index.jsp that just contains a single <jsp:forward> action. That's not necessary, but if it weren't there, you'd need to modify web.xml to change the welcome file list so that it loads "counter.jsf" by default.)
> Was that before JSF 1.2? As far as I understand, the "Avatar" Extension > should make AJAX (forgive me using the buzzword) easier. It was prior to JSF 1.2. I haven't looked into JSF 1.2 yet, though it's on my list of things to do this weekend.
 Signature Chris Smith - Lead Software Developer / Technical Trainer MindIQ Corporation
Timo Stamm - 08 Jul 2006 23:21 GMT Chris Smith schrieb:
>>> In a different form, it's also the Wicket example you posted, which has >>> two id attributes in the page corresponding to the two components; and [quoted text clipped - 11 lines] > content is one-way. That eliminates the really painful bit, which is to > try and keep stuff in sync. Yes, JSF avoids the duality because it doesn't really have templates. You don't have to bind a component to a position in the template, you define components directly in the JSP code using taglibs, and this introduces problems:
- It is impossible to use HTML mockups from a web designer without major changes that render them useless to the web designer.
- Browser incompatibilies are annoying. Having to debug them on a running application instead of the actual HTML file makes the issue worse.
- It forces you to express logic in a XML language. Java may have a verbose syntax, but it's still much better than XML, especially with a decent IDE.
> I can actually write a JSF backing bean > that encapsulates what I need to know in order to perform some task... [quoted text clipped - 8 lines] > the need to enter additional information that the application doesn't > know how to handle yet. The equivalent in the wicket world is called a "model object". But you don't access it from the template, but from the java code. There has been support to do make model properties available via OGNL (roughly similar to the JSP EL), but the usage is discouraged and I don't even know if the feature is still available.
>> But with wicket, you could encapsulate the two components for the link >> and the output label into one component and you can use language [quoted text clipped - 4 lines] > -- that bothers me. I think that's a serious problem. My Java code > shouldn't care what HTML files exist in the application. That is exactly what I was thinking when I had a first look at Wicket. I am somewhat allergic to redundancy and was very dubious about the need to tell the framework twice that I want a component there. But in practice, it really isn't an issue because there are so many ways to remove the redundancy and it isn't really as bad as it looks.
For example, I would create a base page class for a project, that contains common elements like navigation and a footer. This page class would be extended by the actual pages. The subclasses only have to take care of their contribution, and they may not even need any associated HTML files, because the HTML template associated with the super class is reused.
The same can be applied to components. You do not need a HTML template for each and every component.
In practice, I spend very little time maintaining the HTML templates.
>> This is a major problem with JSF to me: You have to define a lot of >> classes and XML configuration files. [quoted text clipped - 33 lines] > > Furthermore, none of these are really all that involved. I stand corrected, you don't have to define twice as many files.
My memory might have played me a trick, because working with JSF sure felt like having to do at least twice as much work :)
> web.xml would > contain a mapping for the faces servlet, Wicket requires the mapping for the wicket servlet, and the class name of the Application class.
> and possibly some configuration > if you want to change the defaults. You configure Wicket applications in the Wicket application class.
> faces-config.xml would contain one > navigation rule Not necessary. In Wicket, pages are plain Java objects and you can navigate with plain Java code:
setResponsePage(new MyPage());
If you really need to maintain navigation paths in an XML file, you can easily create you own method that looks the target up in an XML file. But I doubt that most real world application require this.
> and one backing bean declaration for CounterBean. Not necessary.
> The > counter.jsp file would contain the view code, This would be equivalent to the CounterPage.java + CounterPage.html files of my example. Wicket needs one more file.
> and would bind the > components to CounterBean via EL expressions. I don't need a CounterBean, just an int, but it has to be bound via OGNL (similar to EL).
> Finally, CounterBean > would contain one method to increment the counter variable, and another > to get the counter variable for display. Not necessary, I can simply override Link#onClick(). It would be trivial to write a Link component that uses it's id as a the name of a method that should be called on a model object, but I never needed to.
> (The way I typically write JSF code, there would also be an index.jsp > that just contains a single <jsp:forward> action. That's not necessary, > but if it weren't there, you'd need to modify web.xml to change the > welcome file list so that it loads "counter.jsf" by default.) In your Application class constructor:
setHomePage(MyHomePage.class);
But that was a very simple example. The fun starts when you want to create your own components to avoid copy-and-paste code.
It is quite some time ago that I worked with JSF, but I think these steps are necessary to create a new component (please correct me if I'm wrong):
- implement StateHolder
- define a renderer (no standard template system available)
- create component type identifier
- register the component in faces-config.xml using the class name and component type identifier
- create a custom tag library XML descriptor with all attributes, again repeating the class name and introducing yet another identifier
- add taglib in JSP header before using it
This list is missing event handling and composite components.
In contrast to this, let's have a look at what I have to do to combine the two components of my example into one reusable component:
- Create a new class and copy the code from CounterPage.
That's how it looks:
class CounterComponent extends WebMarkupContainer {
public int counter = 0;
public CounterComponent(String id) { super(id); add(new Link("increase") {
public void onClick() { counter = counter + 1; } }); add(new Label("counter", new PropertyModel(this, "counter"))); } }
That's how it will be used:
add(new CounterComponent("mycounter"));
I know that JSF has it's advantages, but it would be nice if it didn't make trivial stuff so very complicated.
Timo
David Segall - 08 Jul 2006 14:55 GMT >> ... >> Did you have a reason for omitting Java Server Faces? I confess that I [quoted text clipped - 10 lines] >Do you or Chris think that using JSF is better than using, say, >Webwork or Spring? Or perhaps that it's just another approach? I am too inexperienced with both web applications and Java to compare the frameworks you have listed. I regret to say that I have given you an exhaustive list of my reasons for choosing JSF above. My question about the omission was because I feared that I might have made a gross error with my choice.
>In your use of JSF, have you ever felt that it forbids you from doing >something that you really think you should do? As it happens I do have an example. I need to have users confirm their registration at a web site and the only convenient way I can think of is to send them a URL that includes GET method data. However, JSF seems to insist on POST method parameters. I have a solution but it is not very tidy.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|