<!--
  - @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
  -
  - @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
  - @author Ferdinand Thiessen <opensource@fthiessen.de>
  -
  - @license GNU AGPL version 3 or any later version
  -
  - This program is free software: you can redistribute it and/or modify
  - it under the terms of the GNU Affero General Public License as
  - published by the Free Software Foundation, either version 3 of the
  - License, or (at your option) any later version.
  -
  - This program is distributed in the hope that it will be useful,
  - but WITHOUT ANY WARRANTY; without even the implied warranty of
  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  - GNU Affero General Public License for more details.
  -
  - You should have received a copy of the GNU Affero General Public License
  - along with this program.  If not, see <http://www.gnu.org/licenses/>.
  -->

<template>
	<tr :class="['auth-token', { 'auth-token--wiping': wiping }]" :data-id="token.id">
		<td class="auth-token__name">
			<NcIconSvgWrapper :path="tokenIcon" />
			<div class="auth-token__name-wrapper">
				<form v-if="token.canRename && renaming"
					class="auth-token__name-form"
					@submit.prevent.stop="rename">
					<NcTextField ref="input"
						:value.sync="newName"
						:label="t('settings', 'Device name')"
						:show-trailing-button="true"
						:trailing-button-label="t('settings', 'Cancel renaming')"
						@trailing-button-click="cancelRename"
						@keyup.esc="cancelRename" />
					<NcButton :aria-label="t('settings', 'Save new name')" type="tertiary" native-type="submit">
						<template #icon>
							<NcIconSvgWrapper :path="mdiCheck" />
						</template>
					</NcButton>
				</form>
				<span v-else>{{ tokenLabel }}</span>
				<span v-if="wiping" class="wiping-warning">({{ t('settings', 'Marked for remote wipe') }})</span>
			</div>
		</td>
		<td>
			<NcDateTime class="auth-token__last-activity"
				:ignore-seconds="true"
				:timestamp="tokenLastActivity" />
		</td>
		<td class="auth-token__actions">
			<NcActions v-if="!token.current"
				:title="t('settings', 'Device settings')"
				:aria-label="t('settings', 'Device settings')"
				:open.sync="actionOpen">
				<NcActionCheckbox v-if="canChangeScope"
					:checked="token.scope.filesystem"
					@update:checked="updateFileSystemScope">
					<!-- TODO: add text/longtext with some description -->
					{{ t('settings', 'Allow filesystem access') }}
				</NcActionCheckbox>
				<NcActionButton v-if="token.canRename"
					icon="icon-rename"
					@click.stop.prevent="startRename">
					<!-- TODO: add text/longtext with some description -->
					{{ t('settings', 'Rename') }}
				</NcActionButton>

				<!-- revoke & wipe -->
				<template v-if="token.canDelete">
					<template v-if="token.type !== 2">
						<NcActionButton icon="icon-delete"
							@click.stop.prevent="revoke">
							<!-- TODO: add text/longtext with some description -->
							{{ t('settings', 'Revoke') }}
						</NcActionButton>
						<NcActionButton icon="icon-delete"
							@click.stop.prevent="wipe">
							{{ t('settings', 'Wipe device') }}
						</NcActionButton>
					</template>
					<NcActionButton v-else-if="token.type === 2"
						icon="icon-delete"
						:name="t('settings', 'Revoke')"
						@click.stop.prevent="revoke">
						{{ t('settings', 'Revoking this token might prevent the wiping of your device if it has not started the wipe yet.') }}
					</NcActionButton>
				</template>
			</NcActions>
		</td>
	</tr>
</template>

<script lang="ts">
import type { PropType } from 'vue'
import type { IToken } from '../store/authtoken'

import { mdiCheck, mdiCellphone, mdiTablet, mdiMonitor, mdiWeb, mdiKey, mdiMicrosoftEdge, mdiFirefox, mdiGoogleChrome, mdiAppleSafari, mdiAndroid, mdiAppleIos } from '@mdi/js'
import { translate as t } from '@nextcloud/l10n'
import { defineComponent } from 'vue'
import { TokenType, useAuthTokenStore } from '../store/authtoken.ts'

