Ich habe seinerzeit mit jfxbuild lediglich das Grundgerüst für das Ant-File gelegt, alle weiteren Änderungen waren dann rein am build.xml weitergearbeitet.
Mittlerweile sieht es in etwa so aus (habe alle Referenzen auf uns mal raus genommen):
Was macht es?
- Git-Hash vom Head lesen und in eine Java-Datei vorm kompilieren schreiben
- Obfuscating mit ProGuard
- Signieren der Anwendung/des Applets mit eigenen (aber gekauften) Zertifikat (bzw. dem daraus erstellten KeyStore) und aller Bibliotheken
- builden für unterschiedliche Systeme (jeweils auf einem solchen, Cross-Plattform builds sind leider nicht mit einem einzigen Aufruf möglich - brauchst also z.B. Win, Mac und Linux für jede Plattform)
- eventuell den Pfad für die cacerts setzen (auf Linux macht https sonst im WebView Probleme, man muss mit dem Pfad spielen)
- alternativ auch für Applet
- Wenn die Tools da sind, werden auch die Installer / Executables für die Plattform erstellt
- externe Scripte für bestimmte Operationen (wir haben ein DL-Manifest, mit dem wir updates zumindest Theretisch steuern könnten), ...
- und sicher noch mehr, was ich jetzt schon wieder vergessen hab
Code:In die Zwischenablage kopieren
<?xml version="1.0" encoding="UTF-8"?>
<project name="TargetName" default="do-bundle-apps-dev" basedir="./build" xmlns:fx="javafx:com.sun.javafx.tools.ant">
<!-- fetch from Version.VERSION_STRING -->
<property name="app.version" value="1.0.1" />
<property name="app.vendor.st" value="CompanyName" />
<property name="app.title.st" value="TheTitle" />
<property name="app.desc" value="bla bla" />
<property name="app.update.required" value="false" />
<property name="app.update.push" value="false" />
<property name="fx.title" value="TheTitle" />
<property name="fx.minVersion" value="2.2+" />
<property name="fx.minJava" value="1.7.0_60+" />
<property name="fx.permSize" value="-XX:PermSize=256m" />
<property name="fx.maxPermSize" value="-XX:MaxPermSize=256m" />
<property name="fx.xms" value="-Xms256m" />
<property name="fx.xmx" value="-Xmx1024m" />
<property name="fx.appWidth" value="960" />
<property name="fx.appHeight" value="450" />
<property name="win.signToolPath" value="${basedir}/../winKit/bin/x64/signtool.exe" />
<property name="win.certificate" value="${basedir}/../keystore\someName.pfx" />
<taskdef resource="proguard/ant/task.properties" classpath="../proguard5.1/lib/proguard.jar" />
<target name="env" description="environment print">
<echo>Build ${app.title.st} Version ${app.version} ©${app.vendor.st}</echo>
<echo>APP Title: ${app.title.st}</echo>
<echo>APP Version: ${app.version}</echo>
<echo>APP Vendor: ${app.vendor.st}</echo>
<echo>APP Description: ${app.desc}</echo>
<echo>Java Title (JAR): ${fx.title}</echo>
<echo>Min. Java Version: ${fx.minJava}</echo>
<echo>Min. Java FX Version: ${fx.minVersion}</echo>
<echo>Used Java for build: ${java.home}</echo>
</target>
<target name="check-os" description="Check the OS of the build server">
<condition property="isWindows">
<os family="windows"/>
</condition>
<condition property="isNotWindows">
<not>
<os family="windows"/>
</not>
</condition>
</target>
<target name="get-pwd-win" depends="check-os" if="isWindows" description="get the current directory for windows build machine">
<exec executable="echo" outputproperty="exec.pwd">
<arg value="%cd%"/>
</exec>
</target>
<target name="get-pwd" depends="check-os" if="isNotWindows" description="get the current directory for unix build machine">
<exec executable="pwd" outputproperty="exec.pwd" />
</target>
<target name="get-git-revision" description="get the head revision of the git repository">
<exec executable="git" outputproperty="git.revision">
<arg value="rev-parse"/>
<arg value="--short"/>
<arg value="HEAD"/>
</exec>
<fail message="The Git Revision could not be fetched">
<condition>
<not>
<isset property="git.revision" />
</not>
</condition>
</fail>
<property name="version.string" value="${app.version}-${git.revision}" />
<echo>The Git Revision is "${git.revision}" - The resulting Version String is "${version.string}"</echo>
</target>
<target name="update-library-manifests" description="update all library manifests for the build">
<antcall target="update-library-manifest">
<param name="file">httpmime-4.3.1.jar</param>
</antcall>
<antcall target="update-library-manifest">
<param name="file">ourOwnLibrary.jar</param>
</antcall>
<antcall target="update-library-manifest">
<param name="file">log4j-1.2.17.jar</param>
</antcall>
<antcall target="update-library-manifest">
<param name="file">simple-xml-2.7.jar</param>
</antcall>
<antcall target="update-library-manifest">
<param name="file">commons-logging-1.1.3.jar</param>
</antcall>
<antcall target="update-library-manifest">
<param name="file">httpclient-4.3.1.jar</param>
</antcall>
<antcall target="update-library-manifest">
<param name="file">httpclient-cache-4.3.1.jar</param>
</antcall>
<antcall target="update-library-manifest">
<param name="file">httpcore-4.3.jar</param>
</antcall>
<antcall target="update-library-manifest">
<param name="file">jackson-all-1.9.11.jar</param>
</antcall>
<antcall target="update-library-manifest">
<param name="file">sqlite-jdbc-3.8.7.jar</param>
</antcall>
</target>
<target name="update-library-manifest" description="update the input library manifests for the build">
<!-- First we unzip the existing MANIFEST-MF -->
<unzip src="${basedir}/dist/payload/libs/${file}" dest="." >
<patternset>
<include name="META-INF/MANIFEST.MF" />
</patternset>
</unzip>
<!-- Add the three missing attributes -->
<manifest file="META-INF/MANIFEST.MF" mode="update">
<attribute name="Permissions" value="all-permissions" />
<attribute name="Application-Name" value="${app.title.st}" />
<attribute name="Codebase" value="*" />
</manifest>
<!-- Update the JAR File with the modifed MANIFEST -->
<zip destfile="${basedir}/dist/payload/libs/${file}" update="true">
<fileset dir=".">
<include name="META-INF/MANIFEST.MF" />
</fileset>
</zip>
<!-- Delete the MANIFEST again -->
<delete dir="META-INF" />
</target>
<target name="build-manifest" depends="get-pwd, get-pwd-win" description="create a manifest json file for the bundels to handle the update">
<fail message="Could not fetch the current directory from command line tool "pwd".">
<condition>
<not>
<isset property="exec.pwd" />
</not>
</condition>
</fail>
<echo>Current dir: ${exec.pwd} (should be the build directory)</echo>
<echo>Data dir: ${exec.pwd}/deploy/payload/bundles/ourApplication/app/</echo>
<exec executable="python" dir="${exec.pwd}/..">
<arg value="gen_manifest.py"/>
<arg value="${app.version}"/>
<arg value="${app.update.required}"/>
<arg value="${exec.pwd}/deploy/payload/bundles/ourApplication/app/"/>
<arg value="${app.update.push}"/>
</exec>
<fail message="Could not find the file 'manifest.json' - this was the anticipated result of this task, though.">
<condition>
<not>
<resourcecount count="1">
<fileset dir="${basedir}">
<include name="manifest.json"/>
</fileset>
</resourcecount>
</not>
</condition>
</fail>
</target>
<target name="build-manifest-checked" depends="check-os" if="isNotWindows" description="see build-manifest, including os check">
<antcall target="build-manifest" />
</target>
<target name="init-fx-tasks" description="initialize fx dependencies">
<path id="fxant">
<filelist>
<file name="${java.home}/../lib/ant-javafx.jar" />
<file name="${java.home}/lib/jfxrt.jar" />
<file name="${basedir}"/>
</filelist>
</path>
<taskdef resource="com/sun/javafx/tools/ant/antlib.xml" uri="javafx:com.sun.javafx.tools.ant" classpathref="fxant" />
</target>
<target name="setup-staging-area" depends="get-git-revision" description="setup directories, copy libraries, set version">
<delete includeemptydirs="true">
<fileset dir="${basedir}" >
<include name="**/*" />
<exclude name="deploy" />
</fileset>
</delete>
<mkdir dir="${basedir}/externalLibs" />
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="commons-logging-1.1.3.jar" />
</fileset>
</copy>
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="httpclient-4.3.1.jar" />
</fileset>
</copy>
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="httpclient-cache-4.3.1.jar" />
</fileset>
</copy>
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="simple-xml-2.7.jar" />
</fileset>
</copy>
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="ourOwnLibrary.jar" />
</fileset>
</copy>
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="httpmime-4.3.1.jar" />
</fileset>
</copy>
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="httpcore-4.3.jar" />
</fileset>
</copy>
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="log4j-1.2.17.jar" />
</fileset>
</copy>
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="jackson-all-1.9.11.jar" />
</fileset>
</copy>
<copy todir="${basedir}/externalLibs">
<fileset dir="${basedir}/../libs">
<filename name="sqlite-jdbc-3.8.7.jar" />
</fileset>
</copy>
<mkdir dir="${basedir}/project" />
<copy todir="${basedir}/project">
<fileset dir="${basedir}/..">
<include name="src/**" />
<include name="src-desktop/**" />
</fileset>
</copy>
<!-- replace the version string in the source file 'version.java' -->
<replaceregexp byline="true">
<regexp pattern="(.*)VERSION_STRING = "(.*)";"/>
<substitution expression="\1VERSION_STRING = "${app.version}";"/>
<fileset dir="${basedir}/project">
<include name="**/Version.java"/>
</fileset>
</replaceregexp>
<!-- replace the revision string in the source file 'version.java' -->
<replaceregexp byline="true">
<regexp pattern="(.*)REVISION = "(.*)";"/>
<substitution expression="\1REVISION = "${git.revision}";"/>
<fileset dir="${basedir}/project">
<include name="**/Version.java"/>
</fileset>
</replaceregexp>
<mkdir dir="${basedir}/projectRefs" />
<mkdir dir="${basedir}/package" />
<copy todir="${basedir}/package">
<fileset dir="${basedir}/../package">
<include name="**/*" />
</fileset>
</copy>
</target>
<target name="sign-windows-apps" depends="check-os" if="isWindows" description="sign windows apps with our certificate">
<exec executable="${win.signToolPath}">
<arg value="sign"/>
<arg value="/fd"/>
<arg value="SHA256"/>
<arg value="/a"/>
<arg value="/f"/>
<arg value="${win.certificate}"/>
<arg value="/p"/>
<arg value="changeit"/>
<arg value="/tr"/>
<arg value="http://timestamp.comodoca.com/rfc3161"/>
<arg value="${basedir}/deploy/payload/bundles/*.msi"/>
<arg value="${basedir}/deploy/payload/bundles/*.exe"/>
</exec>
</target>
<target name='do-compile' description="build the java classes for the build">
<delete dir="${basedir}/build" />
<mkdir dir="${basedir}/build" />
<mkdir dir="${basedir}/build/src" />
<mkdir dir="${basedir}/build/libs" />
<mkdir dir="${basedir}/build/classes" />
<!-- Copy project-libs references -->
<copy todir="${basedir}/build/libs">
<fileset dir="${basedir}/externalLibs">
<include name="ourOwnLibrary.jar" />
<include name="httpmime-4.3.1.jar" />
<include name="log4j-1.2.17.jar" />
<include name="simple-xml-2.7.jar" />
<include name="commons-logging-1.1.3.jar" />
<include name="httpclient-4.3.1.jar" />
<include name="httpclient-cache-4.3.1.jar" />
<include name="httpcore-4.3.jar" />
<include name="jackson-all-1.9.11.jar" />
<include name="sqlite-jdbc-3.8.7.jar" />
</fileset>
</copy>
<!-- Copy project sources itself -->
<copy todir="${basedir}/build/src">
<fileset dir="${basedir}/project/src">
<include name="**/*" />
</fileset>
</copy>
<copy todir="${basedir}/build/src">
<fileset dir="${basedir}/project/src-desktop">
<include name="**/*" />
</fileset>
</copy>
<!-- Java Build -->
<javac includeantruntime="false" source="1.7" target="1.7" srcdir="${basedir}/build/src" destdir="${basedir}/build/classes" encoding="Cp1252" debug="true">
<classpath>
<fileset dir="${basedir}/build/libs">
<include name="*" />
</fileset>
<filelist>
<file name="${java.home}/lib/jfxrt.jar" />
</filelist>
</classpath>
<compilerarg value="-Xlint" />
</javac>
<!-- Copy none Java-Files -->
<copy todir="${basedir}/build/classes">
<fileset dir="${basedir}/project/src">
<exclude name="**/*.java" />
<exclude name="**/*.fxgraph" />
</fileset>
</copy>
<copy todir="${basedir}/build/classes">
<fileset dir="${basedir}/project/src-desktop">
<exclude name="**/*.java" />
<exclude name="**/*.fxgraph" />
</fileset>
</copy>
</target>
<target name="do-build" depends="env, init-fx-tasks, setup-staging-area, do-compile" description="build the java jar">
<delete file="${basedir}/dist" />
<delete file="${basedir}/deploy" />
<mkdir dir="${basedir}/dist" />
<mkdir dir="${basedir}/dist/payload" />
<mkdir dir="${basedir}/dist/payload/libs" />
<mkdir dir="${basedir}/dist/js" />
<mkdir dir="${basedir}/dist/js/ext" />
<copy todir="${basedir}/dist/payload/libs">
<fileset dir="${basedir}/externalLibs">
<include name="*" />
</fileset>
</copy>
<antcall target="update-library-manifests" />
<copy todir="${basedir}/dist">
<fileset dir="${basedir}/../html">
<include name="**" />
</fileset>
</copy>
<fx:resources id="appRes">
<fx:fileset dir="${basedir}/dist/payload" includes="TargetName-all-${app.version}.jar" />
<fx:fileset dir="${basedir}/dist/payload" includes="libs/*" />
</fx:resources>
<fx:application id="fxApplication"
name="${app.title.st}"
mainClass="ch.company.performanceapplet.fx.Main"
toolkit="fx"
version="${app.version}">
<fx:param name="boxbgcolor" value="silver" />
<fx:htmlParam name="boxbgcolor" value="silver" />
</fx:application>
<mkdir dir="${basedir}/build/classes/META-INF" />
<fx:jar destfile="dist/payload/TargetName-all-${app.version}.jar">
<fx:application refid="fxApplication" />
<fileset dir="${basedir}/build/classes" />
<fx:resources refid="appRes" />
<manifest>
<attribute name="Implementation-Vendor" value="${app.vendor.st}" />
<attribute name="Implementation-Title" value="${app.title.st}" />
<attribute name="Implementation-Version" value="${git.revision}" />
<attribute name="Specification-Version" value="${app.version}" />
<attribute name="Application-Name" value="${app.title.st}" />
<attribute name="JavaFX-Feature-Proxy" value="None" />
<attribute name="Permissions" value="all-permissions" />
<attribute name="Codebase" value="*" />
<attribute name="Caller-Allowable-Codebase" value="*" />
</manifest>
</fx:jar>
</target>
<target name="do-obfuscate" depends="do-build" description="obfuscate the build files">
<proguard configuration="../proguard.cfg" >
<injar file="${basedir}/dist/payload/TargetName-all-${app.version}.jar" />
<outjar file="${basedir}/dist/payload/TargetName-${app.version}.jar" />
<libraryjar file="${java.home}/lib/rt.jar" />
<libraryjar file="${java.home}/lib/ext/jfxrt.jar" />
<libraryjar file="${java.home}/../lib/ant-javafx.jar" />
<libraryjar file="${basedir}/../libs/log4j-1.2.17.jar" />
<libraryjar file="${basedir}/../libs/simple-xml-2.7.jar" />
<libraryjar file="${basedir}/../libs/httpclient-4.3.1.jar" />
<libraryjar file="${basedir}/../libs/httpclient-cache-4.3.1.jar" />
<libraryjar file="${basedir}/../libs/httpcore-4.3.jar" />
<libraryjar file="${basedir}/../libs/httpmime-4.3.1.jar" />
<libraryjar file="${basedir}/../libs/jackson-all-1.9.11.jar" />
<libraryjar file="${basedir}/../libs/sqlite-jdbc-3.8.7.jar" />
<libraryjar file="${basedir}/../libs/ourOwnLibrary.jar" />
</proguard>
</target>
<target name="do-bundle-applet-prod" depends="do-obfuscate" description="build the applet for production">
<mkdir dir="${basedir}/deploy" />
<mkdir dir="${basedir}/deploy/payload" />
<fx:resources id="appResDeploy">
<fx:fileset dir="${basedir}/dist/payload" includes="TargetName-${app.version}.jar" />
<fx:fileset dir="${basedir}/dist/payload" includes="libs/*" />
</fx:resources>
<fx:signjar keystore="${basedir}/../keystore/keyStore.jks"
alias="alias" keypass="changeit" storepass="changeit" destDir="${basedir}/dist"
verbose="true">
<fileset dir='dist'>
<include name='**/*.jar' />
</fileset>
</fx:signjar>
<fx:deploy embedJNLP="false"
extension="false"
width="${fx.appWidth}"
height="${fx.appHeight}"
includeDT="false"
offlineAllowed="false"
outdir="${basedir}/deploy/payload"
outfile="${fx.title}"
placeholderref="app-placeholder"
placeholderid="id"
updatemode="always"
verbose="false">
<fx:info title="${fx.title}" vendor="${app.vendor.st}" description="${app.desc}" />
<fx:application refId="fxApplication" />
<fx:resources refid="appResDeploy" />
<fx:permissions elevated="true" />
<fx:platform javafx="${fx.minVersion}" j2se="${fx.minJava}">
<fx:jvmarg value="${fx.permSize}" />
<fx:jvmarg value="${fx.maxPermSize}" />
<fx:jvmarg value="${fx.xms}" />
<fx:jvmarg value="${fx.xmx}" />
</fx:platform>
</fx:deploy>
<copy todir="${basedir}/deploy">
<fileset dir="dist">
<include name="**" />
</fileset>
</copy>
</target>
<target name="do-bundle-applet-dev" depends="do-build" description="build the applet for development/test">
<mkdir dir="${basedir}/deploy" />
<mkdir dir="${basedir}/deploy/payload" />
<fx:resources id="appResDeploy">
<fx:fileset dir="${basedir}/dist/payload" includes="TargetName-all-${app.version}.jar" />
<fx:fileset dir="${basedir}/dist/payload" includes="libs/*" />
</fx:resources>
<fx:signjar keystore="${basedir}/../keystore/keyStore.jks"
alias="alias" keypass="changeit" storepass="changeit" destDir="${basedir}/dist"
verbose="true">
<fileset dir='dist'>
<include name='**/*.jar' />
</fileset>
</fx:signjar>
<fx:deploy embedJNLP="false"
extension="false"
width="${fx.appWidth}"
height="${fx.appHeight}"
includeDT="false"
offlineAllowed="false"
outdir="${basedir}/deploy/payload"
outfile="${fx.title}"
placeholderref="app-placeholder"
placeholderid="id"
updatemode="always"
verbose="false">
<fx:info title="${fx.title}-dev" vendor="${app.vendor.st}" description="${app.desc}" />
<fx:application refId="fxApplication" />
<fx:resources refid="appResDeploy" />
<fx:permissions elevated="true" />
<fx:platform javafx="${fx.minVersion}" j2se="${fx.minJava}">
<fx:jvmarg value="${fx.permSize}" />
<fx:jvmarg value="${fx.maxPermSize}" />
<fx:jvmarg value="${fx.xms}" />
<fx:jvmarg value="${fx.xmx}" />
</fx:platform>
</fx:deploy>
<copy todir="${basedir}/deploy">
<fileset dir="dist">
<include name="**" />
</fileset>
</copy>
</target>
<target name="do-bundle-apps-prod" depends="do-obfuscate" description="build the apps on the target system for production">
<mkdir dir="${basedir}/deploy" />
<mkdir dir="${basedir}/deploy/payload" />
<fx:resources id="appResDeploy">
<fx:fileset dir="${basedir}/dist/payload" includes="TargetName-${app.version}.jar" />
<fx:fileset dir="${basedir}/dist/payload" includes="libs/*" />
</fx:resources>
<fx:signjar keystore="${basedir}/../keystore/keyStore.jks"
alias="alias" keypass="changeit" storepass="changeit" destDir="${basedir}/dist"
verbose="true">
<fileset dir='dist'>
<include name='**/*.jar' />
</fileset>
</fx:signjar>
<fx:deploy embedJNLP="false"
extension="false"
width="${fx.appWidth}"
height="${fx.appHeight}"
includeDT="false"
offlineAllowed="false"
outdir="${basedir}/deploy/payload"
outfile="${fx.title}"
nativeBundles="all"
placeholderref="app-placeholder"
placeholderid="id"
updatemode="always"
verbose="false">
<fx:info title="${fx.title}" vendor="${app.vendor.st}" description="${app.desc}" />
<fx:application refId="fxApplication" />
<fx:resources refid="appResDeploy" />
<fx:permissions elevated="true" />
<fx:platform javafx="${fx.minVersion}" j2se="${fx.minJava}" basedir="${java.home}">
<fx:jvmarg value="${fx.permSize}" />
<fx:jvmarg value="${fx.maxPermSize}" />
<fx:jvmarg value="${fx.xms}" />
<fx:jvmarg value="${fx.xmx}" />
<!-- TODO set the correct cacerts path !!! check, if the path is correnct on other platforms as well -->
<fx:jvmarg value="-Djavax.net.ssl.keyStore=../runtime/jre/lib/security/cacerts"/>
</fx:platform>
</fx:deploy>
<copy todir="${basedir}/deploy">
<fileset dir="dist">
<include name="**" />
</fileset>
</copy>
<antcall target="build-manifest-checked" />
</target>
<target name="do-bundle-apps-dev" depends="do-build" description="build the apps on the target system for development/test">
<mkdir dir="${basedir}/deploy" />
<mkdir dir="${basedir}/deploy/payload" />
<fx:resources id="appResDeploy">
<fx:fileset dir="${basedir}/dist/payload" includes="TargetName-all-${app.version}.jar" />
<fx:fileset dir="${basedir}/dist/payload" includes="libs/*" />
</fx:resources>
<fx:signjar keystore="${basedir}/../keystore/keyStore.jks"
alias="alias" keypass="changeit" storepass="changeit" destDir="${basedir}/dist"
verbose="true">
<fileset dir='dist'>
<include name='**/*.jar' />
</fileset>
</fx:signjar>
<fx:deploy embedJNLP="false"
extension="false"
width="${fx.appWidth}"
height="${fx.appHeight}"
includeDT="false"
offlineAllowed="false"
outdir="${basedir}/deploy/payload"
outfile="${fx.title}"
nativeBundles="all"
placeholderref="app-placeholder"
placeholderid="id"
updatemode="always"
verbose="false">
<fx:info title="${fx.title}-dev" vendor="${app.vendor.st}" description="${app.desc}" />
<fx:application refId="fxApplication" />
<fx:resources refid="appResDeploy" />
<fx:permissions elevated="true" />
<fx:platform javafx="${fx.minVersion}" j2se="${fx.minJava}" basedir="${java.home}">
<fx:jvmarg value="${fx.permSize}" />
<fx:jvmarg value="${fx.maxPermSize}" />
<fx:jvmarg value="${fx.xms}" />
<fx:jvmarg value="${fx.xmx}" />
<!-- TODO set the correct cacerts path !!! check, if the path is correnct on other platforms as well -->
<fx:jvmarg value="-Djavax.net.ssl.keyStore=../runtime/jre/lib/security/cacerts"/>
</fx:platform>
</fx:deploy>
<copy todir="${basedir}/deploy">
<fileset dir="dist">
<include name="**" />
</fileset>
</copy>
<antcall target="sign-windows-apps" />
</target>
</project>
Grüsse
Daniel
BTW: Grüsse aus Rapperswil...