Thursday, January 24, 2013

JSF 2.x Tip of the Day: AJAX Redirection from @WebFilter (Filter)

I was working on an application where I needed to have it redirect to a login page when certain conditions exist in the application, e.g. session timeout, etc. A ViewExpiredException custom exception handler (available in JSF 2.0) can handle this case, but I had a need for another type of "Session" object to be monitored to determine if I should redirect based on its status. The other object was stored in the HttpSession object as an attribute so I decided to handle it with a Filter (@WebFilter).

The first thing is to determine if the request is a partial/ajax request. If it is a normal post, we can handle it with a HttpResponse.sendRedirect(String location) mechanism. If it is AJAX, we need to handle it in a completely different manner.
1
2
3
4
5
6
7
8
private boolean isAJAXRequest(HttpServletRequest request) {
    boolean check = false;
    String facesRequest = request.getHeader("Faces-Request");
    if (facesRequest != null && facesRequest.equals("partial/ajax")) {
        check = true;
    }
    return check;
}
Once I determined that the request was AJAX, I needed to be able to pass the appropriate response back to the JSF page in a format that it could understand. A great tip came from Jim Driscoll's blog: Redirecting from a JSF 2.0 Ajax Request which gave me the general syntax for what I needed to send back.

Note: This is being intercepted in a Filter so I don't have access to the FacesContext. Here is a partial code snippet of how to send the redirect. You would need to set the variable TARGET to go to the desired location.
1
2
3
4
5
6
7
8
9
10
11
12
String redirectURL = response.encodeRedirectURL(request.getContextPath() + TARGET);
 
if (isAJAXRequest(request)) {
    StringBuilder sb = new StringBuilder();
    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><partial-response><redirect url=\"").append(redirectURL).append("\"></redirect></partial-response>");
    response.setHeader("Cache-Control", "no-cache");
    response.setCharacterEncoding("UTF-8");
    response.setContentType("text/xml");
    PrintWriter pw = response.getWriter();
    pw.println(sb.toString());
    pw.flush();
}

Monday, January 14, 2013

GlassFish 3 Tip of the Day: Using JDK 7 with JSP Code

A question came up on the NetBeans J2EE Mailing List about using JDK 7 with GlassFish 3.1.2. Specifically, they were getting the error:
org.apache.jasper.JasperException: PWC6033: Error in Javac compilation for JSP
PWC6197: An error occurred at line: 4 in the jsp file: /index.jspPWC6199: Generated servlet error:strings in switch are not supported in -source 1.5  (use -source 7 or higher to enable strings in switch)

The fix is quite simple. You must include a glassfish-web.xml file in your project, and set a couple of properties. compilerSourceVM and compilerTargetVM.

Please see the example below for a complete configuration.
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
  <class-loader delegate="true"/>
  <jsp-config>
    <property name="keepgenerated" value="true">
      <description>Keep a copy of the generated servlet class' java code.</description>
    </property>
    <property name="compilerSourceVM" value="7"/>
    <property name="compilerTargetVM" value="7"/>
  </jsp-config>
</glassfish-web-app>

The project will now compile and use JDK7.

Friday, January 11, 2013

JSF 2.x Tip of the Day: RichFaces Table Sorting (3-position switch design)

A technique I like to call the three position switch is what I use for sorting on my RichFaces tables. This consists of default (unsorted), ascending, and descending. It is implemented very easily by setting the <rich:column/> sortOrder attribute to point to our current sort, and using an <a4j:commandLink> in the header facet to control the sort as shown in the example below. This simple technique makes sorting simple and sexy.

code

1
2
3
4
5
6
<rich:column sortBy="#{customer.name}" sortOrder="#{complexDataTable.sorting}">
    <f:facet name="header">
        <a4j:commandLink render="dataTable" value="#{complexDataTable.customerColumnHeader}" action="#{complexDataTable.sort()}"/>
    </f:facet>
    <h:outputText value="#{customer.name}"/>
</rich:column>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private SortOrder sorting = SortOrder.unsorted;
 
public SortOrder getSorting() {
    return sorting;
}
 
public void setSorting(SortOrder sorting) {
    this.sorting = sorting;
}
 
public void sort() {
    switch (sorting) {
        case unsorted: {
            sorting = SortOrder.ascending;
            break;
        }
        case ascending: {
            sorting = SortOrder.descending;
            break;
        }
        case descending: {
            sorting = SortOrder.unsorted;
            break;
        }
    }
}