import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
import NcActionCheckbox from '@nextcloud/vue/dist/Components/NcActionCheckbox.js'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcDateTime from '@nextcloud/vue/dist/Components/NcDateTime.js'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'

// When using capture groups the following parts are extracted the first is used as the version number, the second as the OS
const userAgentMap = {
	ie: /(?:MSIE|Trident|Trident\/7.0; rv)[ :](\d+)/,
	// Microsoft Edge User Agent from https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
	edge: /^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[0-9.]+ (?:Mobile Safari|Safari)\/[0-9.]+ Edge\/[0-9.]+$/,
	// Firefox User Agent from https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference
	firefox: /^Mozilla\/5\.0 \([^)]*(Windows|OS X|Linux)[^)]+\) Gecko\/[0-9.]+ Firefox\/(\d+)(?:\.\d)?$/,
	// Chrome User Agent from https://developer.chrome.com/multidevice/user-agent
	chrome: /^Mozilla\/5\.0 \([^)]*(Windows|OS X|Linux)[^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/(\d+)[0-9.]+ (?:Mobile Safari|Safari)\/[0-9.]+$/,
	// Safari User Agent from http://www.useragentstring.com/pages/Safari/
	safari: /^Mozilla\/5\.0 \([^)]*(Windows|OS X)[^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)(?: Version\/([0-9]+)[0-9.]+)? Safari\/[0-9.A-Z]+$/,
	// Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent
	androidChrome: /Android.*(?:; (.*) Build\/).*Chrome\/(\d+)[0-9.]+/,
	iphone: / *CPU +iPhone +OS +([0-9]+)_(?:[0-9_])+ +like +Mac +OS +X */,
	ipad: /\(iPad; *CPU +OS +([0-9]+)_(?:[0-9_])+ +like +Mac +OS +X */,
	iosClient: /^Mozilla\/5\.0 \(iOS\) (?:ownCloud|Nextcloud)-iOS.*$/,
	androidClient: /^Mozilla\/5\.0 \(Android\) (?:ownCloud|Nextcloud)-android.*$/,
	iosTalkClient: /^Mozilla\/5\.0 \(iOS\) Nextcloud-Talk.*$/,
	androidTalkClient: /^Mozilla\/5\.0 \(Android\) Nextcloud-Talk.*$/,
	// DAVx5/3.3.8-beta2-gplay (2021/01/02; dav4jvm; okhttp/4.9.0) Android/10
	davx5: /DAV(?:droid|x5)\/([^ ]+)/,
	// Mozilla/5.0 (U; Linux; Maemo; Jolla; Sailfish; like Android 4.3) AppleWebKit/538.1 (KHTML, like Gecko) WebPirate/2.0 like Mobile Safari/538.1 (compatible)
	webPirate: /(Sailfish).*WebPirate\/(\d+)/,
	// Mozilla/5.0 (Maemo; Linux; U; Jolla; Sailfish; Mobile; rv:31.0) Gecko/31.0 Firefox/31.0 SailfishBrowser/1.0
	sailfishBrowser: /(Sailfish).*SailfishBrowser\/(\d+)/,
	// Neon 1.0.0+1
	neon: /Neon \d+\.\d+\.\d+\+\d+/,
}
const nameMap = {
	edge: 'Microsoft Edge',
	firefox: 'Firefox',
	chrome: 'Google Chrome',
	safari: 'Safari',
	androidChrome: t('settings', 'Google Chrome for Android'),
	iphone: 'iPhone',
	ipad: 'iPad',
	iosClient: t('settings', '{productName} iOS app', { productName: window.oc_defaults.productName }),
	androidClient: t('settings', '{productName} Android app', { productName: window.oc_defaults.productName }),
	iosTalkClient: t('settings', '{productName} Talk for iOS', { productName: window.oc_defaults.productName }),
	androidTalkClient: t('settings', '{productName} Talk for Android', { productName: window.oc_defaults.productName }),
	syncClient: t('settings', 'Sync client'),
	davx5: 'DAVx5',
	webPirate: 'WebPirate',
	sailfishBrowser: 'SailfishBrowser',
	neon: 'Neon',
}

export default defineComponent({
	name: 'AuthToken',
	components: {
		NcActions,
		NcActionButton,
		NcActionCheckbox,
		NcButton,
		NcDateTime,
		NcIconSvgWrapper,
		NcTextField,
	},
	props: {
		token: {
			type: Object as PropType<IToken>,
			required: true,
		},
	},
	setup() {
		const authTokenStore = useAuthTokenStore()
		return { authTokenStore }
	},
	data() {
		return {
			actionOpen: false,
			renaming: false,
			newName: '',
			oldName: '',
			mdiCheck,
		}
	},
	computed: {
		canChangeScope() {
			return this.token.type === TokenType.PERMANENT_TOKEN
		},
		/**
		 * Object ob the current user agend used by the token
		 * @return Either an object containing user agent information or null if unknown
		 */
		client() {
			// pretty format sync client user agent
			const matches = this.token.name.match(/Mozilla\/5\.0 \((\w+)\) (?:mirall|csyncoC)\/(\d+\.\d+\.\d+)/)

			if (matches) {
				return {
					id: 'syncClient',
					os: matches[1],
					version: matches[2],
				}
			}

			for (const client in userAgentMap) {
				const matches = this.token.name.match(userAgentMap[client])
				if (matches) {
					return {
						id: client,
						os: matches[2] && matches[1],
						version: matches[2] ?? matches[1],
					}
				}
			}

			return null
		},
		/**
		 * Last activity of the token as ECMA timestamp (in ms)
		 */
		tokenLastActivity() {
			return this.token.lastActivity * 1000
		},
		/**
		 * Icon to use for the current token
		 */
		tokenIcon() {
			// For custom created app tokens / app passwords
			if (this.token.type === TokenType.PERMANENT_TOKEN) {
				return mdiKey
			}

			switch (this.client?.id) {
			case 'edge':
				return mdiMicrosoftEdge
			case 'firefox':
				return mdiFirefox
			case 'chrome':
				return mdiGoogleChrome
			case 'safari':
				return mdiAppleSafari
			case 'androidChrome':
			case 'androidClient':
			case 'androidTalkClient':
				return mdiAndroid
			case 'iphone':
			case 'iosClient':
			case 'iosTalkClient':
				return mdiAppleIos
			case 'ipad':
				return mdiTablet
			case 'davx5':
				return mdiCellphone
			case 'syncClient':
				return mdiMonitor
			case 'webPirate':
			case 'sailfishBrowser':
			default:
				return mdiWeb
			}
		},
		/**
		 * Label to be shown for current token
		 */
		tokenLabel() {
			if (this.token.current) {
				return t('settings', 'This session')
			}
			if (this.client === null) {
				return this.token.name
			}

			const name = nameMap[this.client.id]
			if (this.client.os) {
				return t('settings', '{client} - {version} ({system})', { client: name, system: this.client.os, version: this.client.version })
			} else if (this.client.version) {
				return t('settings', '{client} - {version}', { client: name, version: this.client.version })
			}
			return name
		},
		/**
		 * If the current token is considered for remote wiping
		 */
		wiping() {
			return this.token.type === TokenType.WIPING_TOKEN
		},
	},
	methods: {
		t,
		updateFileSystemScope(state: boolean) {
			this.authTokenStore.setTokenScope(this.token, 'filesystem', state)
		},
		startRename() {
			// Close action (popover menu)
			this.actionOpen = false

			this.oldName = this.token.name
			this.newName = this.token.name
			this.renaming = true
			this.$nextTick(() => {
				this.$refs.input!.select()
			})
		},
		cancelRename() {
			this.renaming = false
		},
		revoke() {
			this.actionOpen = false
			this.authTokenStore.deleteToken(this.token)
		},
		rename() {
			this.renaming = false
			this.authTokenStore.renameToken(this.token, this.newName)
		},
		wipe() {
			this.actionOpen = false
			this.authTokenStore.wipeToken(this.token)
		},
	},
})
</script>

<style lang="scss" scoped>
.auth-token {
	border-top: 2px solid var(--color-border);
	max-width: 200px;
	white-space: normal;
	vertical-align: middle;
	position: relative;

	&--wiping {
		background-color: var(--color-background-dark);
	}

	&__name {
		padding-block: 10px;
		display: flex;
		align-items: center;
		gap: 6px;
		min-width: 355px; // ensure no jumping when renaming
	}

	&__name-wrapper {
		display: flex;
		flex-direction: column;
	}

	&__name-form {
		align-items: end;
		display: flex;
		gap: 4px;
	}

	&__actions {
		padding: 0 10px;
	}

	&__last-activity {
		padding-inline-start: 10px;
	}

	.wiping-warning {
		color: var(--color-text-maxcontrast);
	}
}
</style>
kground-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */</style><div class="highlight"><pre><span></span><span class="cm">&lt;!-- @author Wes Isberg --&gt;</span>
<span class="cm">&lt;!-- START-SAMPLE j2ee-tomcat4-precompileJsp Precompile JSP&#39;s for Tomcat 4.x using AspectJ --&gt;</span>
<span class="nt">&lt;project</span> <span class="na">name=</span><span class="s">&quot;Precompile Tomcat JSPs&quot;</span> <span class="na">default=</span><span class="s">&quot;all&quot;</span> <span class="na">basedir=</span><span class="s">&quot;.&quot;</span><span class="nt">&gt;</span><span class="w"> </span>

<span class="w">    </span><span class="nt">&lt;target</span> <span class="na">name=</span><span class="s">&quot;all&quot;</span> <span class="na">depends=</span><span class="s">&quot;jspc,compile&quot;/</span><span class="nt">&gt;</span>

<span class="w">	</span><span class="nt">&lt;target</span> <span class="na">name=</span><span class="s">&quot;info&quot;</span><span class="nt">&gt;</span>
<span class="w">		</span><span class="nt">&lt;echo&gt;</span>
This<span class="w"> </span>Ant<span class="w"> </span>script<span class="w"> </span>precompiles<span class="w"> </span>deployed<span class="w"> </span>.jsp<span class="w"> </span>files<span class="w"> </span>in<span class="w"> </span>Tomcat<span class="w"> </span>
using<span class="w"> </span>AspectJ<span class="w"> </span>1.1.

Usage:

<span class="w">  </span>{ant}<span class="w"> </span>-f<span class="w"> </span>{this-script}<span class="w"> </span>\
<span class="w">    </span>-Dtomcat.home=/home/tomcat<span class="w"> </span>\
<span class="w">    </span>-Dwebapp.name=launchWeb<span class="w"> </span>\
<span class="w">    </span>-DASPECTJ_HOME=/dev/tools/aspectj-1.1.0
<span class="w">		</span>

This<span class="w"> </span>defines<span class="w"> </span>the<span class="w"> </span>web<span class="w"> </span>application<span class="w"> </span>deployment<span class="w"> </span>$${webapp.dir}<span class="w"> </span>as

<span class="w">   </span>$${tomcat.home}/webapps/$${webapp.name}

,<span class="w"> </span>generates<span class="w"> </span>the<span class="w"> </span>Java<span class="w"> </span>source<span class="w"> </span>files<span class="w"> </span>to<span class="w"> </span>

<span class="w">   </span>$${webapp.dir}/WEB-INF/src

,<span class="w"> </span>uses<span class="w"> </span>iajc<span class="w"> </span>(AspectJ)<span class="w"> </span>to<span class="w"> </span>compile<span class="w"> </span>them<span class="w"> </span>to

<span class="w">   </span>$${webapp.dir}/WEB-INF/classes,

,<span class="w"> </span>and<span class="w"> </span>creates<span class="w"> </span>the<span class="w"> </span>mappings

<span class="w">   </span>$${webapp.dir}/WEB-INF/generated_web.xml,

which<span class="w"> </span>must<span class="w"> </span>be<span class="w"> </span>manually<span class="w"> </span>inserted<span class="w"> </span>into<span class="w"> </span>

<span class="w">   </span>$${webapp.dir}/WEB-INF/generated_web.xml,

at<span class="w"> </span>which<span class="w"> </span>point<span class="w"> </span>the<span class="w"> </span>web<span class="w"> </span>application<span class="w"> </span>can<span class="w"> </span>be<span class="w"> </span>reloaded.

This<span class="w"> </span>assumes<span class="w"> </span>that<span class="w"> </span>aspectjrt.jar<span class="w"> </span>is<span class="w"> </span>already<span class="w"> </span>deployed<span class="w"> </span>in<span class="w"> </span>
any<span class="w"> </span>of<span class="w"> </span>places<span class="w"> </span>on<span class="w"> </span>the<span class="w"> </span>Tomcat<span class="w"> </span>application<span class="w"> </span>classpath<span class="w"> </span>
(the<span class="w"> </span>application,<span class="w"> </span>shared,<span class="w"> </span>or<span class="w"> </span>common<span class="w"> </span>classpath).
If<span class="w"> </span>ASPECTJ_HOME<span class="w"> </span>is<span class="w"> </span>not<span class="w"> </span>defined,<span class="w"> </span>it<span class="w"> </span>assumes<span class="w"> </span>that
aspectjtools.jar<span class="w"> </span>is<span class="w"> </span>in<span class="w"> </span>

<span class="w">   </span><span class="cp">${</span><span class="n">CATALINA_HOME</span><span class="cp">}</span>/common/lib

<span class="nt">&lt;/echo&gt;</span>
<span class="w">	</span><span class="nt">&lt;/target&gt;</span>
<span class="w">	</span>
<span class="w">  </span><span class="nt">&lt;target</span> <span class="na">name=</span><span class="s">&quot;init&quot;</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">	</span><span class="cm">&lt;!-- declare these two on command-line --&gt;</span>
<span class="w">	</span><span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;webapp.name&quot;</span>
		<span class="na">value=</span><span class="s">&quot;launchWeb&quot;/</span><span class="nt">&gt;</span>
<span class="w">		</span>
<span class="w">	</span><span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;tomcat.home&quot;</span>
		<span class="na">location=</span><span class="s">&quot;i:/home/tomcat&quot;/</span><span class="nt">&gt;</span>
<span class="w">	</span>
<span class="w">	</span><span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;webapp.path&quot;</span>
		<span class="na">location=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">tomcat</span><span class="o">.</span><span class="n">home</span><span class="cp">}</span><span class="s">/webapps/</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">name</span><span class="cp">}</span><span class="s">&quot;/</span><span class="nt">&gt;</span>
