mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-30 15:04:25 +08:00
527 lines
18 KiB
PowerShell
527 lines
18 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[string]$Project = "LanMountainDesktop.csproj",
|
|
[string]$Configuration = "Release",
|
|
[string]$RuntimeIdentifier = "win-x64",
|
|
[string]$Version = "",
|
|
[string]$PublishDir = "",
|
|
[string]$InstallerOutputDir = "",
|
|
[string]$OnlineInstallerOutputDir = "",
|
|
[string]$ArchiveOutputDir = "",
|
|
[string]$InnoScript = "",
|
|
[string]$InnoCompiler = "",
|
|
[switch]$SkipInstaller,
|
|
[switch]$SkipOnlineInstaller,
|
|
[switch]$SkipArchive,
|
|
[switch]$KeepSymbols
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Resolve-ExistingPath {
|
|
param([Parameter(Mandatory = $true)][string]$PathValue)
|
|
$resolved = Resolve-Path -LiteralPath $PathValue -ErrorAction Stop
|
|
return $resolved.Path
|
|
}
|
|
|
|
function Is-WindowsRuntimeIdentifier {
|
|
param([Parameter(Mandatory = $true)][string]$Rid)
|
|
return $Rid -like "win-*"
|
|
}
|
|
|
|
function Find-InnoCompiler {
|
|
param([string]$ExplicitPath = "")
|
|
|
|
if ($ExplicitPath) {
|
|
if (Test-Path -LiteralPath $ExplicitPath) {
|
|
return (Resolve-ExistingPath -PathValue $ExplicitPath)
|
|
}
|
|
throw "Inno compiler not found at explicit path: $ExplicitPath"
|
|
}
|
|
|
|
$fromPath = Get-Command iscc.exe -ErrorAction SilentlyContinue
|
|
if ($fromPath -and (Test-Path -LiteralPath $fromPath.Source)) {
|
|
return (Resolve-ExistingPath -PathValue $fromPath.Source)
|
|
}
|
|
|
|
$candidates = @(
|
|
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe",
|
|
"C:\Program Files\Inno Setup 6\ISCC.exe"
|
|
)
|
|
|
|
foreach ($candidate in $candidates) {
|
|
if (Test-Path -LiteralPath $candidate) {
|
|
return (Resolve-ExistingPath -PathValue $candidate)
|
|
}
|
|
}
|
|
|
|
throw "ISCC.exe not found. Install Inno Setup 6 or pass -InnoCompiler."
|
|
}
|
|
|
|
function Read-VersionFromProject {
|
|
param([Parameter(Mandatory = $true)][string]$ProjectFile)
|
|
|
|
[xml]$xml = Get-Content -LiteralPath $ProjectFile -Raw
|
|
$versionNode = $xml.Project.PropertyGroup | ForEach-Object { $_.Version } | Where-Object { $_ } | Select-Object -First 1
|
|
if ($versionNode) {
|
|
return $versionNode.Trim()
|
|
}
|
|
return "0.1.0"
|
|
}
|
|
|
|
function Remove-LibVlcForOtherArch {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$PublishedDirectory,
|
|
[Parameter(Mandatory = $true)][string]$Rid
|
|
)
|
|
|
|
$libVlcRoot = Join-Path $PublishedDirectory "libvlc"
|
|
if (-not (Test-Path -LiteralPath $libVlcRoot)) {
|
|
return
|
|
}
|
|
|
|
$dirsToDelete = @()
|
|
if ($Rid -eq "win-x64") {
|
|
$dirsToDelete += (Join-Path $libVlcRoot "win-x86")
|
|
} elseif ($Rid -eq "win-x86") {
|
|
$dirsToDelete += (Join-Path $libVlcRoot "win-x64")
|
|
} elseif (-not (Is-WindowsRuntimeIdentifier -Rid $Rid)) {
|
|
$dirsToDelete += (Join-Path $libVlcRoot "win-x64")
|
|
$dirsToDelete += (Join-Path $libVlcRoot "win-x86")
|
|
}
|
|
|
|
foreach ($dir in $dirsToDelete) {
|
|
if (-not (Test-Path -LiteralPath $dir)) {
|
|
continue
|
|
}
|
|
|
|
$pruned = $false
|
|
try {
|
|
[System.IO.Directory]::Delete($dir, $true)
|
|
$pruned = $true
|
|
} catch {
|
|
if (-not (Test-Path -LiteralPath $dir)) {
|
|
$pruned = $true
|
|
} else {
|
|
Write-Warning "Prune retry for '$dir': $($_.Exception.Message)"
|
|
try {
|
|
Remove-Item -LiteralPath $dir -Recurse -Force -ErrorAction Stop
|
|
$pruned = $true
|
|
} catch {
|
|
if (-not (Test-Path -LiteralPath $dir)) {
|
|
$pruned = $true
|
|
} else {
|
|
throw "Failed to prune '$dir': $($_.Exception.Message)"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($pruned) {
|
|
Write-Host "Pruned: $dir"
|
|
}
|
|
}
|
|
}
|
|
|
|
function Create-PackageArchive {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$SourceDirectory,
|
|
[Parameter(Mandatory = $true)][string]$DestinationDirectory,
|
|
[Parameter(Mandatory = $true)][string]$VersionValue,
|
|
[Parameter(Mandatory = $true)][string]$Rid
|
|
)
|
|
|
|
[System.IO.Directory]::CreateDirectory($DestinationDirectory) | Out-Null
|
|
|
|
$archiveName = "LanMountainDesktop-$VersionValue-$Rid.zip"
|
|
$archivePath = Join-Path $DestinationDirectory $archiveName
|
|
if (Test-Path -LiteralPath $archivePath) {
|
|
[System.IO.File]::Delete($archivePath)
|
|
}
|
|
|
|
Compress-Archive -Path (Join-Path $SourceDirectory "*") -DestinationPath $archivePath -Force
|
|
return $archivePath
|
|
}
|
|
|
|
function Clear-DirectoryContents {
|
|
param([Parameter(Mandatory = $true)][string]$TargetDirectory)
|
|
|
|
[System.IO.Directory]::CreateDirectory($TargetDirectory) | Out-Null
|
|
Get-ChildItem -LiteralPath $TargetDirectory -Force -ErrorAction SilentlyContinue | ForEach-Object {
|
|
Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction Stop
|
|
}
|
|
}
|
|
|
|
function Remove-LegacyOutputArtifacts {
|
|
param([Parameter(Mandatory = $true)][string]$TargetDirectory)
|
|
|
|
$legacyArtifacts = @(
|
|
"LanMontainDesktop.exe",
|
|
"LanMontainDesktop.dll",
|
|
"LanMontainDesktop.deps.json",
|
|
"LanMontainDesktop.runtimeconfig.json",
|
|
"LanMontainDesktop.pdb"
|
|
)
|
|
|
|
foreach ($artifactName in $legacyArtifacts) {
|
|
$artifactPath = Join-Path $TargetDirectory $artifactName
|
|
if (-not (Test-Path -LiteralPath $artifactPath)) {
|
|
continue
|
|
}
|
|
|
|
Remove-Item -LiteralPath $artifactPath -Force -ErrorAction Stop
|
|
Write-Host "Removed legacy artifact: $artifactPath"
|
|
}
|
|
}
|
|
|
|
function Add-LinuxDesktopAssets {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$PublishedDirectory,
|
|
[Parameter(Mandatory = $true)][string]$RepoRoot
|
|
)
|
|
|
|
$resourcesRoot = Join-Path $RepoRoot "packaging/linux"
|
|
$desktopTemplate = Join-Path $resourcesRoot "LanMountainDesktop.desktop"
|
|
$iconSource = Join-Path $resourcesRoot "lanmountaindesktop.png"
|
|
$installScriptSource = Join-Path $resourcesRoot "install.sh"
|
|
|
|
foreach ($requiredPath in @($desktopTemplate, $iconSource, $installScriptSource)) {
|
|
if (-not (Test-Path -LiteralPath $requiredPath)) {
|
|
throw "Linux packaging resource is missing: $requiredPath"
|
|
}
|
|
}
|
|
|
|
$applicationsDir = Join-Path $PublishedDirectory "share/applications"
|
|
$iconsDir = Join-Path $PublishedDirectory "share/icons/hicolor/256x256/apps"
|
|
[System.IO.Directory]::CreateDirectory($applicationsDir) | Out-Null
|
|
[System.IO.Directory]::CreateDirectory($iconsDir) | Out-Null
|
|
|
|
Copy-Item -LiteralPath $desktopTemplate -Destination (Join-Path $applicationsDir "LanMountainDesktop.desktop") -Force
|
|
Copy-Item -LiteralPath $iconSource -Destination (Join-Path $iconsDir "lanmountaindesktop.png") -Force
|
|
Copy-Item -LiteralPath $installScriptSource -Destination (Join-Path $PublishedDirectory "install.sh") -Force
|
|
}
|
|
|
|
function Invoke-PublishPayloadOptimization {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$PublishedDirectory,
|
|
[Parameter(Mandatory = $true)][string]$Rid
|
|
)
|
|
|
|
$optimizer = Join-Path $scriptRoot "Optimize-PublishPayload.ps1"
|
|
if (-not (Test-Path -LiteralPath $optimizer)) {
|
|
throw "Publish payload optimizer is missing: $optimizer"
|
|
}
|
|
|
|
& $optimizer `
|
|
-PublishDir $PublishedDirectory `
|
|
-RuntimeIdentifier $Rid `
|
|
-AssertClean `
|
|
-KeepSymbols:$KeepSymbols
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Publish payload optimization failed with exit code $LASTEXITCODE."
|
|
}
|
|
}
|
|
|
|
function Publish-AirAppHostPayload {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$PublishedDirectory,
|
|
[Parameter(Mandatory = $true)][string]$Rid,
|
|
[Parameter(Mandatory = $true)][string]$VersionValue
|
|
)
|
|
|
|
$airAppHostProject = Join-Path $repoRoot "..\LanMountainDesktop.AirAppHost\LanMountainDesktop.AirAppHost.csproj"
|
|
$airAppHostProject = Resolve-ExistingPath -PathValue $airAppHostProject
|
|
Write-Host "Publishing AirAppHost payload..."
|
|
$airPublishArgs = @(
|
|
"publish",
|
|
$airAppHostProject,
|
|
"-c", $Configuration,
|
|
"-r", $Rid,
|
|
"--self-contained", "false",
|
|
"-p:SelfContained=false",
|
|
"-p:PublishSingleFile=false",
|
|
"-p:PublishTrimmed=false",
|
|
"-p:PublishReadyToRun=false",
|
|
"-p:DebugType=None",
|
|
"-p:DebugSymbols=false",
|
|
"-p:BuildingAirAppHost=true",
|
|
"-p:SkipAirAppHostBuild=true",
|
|
"-p:Version=$VersionValue",
|
|
"-o", $PublishedDirectory
|
|
)
|
|
|
|
& dotnet @airPublishArgs
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "AirAppHost publish failed with exit code $LASTEXITCODE."
|
|
}
|
|
}
|
|
|
|
function Publish-AirAppRuntimePayload {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$PublishedDirectory,
|
|
[Parameter(Mandatory = $true)][string]$Rid,
|
|
[Parameter(Mandatory = $true)][string]$VersionValue
|
|
)
|
|
|
|
$airAppRuntimeProject = Join-Path $repoRoot "..\LanMountainDesktop.AirAppRuntime\LanMountainDesktop.AirAppRuntime.csproj"
|
|
$airAppRuntimeProject = Resolve-ExistingPath -PathValue $airAppRuntimeProject
|
|
Write-Host "Publishing AirAppRuntime framework-dependent JIT payload..."
|
|
$runtimePublishArgs = @(
|
|
"publish",
|
|
$airAppRuntimeProject,
|
|
"-c", $Configuration,
|
|
"-r", $Rid,
|
|
"--self-contained", "false",
|
|
"-p:SelfContained=false",
|
|
"-p:PublishAot=false",
|
|
"-p:PublishSingleFile=false",
|
|
"-p:PublishTrimmed=false",
|
|
"-p:PublishReadyToRun=false",
|
|
"-p:DebugType=None",
|
|
"-p:DebugSymbols=false",
|
|
"-p:Version=$VersionValue",
|
|
"-o", $PublishedDirectory
|
|
)
|
|
|
|
& dotnet @runtimePublishArgs
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "AirAppRuntime publish failed with exit code $LASTEXITCODE."
|
|
}
|
|
}
|
|
|
|
function Publish-LauncherPayload {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$PublishedDirectory,
|
|
[Parameter(Mandatory = $true)][string]$Rid,
|
|
[Parameter(Mandatory = $true)][string]$VersionValue
|
|
)
|
|
|
|
$launcherProject = Join-Path $repoRoot "..\LanMountainDesktop.Launcher\LanMountainDesktop.Launcher.csproj"
|
|
$launcherProject = Resolve-ExistingPath -PathValue $launcherProject
|
|
Write-Host "Publishing Launcher AOT payload..."
|
|
$launcherPublishArgs = @(
|
|
"publish",
|
|
$launcherProject,
|
|
"-c", $Configuration,
|
|
"-r", $Rid,
|
|
"--self-contained",
|
|
"-p:PublishAot=true",
|
|
"-p:PublishSingleFile=true",
|
|
"-p:IncludeNativeLibrariesForSelfExtract=true",
|
|
"-p:EnableCompressionInSingleFile=true",
|
|
"-p:DebugType=None",
|
|
"-p:DebugSymbols=false",
|
|
"-p:Version=$VersionValue",
|
|
"-o", $PublishedDirectory
|
|
)
|
|
|
|
& dotnet @launcherPublishArgs
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Launcher publish failed with exit code $LASTEXITCODE."
|
|
}
|
|
}
|
|
|
|
function Publish-MainAppFrameworkDependentPayload {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string]$ProjectFile,
|
|
[Parameter(Mandatory = $true)][string]$PublishedDirectory,
|
|
[Parameter(Mandatory = $true)][string]$Rid,
|
|
[Parameter(Mandatory = $true)][string]$VersionValue
|
|
)
|
|
|
|
Write-Host "Publishing framework-dependent main app payload..."
|
|
$publishArgs = @(
|
|
"publish",
|
|
$ProjectFile,
|
|
"-c", $Configuration,
|
|
"-r", $Rid,
|
|
"--self-contained", "false",
|
|
"-p:SelfContained=false",
|
|
"-p:PublishSingleFile=false",
|
|
"-p:PublishTrimmed=false",
|
|
"-p:PublishReadyToRun=false",
|
|
"-p:DebugType=None",
|
|
"-p:DebugSymbols=false",
|
|
"-p:SkipAirAppHostBuild=true",
|
|
"-p:Version=$VersionValue",
|
|
"-o", $PublishedDirectory
|
|
)
|
|
|
|
& dotnet @publishArgs
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "dotnet publish failed with exit code $LASTEXITCODE."
|
|
}
|
|
}
|
|
|
|
|
|
$scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$repoRoot = Resolve-ExistingPath -PathValue (Join-Path $scriptRoot "..")
|
|
|
|
$projectPath = $Project
|
|
if (-not [System.IO.Path]::IsPathRooted($projectPath)) {
|
|
$projectPath = Join-Path $repoRoot $projectPath
|
|
}
|
|
$projectPath = Resolve-ExistingPath -PathValue $projectPath
|
|
|
|
if (-not $Version) {
|
|
$Version = Read-VersionFromProject -ProjectFile $projectPath
|
|
}
|
|
|
|
if (-not $PublishDir) {
|
|
$PublishDir = Join-Path $repoRoot "artifacts/publish/$RuntimeIdentifier"
|
|
}
|
|
if (-not [System.IO.Path]::IsPathRooted($PublishDir)) {
|
|
$PublishDir = Join-Path $repoRoot $PublishDir
|
|
}
|
|
Clear-DirectoryContents -TargetDirectory $PublishDir
|
|
|
|
if (Is-WindowsRuntimeIdentifier -Rid $RuntimeIdentifier) {
|
|
$appPublishDir = Join-Path $PublishDir "app-$Version"
|
|
[System.IO.Directory]::CreateDirectory($appPublishDir) | Out-Null
|
|
|
|
Publish-LauncherPayload -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier -VersionValue $Version
|
|
Publish-AirAppRuntimePayload -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier -VersionValue $Version
|
|
Publish-MainAppFrameworkDependentPayload -ProjectFile $projectPath -PublishedDirectory $appPublishDir -Rid $RuntimeIdentifier -VersionValue $Version
|
|
Publish-AirAppHostPayload -PublishedDirectory $appPublishDir -Rid $RuntimeIdentifier -VersionValue $Version
|
|
New-Item -ItemType File -Path (Join-Path $appPublishDir ".current") -Force | Out-Null
|
|
|
|
Remove-LibVlcForOtherArch -PublishedDirectory $appPublishDir -Rid $RuntimeIdentifier
|
|
Remove-LegacyOutputArtifacts -TargetDirectory $appPublishDir
|
|
} else {
|
|
Write-Host "Publishing project..."
|
|
$publishArgs = @(
|
|
"publish",
|
|
$projectPath,
|
|
"-c", $Configuration,
|
|
"-r", $RuntimeIdentifier,
|
|
"--self-contained", "true",
|
|
"-p:PublishSingleFile=false",
|
|
"-p:PublishTrimmed=false",
|
|
"-p:DebugType=None",
|
|
"-p:DebugSymbols=false",
|
|
"-p:SkipAirAppHostBuild=true",
|
|
"-p:Version=$Version",
|
|
"-o", $PublishDir
|
|
)
|
|
|
|
& dotnet @publishArgs
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "dotnet publish failed with exit code $LASTEXITCODE."
|
|
}
|
|
|
|
Publish-AirAppHostPayload -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier -VersionValue $Version
|
|
Publish-AirAppRuntimePayload -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier -VersionValue $Version
|
|
Remove-LibVlcForOtherArch -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier
|
|
Remove-LegacyOutputArtifacts -TargetDirectory $PublishDir
|
|
|
|
if ($RuntimeIdentifier -like "linux-*") {
|
|
Add-LinuxDesktopAssets -PublishedDirectory $PublishDir -RepoRoot $repoRoot
|
|
}
|
|
}
|
|
|
|
Invoke-PublishPayloadOptimization -PublishedDirectory $PublishDir -Rid $RuntimeIdentifier
|
|
|
|
if (Is-WindowsRuntimeIdentifier -Rid $RuntimeIdentifier) {
|
|
if (-not $InstallerOutputDir) {
|
|
$InstallerOutputDir = Join-Path $repoRoot "artifacts/installer"
|
|
}
|
|
if (-not [System.IO.Path]::IsPathRooted($InstallerOutputDir)) {
|
|
$InstallerOutputDir = Join-Path $repoRoot $InstallerOutputDir
|
|
}
|
|
[System.IO.Directory]::CreateDirectory($InstallerOutputDir) | Out-Null
|
|
|
|
if (-not $SkipOnlineInstaller) {
|
|
if (-not $OnlineInstallerOutputDir) {
|
|
$OnlineInstallerOutputDir = Join-Path $repoRoot "artifacts/installer-online/$RuntimeIdentifier"
|
|
}
|
|
if (-not [System.IO.Path]::IsPathRooted($OnlineInstallerOutputDir)) {
|
|
$OnlineInstallerOutputDir = Join-Path $repoRoot $OnlineInstallerOutputDir
|
|
}
|
|
Clear-DirectoryContents -TargetDirectory $OnlineInstallerOutputDir
|
|
|
|
$onlineInstallerProject = Join-Path $repoRoot "LanDesktopPLONDS.installer/LanDesktopPLONDS.installer.csproj"
|
|
Write-Host "Publishing PLONDS online installer..."
|
|
$onlineInstallerArgs = @(
|
|
"publish",
|
|
$onlineInstallerProject,
|
|
"-c", $Configuration,
|
|
"-r", $RuntimeIdentifier,
|
|
"-p:Version=$Version",
|
|
"-p:PublishAot=true",
|
|
"-o", $OnlineInstallerOutputDir
|
|
)
|
|
|
|
& dotnet @onlineInstallerArgs
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Online installer publish failed with exit code $LASTEXITCODE."
|
|
}
|
|
|
|
Write-Host "Online installer published: $OnlineInstallerOutputDir"
|
|
}
|
|
|
|
if ($SkipInstaller) {
|
|
Write-Host "Publish completed. Installer step skipped."
|
|
Write-Host "Published files: $PublishDir"
|
|
exit 0
|
|
}
|
|
|
|
if (-not $InnoScript) {
|
|
$InnoScript = Join-Path $repoRoot "installer/LanMountainDesktop.iss"
|
|
}
|
|
if (-not [System.IO.Path]::IsPathRooted($InnoScript)) {
|
|
$InnoScript = Join-Path $repoRoot $InnoScript
|
|
}
|
|
$InnoScript = Resolve-ExistingPath -PathValue $InnoScript
|
|
|
|
$archForInstaller = "x64"
|
|
if ($RuntimeIdentifier -like "*x86*") {
|
|
$archForInstaller = "x86"
|
|
}
|
|
|
|
$isccPath = Find-InnoCompiler -ExplicitPath $InnoCompiler
|
|
|
|
Write-Host "Building installer..."
|
|
$isccArgs = @(
|
|
"/DMyAppVersion=$Version",
|
|
"/DPublishDir=$PublishDir",
|
|
"/DMyOutputDir=$InstallerOutputDir",
|
|
"/DMyAppArch=$archForInstaller",
|
|
$InnoScript
|
|
)
|
|
|
|
& $isccPath @isccArgs
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "ISCC failed with exit code $LASTEXITCODE."
|
|
}
|
|
|
|
$installer = Get-ChildItem -Path $InstallerOutputDir -File -Filter "*.exe" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
|
if ($null -ne $installer) {
|
|
Write-Host "Installer created: $($installer.FullName)"
|
|
} else {
|
|
Write-Host "Installer build finished, but no .exe was found in $InstallerOutputDir"
|
|
}
|
|
|
|
exit 0
|
|
}
|
|
|
|
if ($SkipArchive) {
|
|
Write-Host "Publish completed. Archive step skipped."
|
|
Write-Host "Published files: $PublishDir"
|
|
exit 0
|
|
}
|
|
|
|
if (-not $ArchiveOutputDir) {
|
|
$ArchiveOutputDir = Join-Path $repoRoot "artifacts/packages"
|
|
}
|
|
if (-not [System.IO.Path]::IsPathRooted($ArchiveOutputDir)) {
|
|
$ArchiveOutputDir = Join-Path $repoRoot $ArchiveOutputDir
|
|
}
|
|
|
|
$archivePath = Create-PackageArchive `
|
|
-SourceDirectory $PublishDir `
|
|
-DestinationDirectory $ArchiveOutputDir `
|
|
-VersionValue $Version `
|
|
-Rid $RuntimeIdentifier
|
|
|
|
Write-Host "Archive created: $archivePath"
|