This additional code will let the user know which sorting direction we are currently using.
1
2
3
4
5
6
7
8
9
10
public String getCustomerColumnHeader() {
    switch (sorting) {
        case unsorted: {
            return "Customer Name";
        }
        default: {
            return "Customer Name (" + sorting + ")";
        }
    }
}

JSF 2.x Tip of the Day: Programmatically Creating a <h:outputText/>

In this tip of the day we create one of the most basic components in our JSF arsenal: <h:outputText>.
This example uses another library called jsf-utils to handle the heavy lifting.
1
2
3
4
5
public HtmlOutputText createHtmlOutputText(final FacesContext context, final String valueValueExpression, Class<?> valueType) {
    HtmlOutputText text = (HtmlOutputText) context.getApplication().createComponent(HtmlOutputText.COMPONENT_TYPE);
    text.setValueExpression("value", JSFUtils.createValueExpression(valueValueExpression, valueType));
    return text;
}

JSF 2.x Tip of the Day: RichFaces Programmatically Creating an <a4j:commandLink/>

This example of how to create an <a4j:commandLink/> uses another library called jsf-utils to handle the heavy lifting.

The method below will create the <a4j:commandLink/> component, any additional configuration will need to be performed programmatically, or using the tag attributes.

1
2
3
4
5
6
7
8
public UICommandLink createUICommandLink(final FacesContext context, final String value, final String render, final String methodExpression) {
    Class<?>[] clazz = new Class<?>[]{};
    UICommandLink link = (UICommandLink) context.getApplication().createComponent(UICommandLink.COMPONENT_TYPE);
    link.setValue(value);
    link.setRender(render);
    link.setActionExpression(JSFUtils.createMethodExpression(methodExpression, String.class, clazz));
    return link;
}
You would bind it to a backing bean to a UICommandLink component;
1
<a4j:commandLink binding="#{indexBean.commandLink1}"/>

Thursday, January 10, 2013

JSF 2.x Tip of the Day: Determining the Base URL

This question has come up a couple of times in the last few days, so I thought I would write a couple of convenience methods to determine the Base URL.