<span class="w">	</span><span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;webapp.src.dir&quot;</span>
		<span class="na">location=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">path</span><span class="cp">}</span><span class="s">/WEB-INF/src&quot;/</span><span class="nt">&gt;</span>

<span class="w">	</span><span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;ASPECTJ_HOME&quot;</span>
		<span class="na">location=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">tomcat</span><span class="o">.</span><span class="n">home</span><span class="cp">}</span><span class="s">/common&quot;/</span><span class="nt">&gt;</span>
<span class="w">	</span>
<span class="w">  </span><span class="nt">&lt;/target&gt;</span>
<span class="w">	</span>
<span class="w">  </span><span class="nt">&lt;target</span> <span class="na">name=</span><span class="s">&quot;jspc&quot;</span> <span class="na">depends=</span><span class="s">&quot;init&quot;</span><span class="nt">&gt;</span><span class="w"> </span>

<span class="w">    </span><span class="nt">&lt;taskdef</span> <span class="na">classname=</span><span class="s">&quot;org.apache.jasper.JspC&quot;</span> <span class="na">name=</span><span class="s">&quot;jasper2&quot;</span> <span class="nt">&gt;</span><span class="w"> </span>
<span class="w">      </span><span class="nt">&lt;classpath</span> <span class="na">id=</span><span class="s">&quot;jspc.classpath&quot;</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">        </span><span class="nt">&lt;pathelement</span> <span class="na">location=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">java</span><span class="o">.</span><span class="n">home</span><span class="cp">}</span><span class="s">/../lib/tools.jar&quot;/</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">        </span><span class="nt">&lt;fileset</span> <span class="na">dir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">tomcat</span><span class="o">.</span><span class="n">home</span><span class="cp">}</span><span class="s">/server/lib&quot;</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">          </span><span class="nt">&lt;include</span> <span class="na">name=</span><span class="s">&quot;*.jar&quot;/</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">        </span><span class="nt">&lt;/fileset&gt;</span><span class="w"> </span>
<span class="w">        </span><span class="nt">&lt;fileset</span> <span class="na">dir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">tomcat</span><span class="o">.</span><span class="n">home</span><span class="cp">}</span><span class="s">/common/lib&quot;</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">          </span><span class="nt">&lt;include</span> <span class="na">name=</span><span class="s">&quot;*.jar&quot;/</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">        </span><span class="nt">&lt;/fileset&gt;</span><span class="w"> </span>
<span class="w">      </span><span class="nt">&lt;/classpath&gt;</span><span class="w"> </span>
<span class="w">    </span><span class="nt">&lt;/taskdef&gt;</span><span class="w"> </span>

