Deploying

Last modified by superadmin on 2014/07/02 11:45

Deploying

Overview

Applications built with WaveMaker can be deployed to a number of environments, including local servers, public clouds, and private clouds. WaveMaker applications require a Java Web Server (for example: Tomcat, tc Server, WebSphere, WebLogic, JBoss, GlassFish). Java Web Servers host applications, which can be in the form of either a WAR (web application archive) file or an EAR (enterprise archive) file. WaveMaker generates both WAR and EAR files.

Before deploying a WaveMaker application, determine which type of server will be use to host the application. The primary options are:

  1. WaveMaker installation - the easiest and quickest deployment uses the Java Web Server included with WaveMaker. This approach is not recommended for production use. Use a WaveMaker installation to quickly share an application with your colleagues.
  2. Cloud Foundry - a public cloud that easily hosts WaveMaker applications
  3. Java Web Server - WaveMaker provides automated deployment to tcServer / Tomcat Java Web Servers. Deploy to other Java Web Servers (e.g. JBoss, GlassFish, WebLogic, or WebSphere) by using WaveMaker's WAR and EAR file generation feature. Java Web Servers may be installed locally or in a cloud environment.

WaveMaker Studio as Server

Run the Application

The easiest way to deploy a WaveMaker application is to press the Run button in WaveMaker Studio. When you press Run from the WaveMaker Studio, you are deploying a web application that can be accessed by anyone on your network (e.g., by anyone inside your network firewall).

Deploying using Run is recommended ~only~ for test or trial uses as the application is deployed to the WaveMaker server provided with WaveMaker Studio. When you stop WaveMaker Studio, using the WaveMaker console, the deployed application stops too.

Pressing Run will run the application in a new browser window. The url for the application in the new browser will look something like this:

http://localhost:8094/EmployeeApp/login.html

Here are the elements of the generated url:

  • localhost: this is the "generic" name for your computer on the network. For other users to access your application, you will need to replace "localhost" with your actual computer name.
  • 8094: this is the port that is running the dedicated tomcat server that is used by WaveMaker studio.
  • EmployeeApp: this is the name of your application, which is the same as the name of your WaveMaker project. You can change this by setting the "context root" parameter during the application deployment
  • login.html: this is the default start page for applications with security enabled. If you are not using security, this will not be part of the url.
The running application will look like this:

runlocal.gif

In order to make this application available to other users on your network, substitute the name "localhost" in the url with the actual name of your computer.

To find the name of your computer on Windows, bring up the System Properties dialog by pressing the Start button, then right-clicking on the "My Computer" icon and selecting "Properties". Next select the "Computer Name" tab and look at the "Full computer name property", which in this case is DB7K25C1.

computername.gif

To enable another user on the same network to access your application, just substitute the "localhost" name in your url with "DB7K25C1". In this case, the url would look like this:

http://DB7K25C1:8094/EmployeeApp/login.html

On another user's computer, your application will look like this:

computerurl.gif

Note: as long as your project is running in WaveMaker studio, it will be available to other users on your network. If you close the project or close Wavemaker studio, it will become unavailable. When you open a new project within WaveMaker Studio the current project is closed.

WaveMaker as a Dedicated Server

When using WaveMaker for deployment, the best practice is to use one computer to edit WaveMaker applications and another computer to run the WaveMaker application that is accessible to other users in your organization. When you stop the dedicated WaveMaker server, using the WaveMaker console, the deployed application stops too.

An easy way to run a deployed WaveMaker application is to install WaveMaker on a dedicated computer. Export your WaveMaker project as a Zip file (select the File menu, then select Export Project), then re-open the zip file in WaveMaker studio on the dedicated computer (unzip the exported project in the WaveMaker project directory and then select the File menu, then select Open Project) and press run. Now the application is deployed and running on the dedicated computer.

The section above (Run the Application) describes how to create the URL for use by colleagues within your organization.

Note that this approach only allows you to run a single WaveMaker application on the dedicated computer. To run multiple WaveMaker applications on a dedicated computer, deploy to a Java Web Server or to Cloud Foundry.

Deploy to Cloud Foundry