I added them to my jsf-utils project for those who want to use my utilities.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
 * <p>Determines the Base URL, e.g.,
 * {@literal http://localhost:8080/myApplication} from the
 * {@link FacesContext}.</p>
 *
 * @param facesContext The {@link FacesContext} to examine.
 * @return the base URL.
 * @throws MalformedURLException if an exception occurs during parsing of
 * the URL.
 * @since 1.3
 */
public String getBaseURL(final FacesContext facesContext) throws MalformedURLException {
    return getBaseURL(facesContext.getExternalContext());
}
 
/**
 * <p>Determines the Base URL, e.g.,
 * {@literal http://localhost:8080/myApplication} from the
 * {@link ExternalContext}.</p>
 *
 * @param externalContext The {@link ExternalContext} to examine.
 * @return the base URL.
 * @throws MalformedURLException if an exception occurs during parsing of
 * the URL.
 * @since 1.3
 */
public String getBaseURL(final ExternalContext externalContext) throws MalformedURLException {
    return getBaseURL((HttpServletRequest) externalContext.getRequest());
}
 
/**
 * <p>Determines the Base URL, e.g.,
 * {@literal http://localhost:8080/myApplication} from the
 * {@link HttpServletRequest}.</p>
 *
 * @param request The {@link HttpServletRequest} to examine.
 * @return the base URL.
 * @throws MalformedURLException if an exception occurs during parsing of
 * the URL.
 * @see URL
 * @since 1.3
 */
public String getBaseURL(final HttpServletRequest request) throws MalformedURLException {
    return new URL(request.getScheme(),
            request.getServerName(),
            request.getServerPort(),
            request.getContextPath()).toString();
}

Wednesday, January 09, 2013

JSF 2.x Tip of the Day: Displaying Content Conditionally by FacesMessage.Severity

Many times we do, or do not want to display content based on whether there are FacesMessage queued to be displayed. The FacesMessage.Severity can be used to help us determine if messages should be displayed. Please see the table below.

FacesMessage Values
Ordinal Severity
0 INFO
1 WARN
2 ERROR
3 FATAL


The examples below demonstrate a couple of techniques to determine if a component (in this case a <ui:fragment/> containing a <ui:include/>) should be displayed based on whether FacesMessage.Severity are present and if they are not equal to an informational message.

1
2
3
<ui:fragment rendered="#{empty facesContext.maximumSeverity or facesContext.maximumSeverity eq FacesMessage.SEVERITY_INFO}" >
    <ui:include src="somePage.xhtml"/>
</ui:fragment>
This is equivalent to the listing above.
1
2
3
<ui:fragment rendered="#{empty facesContext.maximumSeverity or facesContext.maximumSeverity.ordinal eq 0}" >
    <ui:include src="somePage.xhtml"/>
</ui:fragment>
This displays if the messages are WARN or less.
1
2
3
<ui:fragment rendered="#{empty facesContext.maximumSeverity or facesContext.maximumSeverity.ordinal le 1}" >
    <ui:include src="somePage.xhtml"/>
</ui:fragment>

Tuesday, January 08, 2013

Internet Explorer 9 (IE9) Table White Space Issues

I was tasked with fixing a problem in our product where one of our data tables (HTML) was rendering on IE9 with spaces randomly scattered throughout the table this resulted in the data being in the wrong columns, or headers appearing in the wrong place. I originally thought I might there might be "holes", or null values in my data which was resulting in the error. I was wrong.

It is actually a bug in IE9.

The issue shows up, most often, when using AJAX when there is partial page rendering. It seems according to forum remarks to be focused on white space between table tag elements like line breaks, spaces, or carriage returns. So if you use HTML tidy, you will screw up your output. Nice one Microsoft!

Fortunately, there are "fixes" out there to help you get along. Here is the fix which I slightly modified from an answer on stackoverflow. A shout out goes to Blago for his recursive function listed below.
1
2
3
4
5
6
7
8
9
10
11
12
jQuery.fn.htmlClean = function() {
    this.contents().filter(function() {
        if (this.nodeType != 3) {
            $(this).htmlClean();
            return false;
        }
        else {
            return !/\S/.test(this.nodeValue);
        }
    }).remove();
    return this;
}

You can implement it this way.
1
$('#myTable').htmlClean();
Here are some references on the issue if you are interested.

Monday, January 07, 2013

RichFaces 4.2.x: Unique <rich:dataTable/> Design

In my current job, I have opportunities to do Proof-of-Concept for various new JSF ideas for our products. I often do a lot of these general experiments on my own time after hours at home. That is not unusual I would imagine for most developers. A couple of months ago I was tasked with trying to generate a table dynamically using RichFaces 4. In RichFaces 3, you could provide dynamic columns and have it generate the table columns and data dynamically. This functionality is currently not available in RichFaces 4.2.

I came up with a strange amalgamation of bed-mates which worked. It is an interesting approach to getting around various problems encountered developing tables.

An additional requirement was the ability to sort the data displayed in the table. Since our application at work does BI analytics, doing server side sorting is much slower and expensive than doing it client side. This problem was partially solved with JQuery and a plugin called TableSorter. I think it will work on most basic tables, and this one... well is no different.

Are you ready for some magic?

Data Table Design #3


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      xmlns:c="http://java.sun.com/jsp/jstl/core"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:rich="http://richfaces.org/rich">
    <h:head>
        <title>Data Table Design #3</title>
    </h:head>
    <h:body>
        <h:form id="form1">
            <rich:dataTable id="dataTable3" value="#{indexBean.customers}" var="customer"
                            rowKeyVar="idx" styleClass="tablesorter">
                <c:forEach items="#{indexBean.customerByIndex(idx)}" var="cx">
                    <f:facet name="header">
                        <rich:columnGroup>
                            <rich:column colspan="2">
                                <h:outputText value="Customers"/>
                            </rich:column>
                            <rich:column breakRowBefore="true">
                                <h:outputText value="Name"/>
                            </rich:column>
                            <rich:column>
                                <h:outputText value="Phone"/>
                            </rich:column>
                        </rich:columnGroup>
                    </f:facet>
                    <rich:column>
                        <h:outputText value="#{cx.name}"/>
                        <f:facet name="footer">
                            Number of Customers: #{indexBean.customers.size()}
                        </f:facet>
                    </rich:column>
                    <rich:column>
                        <h:outputText value="#{cx.phone}"/>
                        <f:facet name="footer"/>
                    </rich:column>
                </c:forEach>
            </rich:dataTable>
            <rich:jQuery/>
            <h:outputScript name="jquery.tablesorter.js" library="js"/>
            <script type="text/javascript">
                $(document).ready(function(){ $('#form1\\:dataTable3').tablesorter();});
            </script>
        </h:form>
    </h:body>
</html>

Now that you have a chance to look at the XHTML file, I am sure you noticed some strange things like a mix of <c:forEach/> wrapping a number of <rich:column/> components inside a <rich:dataTable/>. This is the normal configuration that you might see. Also, we have added a <rich:jQuery/< component along with our JavaScript. Yes, it works. The data is pulled from JPA and displayed. It also elegantly sorts on all of the columns. The only strange code is the EL code in the <c:forEach/> for the items attribute. Since the <c:forEach/> is expecting an array, or a Collection (List) to iterate over, we must provide it a customer in that format.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private List<customer> customers;
public List<customer> getCustomers() {
    return customers;
}
 
public void setCustomers(List<customer> customers) {
    this.customers = customers;
}
 
public List<customer> customerByIndex(final int index) {
    List<customer> customer = new ArrayList<customer>();
    customer.add(customers.get(index));
    return customer;
}


I thought about deleting the design, but it actually works and may help someone solve a problem so I am publishing it.

I will publish all of the other designs once they are cleaned up in project for download.

Sunday, January 06, 2013

JSF 2.1 Tip of the Day: Programmatically Creating a <h:commandButton/>

I have been doing a lot of work on JSF lately including making custom components. It seems like the whole process of creating custom components looks like some arcane arts. It almost seems like black magic in some cases.

I thought I would share some of the things I have discovered over time in an attempt to help others avoid some of the pitfalls I have come across.
This JSF Tip of the Day is an amalgamation of a couple of tips: JSF 2.x Tip of the Day: Programmatically Creating EL ValueExpression and JSF 2.x Tip of the Day: Programmatically Creating EL MethodExpression which are combined with this tip.

In this tip we will create a <h:commandButton/> programmatically. The code from the previous tips noted, are used to create the component.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.bluelotussoftware.example.jsf;
 
import com.bluelotussoftware.jsf.utils.JSFUtils;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.Application;
import javax.faces.component.html.HtmlCommandButton;
import javax.faces.context.FacesContext;
import javax.inject.Named;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
@Named
@SessionScoped
public class CommandBean implements Serializable {
 
    private static final long serialVersionUID = -7866778404577507805L;
    private HtmlCommandButton commandButton;
    private String UUID;
 
    @PostConstruct
    private void init() {
        commandButton = createCommandButton(FacesContext.getCurrentInstance(),
                "#{commandBean.generateUUID()}", "Generate UUID");
    }
 
    public HtmlCommandButton getCommandButton() {
        return commandButton;
    }
 
    public void setCommandButton(HtmlCommandButton commandButton) {
        this.commandButton = commandButton;
    }
 
    public String getUUID() {
        return UUID;
    }
 
    public void setUUID(String UUID) {
        this.UUID = UUID;
    }
 
    private HtmlCommandButton createCommandButton(final FacesContext context,
            final String methodExpression, final String value) {
        Application application = context.getApplication();
        Class<?>[] clazz = new Class<?>[]{};
        HtmlCommandButton htmlCommandButton =
                (HtmlCommandButton) application.createComponent(HtmlCommandButton.COMPONENT_TYPE);
        htmlCommandButton.setValue(value);
        htmlCommandButton.setActionExpression(JSFUtils.createMethodExpression(methodExpression, String.class, clazz));
        return htmlCommandButton;
    }
 
    public String generateUUID() {
        UUID = java.util.UUID.randomUUID().toString();
        return null;
    }
}
The component is bound using the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title><h:commandButton/> Binding</title>
    </h:head>
    <h:body>
        <h:form>
            <h:outputText value="#{commandBean.UUID}"/>
             
 
            <h:commandButton binding="#{commandBean.commandButton}"/>
        </h:form>
    </h:body>
</html>

Saturday, January 05, 2013

Using GlassFish 3.1.1 Embedded with JUnit 4.x and HtmlUnit 2.x

Introduction

I was looking for an example of how to use GlassFish Embedded Maven plugin to integrate with HtmlUnit(JUnit) for doing testing. I was surprised that I really didn't find anything that seemed very complete. There were a number of examples that showed how to use the Embedded EJB Container in tests, but nothing that really showed how to use the Maven plugin. While searching I came across a question on stackoverflow asking how about Unit testing a Java Servlet. I decided to kill two birds with one stone; (1) write up a good example for Glassfish, and (2) help someone else with a complete solution

The testing here is implemented as part of the integration-test lifecycle of Maven. This does not replace standard JUnit testing of your code, but rather provides testing of your web application as you would expect in deployment. Consider this a valuable supplement to your testing strategy.

The complete project is located here: image-servlet.

Requirements

  1. First make sure that you configure the Maven plugin. Complete details can be found in Oracle GlassFish Server Embedded Server Guide
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    <build>
        <plugins>
            <plugin>
                <groupId>org.glassfish</groupId>
                <artifactId>maven-embedded-glassfish-plugin</artifactId>
                <version>3.1.1</version>
                <configuration>
                    <!-- This sets the path to use the war file we have built in the target directory -->
                    <app>target/${project.build.finalName}</app>
                    <port>8080</port>
                    <!-- This sets the context root, e.g. http://localhost:8080/test/ -->
                    <contextRoot>test</contextRoot>
                    <!-- This deletes the temporary files during GlassFish shutdown. -->
                    <autoDelete>true</autoDelete>
                </configuration>
                <executions>
                    <execution>
                        <id>start</id>
                        <!-- We implement the integration testing by setting up our GlassFish instance to start and deploy our application. -->
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>start</goal>
                            <goal>deploy</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>stop</id>
                        <!-- After integration testing we undeploy the application and shutdown GlassFish gracefully. -->
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>undeploy</goal>
                            <goal>stop</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
       </plugins>
    </build>
  2. Next, configure the surefire plugin to skip its normal test cycle.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.12.4</version>
        <!-- We are skipping the default test lifecycle and will test later during integration-test -->
        <configuration>
            <skip>true</skip>
        </configuration>
        <executions>
            <execution>
                <phase>integration-test</phase>
                <goals>
                    <!-- During the integration test we will execute surefire:test -->
                    <goal>test</goal>
                </goals>
                <configuration>
                    <!-- This enables the tests which were disabled previously. -->
                    <skip>false</skip>
                </configuration>
            </execution>
        </executions>
    </plugin>
  3. Add a dependencies for JUnit and HtmlUnit to the pom.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <dependency>
        <groupid>junit</groupId>
        <artifactid>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupid>net.sourceforge.htmlunit</groupId>
        <artifactid>htmlunit</artifactId>
        <version>2.11</version>
        <scope>test</scope>
    </dependency>
  4. Write your tests. This is one example.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Test
    public void notFound() throws IOException {
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
        webClient.getOptions().setPrintContentOnFailingStatusCode(false);
        final HtmlPage page = webClient.getPage("http://localhost:8080/test/images/abc.png");
        final WebResponse response = page.getWebResponse();
        assertEquals(404, response.getStatusCode());
        assertEquals("abc.png was not found.", response.getStatusMessage());
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(true);
        webClient.getOptions().setPrintContentOnFailingStatusCode(true);
        webClient.closeAllWindows();
    }
  5. Execute mvn:install.

Conclusion

You should see the GlassFish server start, deploy your application, execute the unit tests, undeploy the application, and shutdown gracefully.

There is a complete project on Bitbucket which demonstrates the entire process from start to finish doing a complete set of integration tests using HtmlUnit.

The project was developed using NetBeans 7.2.1, and GlassFish 3.1.2.

The complete project is located here: image-servlet.

Java Tip of the Day: Converting an InputStream to a BufferedImage

I was looking for a standard way using the JDK to convert an InputStream into a BufferedImage as part of a JUnit test. The solution was quite simple using ImageIO.

Code

1
2
3
4
5
6
7
public BufferedImage convertInputStreamToBufferedImage(final InputStream is) throws IOException {
    BufferedImage image = null;
    if (is != null) {
        image = ImageIO.read(is);
    }
    return image;
}

Wednesday, January 02, 2013

<ui:repeat/>, Templates, and @ConversationScope

Fishy Dates
I was going through stackoverflow when I came across: ui:repeat does not work in JSF 2.0? I know that their had been some issues which I detailed in JSF Tip of the Day: <ui:repeat /> Usage Example so I took a look. I resolved the basic issue and printed out a pretty page with some data. The solution is  on  stackoverflow so I won't repeat myself too much.

The modified version which includes a conversation portion and some other bells and whistles is available for download.

The code for the solution is available stackoverflow-uirepeat-example

The project was developed using NetBeans 7.2.1 on GlassFish 3.1.2 on JSF 2.1 (Mojarra) and Weld 1.0.




Popular Posts