<span class="w">	</span><span class="nt">&lt;mkdir</span> <span class="na">dir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">src</span><span class="o">.</span><span class="n">dir</span><span class="cp">}</span><span class="s">&quot;/</span><span class="nt">&gt;</span>
<span class="w">    </span><span class="nt">&lt;jasper2</span> 
		 <span class="na">validateXml=</span><span class="s">&quot;true&quot;</span> 
		 <span class="na">uriroot=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">path</span><span class="cp">}</span><span class="s">&quot;</span> 
		 <span class="na">webXmlFragment=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">path</span><span class="cp">}</span><span class="s">/WEB-INF/generated_web.xml&quot;</span> 
		 <span class="na">outputDir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">src</span><span class="o">.</span><span class="n">dir</span><span class="cp">}</span><span class="s">&quot;</span> <span class="nt">/&gt;</span><span class="w"> </span>

<span class="w">  </span><span class="nt">&lt;/target&gt;</span><span class="w"> </span>

<span class="w">  </span><span class="nt">&lt;target</span> <span class="na">name=</span><span class="s">&quot;compile&quot;</span> <span class="na">depends=</span><span class="s">&quot;init&quot;</span><span class="nt">&gt;</span>

<span class="w">    </span><span class="nt">&lt;mkdir</span> <span class="na">dir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">path</span><span class="cp">}</span><span class="s">/WEB-INF/classes&quot;/</span><span class="nt">&gt;</span>
<span class="w">    </span><span class="nt">&lt;mkdir</span> <span class="na">dir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">path</span><span class="cp">}</span><span class="s">/WEB-INF/lib&quot;/</span><span class="nt">&gt;</span>
<span class="w">    </span>
<span class="w">      </span><span class="nt">&lt;path</span> <span class="na">id=</span><span class="s">&quot;iajc.classpath&quot;</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">        </span><span class="nt">&lt;fileset</span> <span class="na">dir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">ASPECTJ_HOME</span><span class="cp">}</span><span class="s">/lib&quot;</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">          </span><span class="nt">&lt;include</span> <span class="na">name=</span><span class="s">&quot;aspectjtools.jar&quot;/</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">        </span><span class="nt">&lt;/fileset&gt;</span><span class="w"> </span>
<span class="w">      </span><span class="nt">&lt;/path&gt;</span><span class="w"> </span>
<span class="w">	</span><span class="nt">&lt;taskdef</span> 
      <span class="na">resource=</span><span class="s">&quot;org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties&quot;</span><span class="nt">&gt;</span>