Cloud Foundry is VMware's hosted, managed, and supported cloud. Cloud Foundry is a Platform as a Service (PaaS) therefore provides an application-centric interface that is perfectly suited for WaveMaker applications. Cloud Foundry manages the applications as well as the services required by the application (i.e. databases). Cloud Foundry is open source and available in multiple forms, including:

  • CloudFoundry.com - VMware's public cloud offering
  • Micro Cloud Foundry - run a complete cloud instance on your own computer
  • Partners: ActiveState stackato, AppFog, and others
To deploy to Cloud Foundry follow these steps:

  1. In WaveMaker Studio, select File->Deploy Project->New Deployment...
    newdeployment.png
  2. Select Tomcat Server in the Deployment Type dialog then press OK.
    cfdeploy.png
  3. The Deployment dialog displays, providing all options for deploying to Cloud Foundry. The setting required for Cloud Foundry deployment are:
    • Deployment Name - name your deployment. Subsequent deployments can reuse these settings by selecting this name.
    • CloudFoundry target - the location of the Cloud Foundry server manager. To deploy to cloudfoundry.com, use:
      https://api.cloudfoundry.com
    • Application name - the name that will be used to access your application within the Cloud Foundry target. If the name is not unique within the Cloud Foundry environment then you will be prompted to provide a new name.
    • URL - The resulting URL to use to access the application after the application is deployed. This field is not editable.
  4. Configure database information. If the project includes one or more databases the Deployment dialog will display the database section. Configure the database connection information for each database used within the application. The screenshot below shows an application with one database.
    cfdeployment.png
    The setting required for database deployment are:
    • Type - The type of the database. The database type is defined within the project. It cannot be changed during deployment.
    • Database name - The name of the database within your Cloud Foundry account. If the database does not already exist, the application will automatically create the database tables during initialization. To populate the database with content, see Populating Cloud Foundry Database.
  5. Save the settings to reuse in subsequent deployments. Access this deployment using the Deployment name.
  6. Press Deploy Now
  7. The confirmation dialog displays. If you do not want to update the database definition then uncheck Update database schema?.
  8. Press OK.
  9. If you have not previously provided Cloud Foundry credentials then you will be prompted to provide your Cloud Foundry Account name and Password". Enter this information and press *OK.
    This step will take a few minutes, likely 3-5 minutes. WaveMaker will generate a WAR file ((web application archive) then deploy the application to Cloud Foundry. When the deployment is complete an alert appears, which displays a link to the newly deployed application.
  10. Close the alert then Close the Deployment dialog when finished.

Populating Cloud Foundry Database

Situation

You've developed an application using WaveMaker that accesses a local MySQL database, which you've used during the development of your application. The content in the local database needs to be copied to the application when deployed on Cloud Foundry.

Solution

In a few steps you can enhance your application so the database content is initialized when you deploy your application. The steps are:

  1. Export the database content
  2. Configure your application to populate the database when the application deploys to Cloud Foundry

Export

The mysqldump utility will create an export of the contents of your database. The exported contents must be stored within your project so it is included in the Cloud Foundry deployment (the project .war file). The "src" directory within the project is the recommended location for the export file. Here's a command line example:

mysqldump -u root -p sampledata > sampledata.sql

where "root" is the database user name, "sampledata" is the database name, and "sampledata.sql" is the name of the file created . Move the "sampledata.sql" file to the "src" directory within your project.

Configure

Configure the Spring initialization to automatically populate the database when the database is created. Using any editor, modify the project-spring.xml file, located in your project's webapprootWEB-INF directory. Insert the following spring bean definition using your projects values:

<bean id="sampledataDBInitializer" 
		class="org.springframework.jdbc.datasource.init.DataSourceInitializer" 
		depends-on="sampledataDBSessionFactory">

		<property name="dataSource" ref="sampledataDBDataSource"/>

		<property name="databasePopulator">
			<bean class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator">
				<property name="scripts" value="classpath:sampledata.sql"/>
				<property name="continueOnError" value="true"/>
			</bean> 
		</property>
	</bean>
Values you must change:
depends-on: Replace the DBSessionFactory name with your DB session Factory. This is usually the the DB service name and can be found in the spring.xml for your database service under services.
dataSource: Replace the DBDataSource name with your DB data source name. This can also be found in the spring.xml for your database service under services.
scripts: Ensure the name used matches the name of the database export. In the example above, the export file is named "sampledata.sql".
The complete project-spring.xml should look similar to this one project-spring.xml

Manage Cloud Foundry Deployments

To manage Cloud Foundry deployments follow these steps:

  1. In WaveMaker Studio, select File->Deploy Project->Manage Cloud Foundry Apps...
    managecf.png
  2. In the Cloud Foundry Account Info dialog enter or confirm the Cloud Foundry target, Account name, and Password, then press OK.
  3. WaveMaker Studio will connect to your Cloud Foundry account and list your deployed applications.
    deployedapps.png
To view the running application click on the application links.

To undeploy the application from Cloud Foundry, select one of the applications in the list then press Undeploy. To also delete any services associated with the application, select the checkbox Delete services too? then press Undeploy.

Automated deployment to Tomcat / tcServer

To deploy to tcServer or Tomcat follow these steps:

  1. In WaveMaker Studio, select File->Deploy Project->New Deployment...
    newdeployment.png
  2. Select Tomcat Server in the Deployment Type dialog then press OK.
    tomcatdeploy.png
  3. The Deployment dialog displays, providing all options for deploying to Tomcat. The setting required for Tomcat deployment are:
    • Deployment Name - name your deployment. Subsequent deployments can reuse these settings by selecting this name.
    • Hostname / IP addr - the location of the Tomcat server on which WaveMaker will deploy the application. If the application should be deployed on the local machine then enter "localhost" otherwise enter the IP address or hostname of the machine.
    • Port - the port on which the application will run. If you are installing to the Tomcat server then 8094 is likely the correct port. The WaveMaker Console displays the Server Port; enter the same port number in this field.
    • Application name - the name to be used to access the application once it has been deployed.
      Note: the URL field displayed the resulting URL where the application will be available after deployment has completed.
    • User name - the Tomcat manager username
    • Password - the Tomcat manager password
  4. Configure database information. If the project includes one or more databases the Deployment dialog will display the database section. Configure the database connection information for each database used within the application. The screenshot below shows an application with one database.
    deployment.png
    The setting required for database deployment are:
    • Database connection - Standard or JNDI. JNDI is an advanced option. See JNDI for details.
    • Type - The type of the database. The database type is defined within the project. It cannot be changed during deployment.
    • User name - the database connection username to be used by the deployed application.
    • Password - the database connection password to be used by the deployed application.
    • Host/IP Address - the location of the database server.
    • Port - the database port number
    • Database Name - the database instance name, available on the database server.
    • Connection URL - the connection string used to connect to the database. The value is created based on the settings provided within this dialog. The value can be customized further although in most cases the default value is correct.
  5. Save the settings to reuse in subsequent deployments. Access this deployment using the Deployment name.
  6. Press Deploy Now - This step will take a few minutes, likely 3-5 minutes. WaveMaker will generate a WAR file ((web application archive) then deploy the application to the specified Tomcat server.

Generate a WAR or EAR File

WaveMaker Studio will generate a WAR (web application archive) and EAR (enterprise archive) file, which you can deploy on to any Java web server (for example: Tomcat, WebLogic, WebSphere, JBoss, GlassFish) running on JDK 1.5, or JDK 1.6.0_04 or above.

For the latest information on supported platforms and configurations for WaveMaker Studio development and deployment, see System Platforms.

To generate a WAR and EAR file, follow these steps:

  1. Open the project in WaveMaker Studio.
  2. Select File->Deploy Project->New Deployment...
    newdeployment.png
  3. Select Application Files (WAR/EAR) in the Deployment Type dialog then press OK.
    wardeploy.png
  4. The Deployment dialog displays, providing all options for generating the application. The setting required for WAR or EAR geneation are:
    • Deployment Name - name your deployment. Subsequent deployments can reuse these settings by selecting this name.
    • Select either WAR file or EAR file depending on your server's requirements.
  5. Configure database information. If the project includes one or more databases the Deployment dialog will display the database section. Configure the database connection information for each database used within the application.
    The setting required for database deployment are:
    • Database connection - Standard or JNDI. JNDI is an advanced option. See JNDI for details.
    • Type - The type of the database. The database type is defined within the project. It cannot be changed during deployment.
    • User name - the database connection username to be used by the deployed application.
    • Password - the database connection password to be used by the deployed application.
    • Host/IP Address - the location of the database server.
    • Port - the database port number
    • Database Name - the database instance name, available on the database server.
    • Connection URL - the connection string used to connect to the database. The value is created based on the settings provided within this dialog. The value can be customized further although in most cases the default value is correct.
  6. Save the settings to reuse in subsequent deployments. Access this deployment using the Deployment name.
  7. Press Deploy Now - This step will take a few minutes, likely 3-5 minutes. WaveMaker will generate a WAR (web application archive) file or EAR (enterprise archive) file, depending on your selection.
    When complete the WAR file or EAR file is automatically downloaded to your browser.
Note: The generate WAR/EAR file is also available in the "dist" directory of your project.

JNDI (Java Naming and Directory Interface)

Advanced users only.

When deploying to a Java web server, WaveMaker allows you to configure the JNDI setting. To use this service, JNDI must be configured in your server environment. JNDI, is a directory service interface. If JNDI is not configured in your environment then do not set the Database Connection to JNDI. Enterprises use JNDI to adjust DB specifics, including connection settings, without having to modify the applications that uses the DB.

The database must be reachable by the server when the application is executed. If you are deploying your app to a Java web server, the db must be reachable by the webserver. This can be on the same host as the httpd/tomcat or on a different host, but the Java web server (tomcat) must be able to access the db. The DB connection may be different in production than in development. Be certain to update the connection settings BEFORE generating the WAR file.

JNDI setting is:

  • JNDI Name - the JNDI resource name.
WaveMaker will configure Spring (datamodelname.spring.xml) and the data model property file (datamodelname.properties) based on the information provide in the JNDI Setup dialog

By convention JDBC JNDI resource names are prefaced with "jdbc". A datasource named CustomerDB would then have the JNDI resource name "jdbc/CustomerDB". The JDNI Name to use in the JNDI Setup dialog would be "java:comp/env/CustomerDB"

For more information on JNDI, see the Java Documentation on JNDI.

Java Web Server Deployment

Once a WAR or EAR file is generated (see Generate a WAR or EAR File)a WaveMaker application may be deployed to any of a number of Java web servers, including tcServer, Tomcat, JBoss, GlassFish, WebLogic, and WebSphere.

Web.xml entries

The web.xml file in a project webapprootWEB-INF folder is managed by studio and should not be edited directly.
Web.xml customizations should be placed in webapprootWEB-INFuser-web.xml. The contents of user-web.xml will be merged with the contents of web.xml for deployment.

Tomcat Deployment

When deploying to Tomcat, there are a few tips that may help you get the most out of your WaveMaker application. Most of Tomcat's defaults are fine for standard web applications, including WaveMaker.

Memory

If you have several WaveMaker applications deployed to a single machine, you might need to increase both Java's heap size and the amount of permgen space. By default, both are set at 64 megabytes. It is difficult to measure exactly how much of each an individual application may take, as resource usage varies heavily depending on the application.

WaveMaker recommends 20m of permgen and 30m of heap per application, but this varies by application and load. At absolute minimum, for each application you should have 5605k of heap and 9344k of permgen. Heap usage in particular will increase with load, so be sure to provide plenty.

To increase Java's memory usage, see below. Recommended settings (and the defaults) are:

  • Heap is set with -Xmx128m (increasing the maximum to 128 megabytes)
  • permgen is set with -XX:MaxPermSize=400m (increasing the maximum to 400)
Note that these are separate measures; with heap set to 128 and permgen set to 400, your Java program could take up to 528m. Make sure you have sufficient system memory.

Editing Tomcat JVM settings

The following describes editing the JVM settings for the embedded Studio Tomcat.
To adjust tomcat JVM settings for standalone tomcat installations, see a Tomcat guide such as this one by Atlassian

Edit the file /applications/wavemaker.app/Contents/MacOS/wmstart.sh

Edit the start command to pass th "-Xmx" property to the JVM. For example to set the max memory to 512 MB, use " -Xmx512m"


To increase the max heap size:

  1. Open the WaveMaker start menu item
    1. Start Menu -> WaveMaker -> Version -> WaveMaker
      startmenu.PNG
  2. Right click on WaveMaker
  3. Select Properties
  4. Edit the Target value
    Note, you will need to scroll within the target field to see the JVM options.
    wmproperties.PNG

Server Status

To monitor the current JVM Max Heap Size setting and memory usage, go to the tomcat status page

http://localhost:8094/manager/status

Here is example output of a Tomcat status with the max heap size set to 400m

tomcatheap.jpg

Log Rotation

By default, WaveMaker applications log everything to stdout. Tomcat redirects this to a log file, but the log file will grow without bounds. Log rotation is the recommended way to solve this, but you'll have to change the log appender from stdout to a file.

Your project's log4j.properties (located in the src directory) may have a header like:

log4j.rootLogger=warn, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p &#91;%c&#93; - <%m> (%x) %n

or

log4j.rootLogger=warn, stdout, wmlog\\log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p &#91;%c&#93; - <%m> (%x) %n

# default catalina.home; when the System property isn't set, this will be
# used
catalina.home=.
log4j.appender.wmlog=org.apache.log4j.RollingFileAppender
log4j.appender.wmlog.File=${catalina.home}/logs/wm.log
log4j.appender.wmlog.MaxFileSize=10MB
log4j.appender.wmlog.MaxBackupIndex=10
log4j.appender.wmlog.layout=org.apache.log4j.PatternLayout
log4j.appender.wmlog.layout.ConversionPattern=%d %p &#91;%c&#93; - <%m> (%x) %n

You should remove the stdout entries, and add wmlog entries if they do not exist. The logger entries (following the above snippets) can be left unchanged. For example:

log4j.rootLogger=warn, wmlog
log4j.appender.wmlog=org.apache.log4j.RollingFileAppender
log4j.appender.wmlog.File=${catalina.home}/logs/wm.log
log4j.appender.wmlog.MaxFileSize=10MB
log4j.appender.wmlog.MaxBackupIndex=10\\log4j.appender.wmlog.layout=org.apache.log4j.PatternLayout
log4j.appender.wmlog.layout.ConversionPattern=%d %p &#91;%c&#93; - <%m> (%x) %n

The ${catalina.home} variable only exists in Tomcat. Other application servers may have similar settings.

Enabling GZIP Compression

Note: WaveMaker 6.1 Automatically GZIPs JavaScript files.

The WaveMaker client libraries are several large JavaScript files. Large files load faster than multiple small files, and further gains can be realized by enabled GZIP compression on the server-side. This will compress the files before they are sent; modern browsers can uncompress these on the fly.

To enable this, edit the Tomcat server.xml, and add the following lines to your Connector configuration:

compression="on" compressionMinSize="2048"
noCompressionUserAgents="gozilla, traviata, &#42;?MSIE 6.&#42;?"
compressableMimeType="text/html,text/xml,text/javascript,text/css"

For example, the Connector configuration might look like this:

<Connector port="8094" maxHttpHeaderSize="8192"
URIEncoding="UTF-8" maxThreads="150" minSpareThreads="25"
maxSpareThreads="75" enableLookups="false"
redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true"
compression="on" compressionMinSize="2048"
noCompressionUserAgents="gozilla, traviata, .&#42;?MSIE 6.&#42;?" compressableMime Type="text/html,text/xml,text/javascript,text/css" />

Using APR native libraries

The APR native libraries will provide general performance improvements to Tomcat. This includes major improvements to serving static files directly, crypto/SSL speed, as well as some improvements to AJP connections to Apache httpd.

Using APR might disable GZIP compression. In situations with many clients connecting simultaneously, APR may have advantages, but in most situations GZIP compression will provide a better client experience, so WaveMaker recommends either using only GZIP compression (Enabling GZIP Compression), or APR and Apache httpd (Serving Static Content with Apache httpd).

For more information and downloads, consult Tomcat's documentation:

Serving Static Content with Apache httpd

In cases where APR native libraries don't provide enough of a performance boost, or if you want an additional layer between client and appserver, you can use Apache httpd. The Apache httpd server can be configured to respond to all requests; static files are served directly, and requests for Java resources are forwarded to Tomcat for processing. Apache httpd also handles SSL processing and GZIP compression.

You will need an Apache httpd server set up, and you should be familiar with Apache httpd configuration before attempting this.

Tomcat side configuration:

For Tomcat 5.5:

http://tomcat.apache.org/tomcat-5.5-doc/config/ajp.html

And Tomcat 6:

http://tomcat.apache.org/tomcat-6.0-doc/config/ajp.html

For Apache httpd, you should use either mod_jk:

http://tomcat.apache.org/connectors-doc/

or mod_proxy_ajp: http://httpd.apache.org/docs/2.2/mod/mod_proxy_ajp.html

Configuration information is available at those sites.

Deploying on WebLogic 10

WaveMaker's JSON runtime requires commons-lang-2.3.jar, however WebLogic uses an older version of commons-lang.jar.

To fix this, you will have to edit the setDomainEnv.cmd file (on Linux, this file is called setDomainEnv.sh) to set the PRE_CLASSPATH variable to use the commons-lang-2.3.jar.

For example:

PRE_CLASSPATH=%PRE_CLASSPATH%;C:worklibcommons-lang-2.3.jar

If you don't make this change, you'll see an exception that looks something like this:

java.lang.NoSuchMethodError: join
at com.wavemaker.runtime.server.json.JSONMarshaller.getPropertyName(JSONMarshaller.java:470)
at com.wavemaker.runtime.server.json.JSONMarshaller.handleObjectInternal(JSONMarshaller.java:395)
at com.wavemaker.runtime.server.json.JSONMarshaller.handleObject(JSONMarshaller.java:323)
at com.wavemaker.runtime.server.json.JSONMarshaller.doMarshal(JSONMarshaller.java:280)
at com.wavemaker.runtime.server.json.JSONMarshaller.marshal(JSONMarshaller.java:150)
at com.wavemaker.runtime.server.json.JSONMarshaller.marshal(JSONMarshaller.java:127)

See also: Tomcat in Dev

Build and Deploy Using Scripts

BatchBuild is a set of scripts to build, deploy, and undeploy WaveMaker projects. The scripts can be integrated into automated build process and do not require a running WaveMaker Studio.

The scripts are provided in the WaveMaker installation in the <WM-Install-Dir>/Support/Batchbuild director. The three scripts are:

  • build.bat
  • deploy.bat
  • undeploy.bat
Currently the scripts are only available for Windows systems, however all users can download the files

To use the scripts, update the included infrastructure to reflect the WaveMaker installation, specifically:

  1. app-deploy.properties
    • project.dir - change the value to the location of your WaveMaker projects.
    • deploy.name - change the value to the name of the deployed project.
    • studio.webapproot - replace "WM" with the location of the WaveMaker installation. (The Windows default is "C:/Program Files/WavemMaker/6.1.9GA"
    • war.file.name - replace "myproject" with the name of the project to be managed
    • ear.file.name - replace "myproject" with the name of the project to be managed
    • orig.proj.dir - replace "myproject" with the name of the project to be managed
    • build.app.webapproot - replace "C:/wavemaker" with the location of your WaveMaker projects directory and replace "myproject" with the name of the project to be managed
    • wavemaker.home - change the value to the location of your WaveMaker projects
    • tomcat.manager.username - change the value to the username of the Tomcat manager
    • tomcat.manager.password - change the value to the password of the Tomcat manager
  2. deploy.bat, build.bat, and undeploy.bat
    • Change "WM" to the location of the WaveMaker installation.

Manage Cloud Servers

WaveMaker applications may be deployed to public or private cloud servers. WaveMaker applications have been deployed to numerous clouds, including:

  • Amazon Elastic Compute Cloud (EC2)
  • Eucalyptus
  • OpSource Cloud
  • RackSpace Cloud
To deploy an application to one of these clouds you will need to:

  1. Acquire and account (public cloud) or install the software (private cloud)
  2. Create a cloud instance - a virtual machine with a standard operating system
  3. Install a Java web server - for example, tcServer or Tomcat
  4. Deploy the WaveMaker WAR (or EAR) to the Java web server

See Also

Tags:
Created by Derek Henninger on 2009/12/13 14:15

© 2012-2014 WaveMaker Inc. All Rights Reserved.
Share/Bookmark