<span class="w">      </span><span class="nt">&lt;classpath</span> <span class="na">refid=</span><span class="s">&quot;iajc.classpath&quot;/</span><span class="nt">&gt;</span><span class="w"> </span>
<span class="w">    </span><span class="nt">&lt;/taskdef&gt;</span><span class="w"> </span>

<span class="w">	</span><span class="cm">&lt;!-- forking compile so it runs in Eclipse --&gt;</span>
<span class="w">    </span><span class="nt">&lt;iajc</span> <span class="na">destdir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">path</span><span class="cp">}</span><span class="s">/WEB-INF/classes&quot;</span>
           <span class="na">sourceroots=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">src</span><span class="o">.</span><span class="n">dir</span><span class="cp">}</span><span class="s">&quot;</span>
           <span class="na">debug=</span><span class="s">&quot;on&quot;</span> 
           <span class="na">verbose=</span><span class="s">&quot;true&quot;</span>
           <span class="na">fork=</span><span class="s">&quot;true&quot;</span> 
           <span class="na">forkclasspathRef=</span><span class="s">&quot;iajc.classpath&quot;</span>
           <span class="na">failonerror=</span><span class="s">&quot;true&quot;</span>
           <span class="nt">&gt;</span>
<span class="w">      </span><span class="nt">&lt;classpath&gt;</span>
<span class="w">        </span><span class="nt">&lt;pathelement</span> <span class="na">location=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">path</span><span class="cp">}</span><span class="s">/WEB-INF/classes&quot;/</span><span class="nt">&gt;</span>
<span class="w">        </span><span class="nt">&lt;fileset</span> <span class="na">dir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">webapp</span><span class="o">.</span><span class="n">path</span><span class="cp">}</span><span class="s">/WEB-INF/lib&quot;</span><span class="nt">&gt;</span>
<span class="w">          </span><span class="nt">&lt;include</span> <span class="na">name=</span><span class="s">&quot;*.jar&quot;/</span><span class="nt">&gt;</span>
<span class="w">        </span><span class="nt">&lt;/fileset&gt;</span>
<span class="w">        </span><span class="nt">&lt;pathelement</span> <span class="na">location=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">tomcat</span><span class="o">.</span><span class="n">home</span><span class="cp">}</span><span class="s">/common/classes&quot;/</span><span class="nt">&gt;</span>
<span class="w">        </span><span class="nt">&lt;fileset</span> <span class="na">dir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">tomcat</span><span class="o">.</span><span class="n">home</span><span class="cp">}</span><span class="s">/common/lib&quot;</span><span class="nt">&gt;</span>
<span class="w">          </span><span class="nt">&lt;include</span> <span class="na">name=</span><span class="s">&quot;*.jar&quot;/</span><span class="nt">&gt;</span>
<span class="w">        </span><span class="nt">&lt;/fileset&gt;</span>
<span class="w">        </span><span class="nt">&lt;pathelement</span> <span class="na">location=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">tomcat</span><span class="o">.</span><span class="n">home</span><span class="cp">}</span><span class="s">/shared/classes&quot;/</span><span class="nt">&gt;</span>
<span class="w">        </span><span class="nt">&lt;fileset</span> <span class="na">dir=</span><span class="s">&quot;</span><span class="cp">${</span><span class="n">tomcat</span><span class="o">.</span><span class="n">home</span><span class="cp">}</span><span class="s">/shared/lib&quot;</span><span class="nt">&gt;</span>
<span class="w">          </span><span class="nt">&lt;include</span> <span class="na">name=</span><span class="s">&quot;*.jar&quot;/</span><span class="nt">&gt;</span>
<span class="w">        </span><span class="nt">&lt;/fileset&gt;</span>
<span class="w">      </span><span class="nt">&lt;/classpath&gt;</span>
<span class="w">    </span><span class="nt">&lt;/iajc&gt;</span>

<span class="w">  </span><span class="nt">&lt;/target&gt;</span>

<span class="nt">&lt;/project&gt;</span>
<span class="cm">&lt;!-- END-SAMPLE j2ee-tomcat4-precompileJsp --&gt;</span>
</pre></div>
