Posted on 02-19-2016 03:33 PM
Adobe must have lost a competent person and hired a newbee to head up the Adobe DC team.
This new versioning system is completely insane. But why am I not surprised?.
EA to identify Acrobat Reader DC (Continuous) 15.010.20056 thru 17.x, so we can deploy patches without inadvertently rolling anyone back. Ugh.
Any suggestions to shorten this is most welcome...
...[snip]...
...[snip]...
...[snip]...
EDIT: Removing the long list of "Like" to avoid confusion, after getting pinged about it.
Solved! Go to Solution.
Posted on 02-20-2016 05:59 PM
More python-ey way of doing the same thing as the script above.
https://gist.github.com/opragel/50c47c7c9c9100e3b1dd#file-ea_adobe_acrobat_dc_versioncheck-py
#!/usr/bin/python
"""
This script checks whether the installed version of Adobe Acrobat DC is
equal, less, or more than the target version defined by APP_TARGET_VERSION
and reports the result in Casper Suite extension attribute style.
T = Local app version is equal to provided current version
N = Local app version is newer than provided current version
F = Local app version is less than provided current version
N/A = Local app plist was not found at provided path
"""
import os.path
import plistlib
from pkg_resources import parse_version
APP_PATH = "/Applications/Adobe Acrobat DC/Adobe Acrobat.app"
APP_VERSION_KEY = "CFBundleShortVersionString"
APP_TARGET_VERSION = "15.010.20059"
def get_version_check_result(app_path, app_version_key, app_target_version):
"""
Reports T if the local app version is equal to target version, F if the
local app version is less than target version, N if the local app
version is greater than target version, and N/A if the plist is not found.
"""
app_plist_path = app_path + "/Contents/Info.plist"
if not os.path.isfile(app_plist_path):
version_check_result = "N/A"
else:
app_info_plist = plistlib.readPlist(app_plist_path)
app_version = app_info_plist[app_version_key]
if parse_version(app_target_version) == parse_version(app_version):
version_check_result = "T"
elif parse_version(app_target_version) < parse_version(app_version):
version_check_result = "N"
else:
version_check_result = "F"
return version_check_result
def main():
""" Executes script functions. """
result = get_version_check_result(APP_PATH,
APP_VERSION_KEY,
APP_TARGET_VERSION)
print '<result>%s</result>' % result
if __name__ == "__main__":
main()
Posted on 02-19-2016 06:51 PM
If it serves as consolation, Adobe is not the only company moving in that same direction. Microsoft is slowly doing the same to Windows and even to their MS Office suite. Adobe just has the lead in this confusing versioning scheme.
Posted on 02-19-2016 10:12 PM
Microsoft Office 2016 for Mac uses proper versioning. Did you mean Office on Wondows?
Posted on 02-20-2016 06:29 AM
agreed.
Posted on 02-20-2016 10:04 AM
In your example, what's the problem with doing
LIKE 15.
LIKE 16.
LIKE 17.
?
I'm aware that Acrobat now has two different release tracks for updates (Classic and Continuous). But I'm assuming you're deploying Continuous across the board. With that said, why can't you deploy a fully patched installer of DC and simply do VERSION IS NOT 17.X (or whatever it is they're up to)?
Posted on 02-20-2016 12:14 PM
Hi @bpavlov users might be at a higher version than what we are deploying (15.010.20056), this will prevent rolling back those users. This also future-proofs the scope, so when a newer version comes out we just need to tweak the scope.
We use EAs to differentiate between Continuous and Classic track installs. Whether what we are pushing is an update or a full install, the end goal is to get targeted computers to the desired version and track. Those with equal or higher versions will excluded using the above logic.
Been thinking there must be an easier way to do this, using the version string...as outlined in the above link.
Thanks,
Don
Posted on 02-20-2016 12:53 PM
Not sure if this helps at all, have used a similar technique to not overwrite newer versions before.. track the version you're targeting within the extension attribute. Will return 'F' if Adobe Acrobat DC is less than 15.010.20056, 'T' if the version equals 15.010.20056, and 'N' if the version is more than 15.010.20056.
https://gist.github.com/opragel/47e23d6084a5f5305180#file-ea_adobe_acrobat_dc_versioncheck-sh
#!/bin/bash
# T = Local app version is equal to provided current version
# N = Local app version is newer than provided current version
# F = Local app version is less than provided current version
# N/A = Local app was not found at provided path
APP_PATH="/Applications/Adobe Acrobat DC/Adobe Acrobat.app"
APP_VERSION_KEY="CFBundleShortVersionString"
APP_CURRENT_VERSION="15.010.20056"
compareVersions () {
if [[ "$1" == "$2" ]]; then
return 0
fi
local IFS=.
local i currentVersion=($1) localVersion=($2)
for ((i=${#currentVersion[@]}; i<${#localVersion[@]}; i++)); do
currentVersion[i]=0
done
for ((i=0; i<${#currentVersion[@]}; i++)); do
if [[ -z ${localVersion[i]} ]]; then
localVersion[i]=0
fi
if ((10#${currentVersion[i]} > 10#${localVersion[i]})); then
return 1
fi
if ((10#${currentVersion[i]} < 10#${localVersion[i]})); then
return 2
fi
done
return 0
}
if [ -d "$APP_PATH" ]; then
localAppVersion=$(defaults read "$APP_PATH/Contents/Info.plist" "$APP_VERSION_KEY")
compareVersions "$localAppVersion" "$APP_CURRENT_VERSION"
versionCode="$?"
case $versionCode in
0) versionCheckResult='T';;
1) versionCheckResult='N';;
2) versionCheckResult='F';;
esac
else
versionCheckResult="N/A"
fi
printf "<result>%s</result>" "$versionCheckResult"
Posted on 02-20-2016 05:59 PM
More python-ey way of doing the same thing as the script above.
https://gist.github.com/opragel/50c47c7c9c9100e3b1dd#file-ea_adobe_acrobat_dc_versioncheck-py
#!/usr/bin/python
"""
This script checks whether the installed version of Adobe Acrobat DC is
equal, less, or more than the target version defined by APP_TARGET_VERSION
and reports the result in Casper Suite extension attribute style.
T = Local app version is equal to provided current version
N = Local app version is newer than provided current version
F = Local app version is less than provided current version
N/A = Local app plist was not found at provided path
"""
import os.path
import plistlib
from pkg_resources import parse_version
APP_PATH = "/Applications/Adobe Acrobat DC/Adobe Acrobat.app"
APP_VERSION_KEY = "CFBundleShortVersionString"
APP_TARGET_VERSION = "15.010.20059"
def get_version_check_result(app_path, app_version_key, app_target_version):
"""
Reports T if the local app version is equal to target version, F if the
local app version is less than target version, N if the local app
version is greater than target version, and N/A if the plist is not found.
"""
app_plist_path = app_path + "/Contents/Info.plist"
if not os.path.isfile(app_plist_path):
version_check_result = "N/A"
else:
app_info_plist = plistlib.readPlist(app_plist_path)
app_version = app_info_plist[app_version_key]
if parse_version(app_target_version) == parse_version(app_version):
version_check_result = "T"
elif parse_version(app_target_version) < parse_version(app_version):
version_check_result = "N"
else:
version_check_result = "F"
return version_check_result
def main():
""" Executes script functions. """
result = get_version_check_result(APP_PATH,
APP_VERSION_KEY,
APP_TARGET_VERSION)
print '<result>%s</result>' % result
if __name__ == "__main__":
main()
Posted on 02-20-2016 08:50 PM
@owen nice, just curious how the script handles the different portions of the version string, such as release year, internal build #, track ID, internal build #, and hidden change list field?
Posted on 02-20-2016 09:50 PM
@donmontalvo The bash script is splitting the number on the decimals and comparing each part individually. The python script can parse the number natively, so nothing special, just comparing 2 versions.
Posted on 02-22-2016 05:02 AM
I can understand not wanting to roll anyone backward, but why not just roll everyone forward to be on the same page?
Posted on 02-22-2016 06:08 AM
As mentioned... :)
so we can deploy patches without inadvertently rolling anyone back.
Posted on 02-22-2016 06:20 AM
Apparently I don't understand your answer. If you've got people running the multitude of 15.x.x.x.x and 16.x, why not just install 17.x on ALL of them then you'll only have a single version to worry about and no risk of rolling anyone backward. Why make things hard on yourself by tracking 15.010.206, 15.010.207, 15.010.208, 15.010.209, 15.010.21, etc? What does it matter if someone is running 15.010.206 vs 15.010.207? Why not just have a single EA that looks for "is not like 17."? When Adobe releases an update, then change it to "is not like 17.1." What risk is there of rolling anyone backward if the only path is forward?
Posted on 02-22-2016 06:24 AM
Maybe I should ask: How would users get a version that you didn't push from Casper?
Posted on 02-22-2016 06:35 AM
@AVmcclint In my environment, all users are admins. Sometimes they will adopt updates before they are vetted by IT. The goal is to not roll them back with the current tested version.
Some environments are stricter than others.
Posted on 02-22-2016 06:38 AM
@AVmcclintI suspect he wants to setup a base for the software already found on machines. My guess is that 1) his users have admin access and 2) they are not going through their Self Service to install this software.
I do agree that @donmontalvo should really be pushing the latest version unless there's a reason he didn't want his users on the latest (in which case he should be looking at how to uninstall versions that don't match the one he wants to deploy).
Posted on 02-22-2016 06:42 AM
Yeah, admin users being able to install what they want throws wrenches into the works. If you happen to have a more strict environment that doesn't allow anyone to be local admin, then you probably don't need to deal with anything like this, but for those of us that aren't in that position, being able to do proper version checking and not rolling someone back to a previous release is important.
The main issue here of course, is the Casper Suite's inability to do real version comparison natively.
BTW, +1 to @owen's process above. I do something pretty similar in one of my scripts - splitting the version on the period into 2 arrays and comparing each section to the other to determine which is greater, less than or equal and setting an appropriate flag on exit. Its the only way (short of using python as mentioned) to do actual version comparison, since you can't just do something like remove the periods and lump the integers together and compare them. That fails more often that you might think because of developers using very inconsistent versioning schemes.
Posted on 02-22-2016 06:44 AM
Ah that would explain it. It always makes my skin crawl when I hear of sites where all users are local admins. I don't want to imagine the management nightmare if dealing with more than a handful of users.
Even with the fluid nature of uncontrolled user installs, you've still gotta draw a line somewhere, right? I dunno. i don't envy MacAdmins dealing with a flock of local admin users. Good luck to you!
Posted on 02-22-2016 06:49 AM
@mscottblake if users have admin access and IT insists on vetting updates then I see two options: 1) the vetting process needs to be quicker or 2) admin access needs to be stripped away so as to prevent being behind the version end users have. there's also the option of 3) simply not doing anything. i've chosen to go with a combination of options 1 and 2. it's worked pretty well.
while not every vendor is updating their software every day, it seems like a lot of maintenance/effort to put on IT to update smart groups with each version of software that could possibly be out there (as clearly illustrated by this thread) just to prevent rollbacks. seems a bit more useful to expend that effort on vetting new updates. like you said though every environment is different.
Posted on 02-22-2016 07:14 AM
I think we've gotten a little off-topic from the Adobe version numbers, but since we're here.... For me, I see my role as Mac support/admin/engineer to be proactive as much as possible. Build it right the first time to minimize problems. If all my users had admin rights, I'd be spending all my time cleaning up and fixing the things they broke. Since their admin rights would give them the freedom to mess up anything and everything on the computer, this would make troubleshooting a nightmare. Instead, I vet all the software before it gets installed on anyone's Macs. The prime example of why this is usually the best method is the MS Office 14.5.0 update. That was nasty. I have 80 users I manage by myself and if I had to run around to all 80 Macs to uninstall that horrible update, I'd pull my hair out. Instead, I installed it on my Mac to test and I discovered the show-stopping bug and I only had to uninstall and roll back ONE computer. I waited until the 14.5.1 update fixed it and then I pushed it out through Casper. Maybe if your support team has a lot more techs who are Mac-savvy, then maybe you can afford to let the users be on the bleeding edge of updates and don't mind undoing the damage. Now, the part where I give in and let users do things themselves is by letting them perform drag-n-drop installs into ~/Applications and since we have a lot of Java developers and they do need some freedom to do their work, I let them install all their commandline tools into ~/ mainly because there is no way I could possibly wrangle all those tools (like homebrew) myself and manage with Casper. The worse case scenario for them is they mangle their home folder while the computer stays operational. I warn all of them that they are free to shoot themselves in the foot and so far I've only had one user do that.
Posted on 02-22-2016 08:29 AM
We use extension attributes to convert the text into integers so we can use the 'less than' ability of a smart group.
#!/bin/sh
if [ -d /Library/Internet Plug-Ins/AdobePDFViewer.plugin ]; then
AcrobatProVersion=`/usr/bin/defaults read /Library/Internet Plug-Ins/AdobePDFViewer.plugin/Contents/Info CFBundleVersion | sed 's/[.]//g'`
if [ $AcrobatProVersion == "" ];then
echo "<result>No Version</result>"
else
echo "<result>$AcrobatProVersion</result>"
fi
else
echo "<result>Not installed</result>"
fi
exit 0
Posted on 02-22-2016 08:38 AM
@AVmcclint I wouldn't assume this...
Ah that would explain it. It always makes my skin crawl when I hear of sites where all users are local admins.
When you walk into an environment with 125 times as many Macs as you have, it is fair to expect finding issues that need to be addressed. Folks who have admin rights have security exemptions, but let's get the conversation back on track. ;)
Where a patch needs to be deployed, and the software has a wonky versioning scheme, I'm trying to find the most logical way to avoid rolling back someone who might be on a new version. The reason I ask, Adobe decided to toss the Track ID in the middle of the string. Which is, well, stupid. Except maybe to the folks who did it, who most likely don't understand enterprise management.
@owen I'll have a look at your scripts. I suppose our EAs that are already in place to identify Continuous vs Classic, plus your script, should do the trick.
PS, has anyone (@kagibson ?) else noticed Adobe's article provides paths for Adobe Acrobat Reader DC Continuous vs Classic tracks, but then their installer places it in /Applications/Adobe Acrobat Reader DC.app which is totally not right according to the doc. Oy vey! ;)
(queue in Deadpool doing many rapid double takes between the article and the installed app)
Posted on 02-22-2016 08:39 AM
@jonnycat01 curious are you removing the periods to come up with one numerical string? The issue again is the Track ID is right in the middle of the string. Which sucks. Really bad. LOL
Posted on 02-22-2016 09:37 AM
Ah, but removing periods and doing a straight integer comparison is a bad way to do it. Oh, you'll get lucky and it will work a few times, giving you a false sense of confidence, but you will quickly run into apps that will blow the whole thing up on you.
Here's a simple example. Which is newer, Firefox 45.0 or Firefox 44.0.2? We as humans can clearly see 45.0 is newer. but what happens if you remove the periods and compare the 2 results?
You are comparing 450 to 4402. Which one is larger, aka "newer" now? Now, you can use a method I've used like padding the shorter string with 0's to match the length of the longer string, like 4500 to 4402, but even this will run into problems. I was using that for a little while, and then Lync 14.0.10 came along, which replaced Lync 14.0.9. Once the periods are removed and the shorter string gets padded with a "0" you end up with 14010 vs 14090, where 14090 (14.0.9) is higher than 14010 (14.0.10). See what I mean? No matter how hard you try, some semi-insane product manager or developer somewhere is going to ruin your day by coming up with a version scheme that only makes sense to someone in an asylum who talks to little green men, lol.
The only (mostly) reliable way is to split the version on the sections and compare each one in a loop. I'm not even 100% convinced this method will always work, but it should work most of the time and only fail in some rare extreme cases. Using that method in the examples above, Firefox 45.0 would win over Firefox 44.0.2 and Lync 14.0.10 will win over Lync 14.0.9.
Posted on 02-22-2016 12:05 PM
@mm2270 wrote:
Ah, but removing periods and doing a straight integer comparison is a bad way to do it.
That's exactly the concern. I think the assumption being made is that the string is a major.minor.patch value. It isn't.
The string is some Adobe employee's way of saying:
I'm going to come up with a string that makes absolutely no sense, so nobody can work with it, for no other reason than, nobody is managing me - and it gives me job security. Besides I'm hiding behind so many layers of management that nobody will ever get to me.
Posted on 02-23-2016 03:16 AM
Doesn't Casper allow you to check version numbers against each other (on the assumption the version quoted is actually a version)? You could re-order the parts to return some kind of EA
#!/bin/bash
# Strip out track ID from Adobe DC version and put it somewhere else
# See http://www.adobe.com/devnet-docs/acrobatetk/tools/AdminGuide/whatsnewdc.html
# Assuming you can just change this for Acrobat Pro DC
# Set to your domain
my_domain="com.mycompany"
app_name="adobereaderdc"
app_path="/Applications/Adobe Acrobat Reader DC.app/Contents/"
app_framework="Frameworks/Acrobat.framework/Acrobat"
# Let the faff begin to get version number including hidden minor version
adobe_short_version=`defaults read "${app_path}Info.plist" CFBundleShortVersionString`
start_version="${adobe_short_version%%.*}"
end_version="${adobe_short_version##*.}"
adobe_version=`strings "${app_path}${app_framework}" | grep "^${start_version}.*${end_version}." | tr "." " "`
counter=0
our_adobedc_plist="/Library/Preferences/${my_domain}.${app_name}.plist"
function getVersion
{
while [ $# -gt 0 ]
do
counter=$((counter + 1))
case $counter in
1)
major_version=$1
;;
2)
minor_one=$1
;;
3)
# 20 = Continuous, 30 = Classic
minor_two=`echo ${1:2}`
dc_track_id=`echo ${1:0:2}`
case $dc_track_id in
20)
dc_track="Continuous"
;;
30)
dc_track="Classic"
;;
*)
dc_track="What have adobe done now"
;;
esac
;;
4)
minor_three=$1
;;
esac
shift
done
# Write to a plist and have two EAs for version and track that reads the plist
defaults write $our_adobedc_plist VersionNumber ${major_version}.${minor_one}.${minor_two}.${minor_three}
defaults write $our_adobedc_plist DCTrack "$dc_track"
# or perhaps re-order to put track first
echo "<result>${dc_track_id}.${major_version}.${minor_one}.${minor_two}.${minor_three}</result>"
}
getVersion $adobe_version
exit 0
If not, you could output each major/minor version to it's own key/value pair and have a bunch of EAs. That's not at all ugly!
Alternatively would you like some kind of pre-flight? Re-hashing the above
#!/bin/bash
# See http://www.adobe.com/devnet-docs/acrobatetk/tools/AdminGuide/whatsnewdc.html
# Remember that depending on when a script runs Casper has some preset values, so you may
# need to bump the following to start at $4 for example.
# $1 Major Version
# $2 Minor Version (Internal Build Number)
# $3 Minor Version (Internal Build Number)
# $4 Minor Version (Change List Field)
# $5 Track ID
# Eg. For version 15 007 20456 110321 pass the following to the script 15 007 456 110321 20
# Neater would be to read the name of the installer to save you having to change the passed values
# Eg. Name of installer: INS-AdobeDC-15-007-20456-110321 and then some crazy awk/sed/regex stuff
# Will re-install if the version to install matches the local installed version
# Exit code 3: track does not match or local version is newer than installer
declare -a install_version=("$1" "$2" "$3" "$4" "$5")
# Assuming you can just change this for Acrobat Pro DC
app_path="/Applications/Adobe Acrobat Reader DC.app/Contents/"
app_framework="Frameworks/Acrobat.framework/Acrobat"
# Let the faff begin to get version number including hidden minor version
adobe_short_version=`defaults read "${app_path}Info.plist" CFBundleShortVersionString`
start_version="${adobe_short_version%%.*}"
end_version="${adobe_short_version##*.}"
adobe_version=`strings "${app_path}${app_framework}" | grep "^${start_version}.*${end_version}." | tr "." " "`
counter=0
do_install=TRUE
dc_track_id=`echo $adobe_version | awk '{print substr($3,1,2)}'`
function checkVersion
{
install_this=${install_version[$((counter - 1))]}
if [ $1 -gt $install_this ]
then
do_install="FALSE"
fi
}
function getVersion
{
while [ $# -gt 0 ] && [[ "$do_install" != "FALSE" ]]
do
counter=$((counter + 1))
case $counter in
1|2|4)
checkVersion $1
;;
3)
# 20 = Continuous, 30 = Classic
checkVersion `echo ${1:2}`
;;
esac
shift
done
}
getVersion $adobe_version
echo "Compared local version $adobe_version with install version ${install_version[@]}"
# Install if track id matches and version to install is greater than current installed version
if [ $dc_track_id -eq ${install_version[4]} ] && [[ "$do_install" == "TRUE" ]]
then
echo "Installing..."
else
exit 3
fi
exit 0
Running the above:
# /tmp/adobedcversion.sh 16 010 059 172052 20
Compared local version 15 10 20059 172052 with install version 16 010 059 172052 20
Installing...
# /tmp/adobedcversion.sh 14 010 059 172053 20
Compared local version 15 10 20059 172052 with install version 14 010 059 172053 20
# echo $?
1
# /tmp/adobedcversion.sh 15 010 059 172053 20
Compared local version 15 10 20059 172052 with install version 15 010 059 172053 20
Installing...
Edit 1. It relies on having strings installed and the Xcode license agreed. We do this as standard. It therefore also relies on the binary not changing significantly enough to get confused results. Could grep -m 1 I guess, still not full proof though.
Posted on 02-24-2016 07:08 AM
We have been put in touch with the Adobe Acrobat team dev group. Hoping they can at least provide a proper incremental version key in Info.plist so administrators can scope policies without having to jump through hoops.
I'll also ask why this article gives two paths for Continuous vs Classic, but the actual install path is right smack at the top of /Applications
.
Posted on 03-01-2016 08:07 AM
Adobe reached out, they want to have a call to review how software is scoped for deployment.
I hope Adobe's DC team gets it and makes the necessary changes to give us proper version strings.
All the work Jody/Karl did for Creative Suite and Creative Cloud has made deployment a snap.
Now we need the Adobe DC team to get up to speed. Hopefully they'll listen. Or we'll escalate.
Posted on 03-17-2016 08:35 AM
Just got off the phone with the Acrobat dev team at Adobe.
They acknowledged their KB has bad paths, which don't match what is installed for Classic vs Continuous. They plan to fix in the coming days.
They also suggested coming up with two phased logic.
I requested adding a "Track" key in Info.plist, to identify Classic vs Continuous. They are going to see if that is possible.
I'll post their email once it comes in.
Thanks,
Don
Posted on 03-17-2016 09:28 AM
Just got off a conference call with the Adobe team responsible for the Acrobat and Acrobat Reader products. They really like @sean's script. :) Here is their summary email. I would post the text, but it has formatting that needs to be preserved.
Kudos to Adobe's dev/engineer team, JoydeepM, AnuragG, and PravalJ, for reaching out!
Posted on 03-17-2016 09:58 AM
@donmontalvo amazing work. another win for engaging vendors and vendors actually being receptive and responsive!
Posted on 03-17-2016 10:28 AM
Posted on 03-17-2016 12:41 PM
@sean gets the green for the solution that caught Adobe engineer's eye. :) I just made noise. :)
@mm2270 wrote:
Ah, but removing periods and doing a straight integer comparison is a bad way to do it.
During our call, the Adobe engineers explained, we just need to first identify Track ID (Classic vs Continuous), then yes we can treat the XX.XXX.XXXXX string as a number. Seems reliable, if not a bit convoluted.
I pressed for a "TrackID" key in Info.plist, seems that's the simplest way to put this all to rest.
Thanks,
Don
Posted on 03-17-2016 02:43 PM
Thanks, but I didn't offer up the python method, @owen did.
Posted on 03-18-2016 04:32 AM
I still don't have a clue what the "Tracks" are.
I mean i've read that whatsnewdc.html page a dozen times but for some reason it just isn't clicking for me. I could swear Adobe spends more time and money on confusing the hell out of users than they spend on making products that just work.
I still don't even know what Adobe Reader DC is compared to Adobe Reader 11. I have not found ANYTHING to explain that one.
Posted on 03-18-2016 05:56 AM
It's kinda explained in the link already posted above:
Posted on 03-18-2016 11:35 AM
@AVmcclint wrote:
I still don't have a clue what the "Tracks" are.
Continuous Track = Firefox (lots of changes, hard to keep up and manage...and cloud services)
Classic Track = Firefox ESR (fewer radical changes; easier to manage...and no cloud services)
Their article is very detailed, but a high(er) level, distilled down, article would be helpful.
Don
Posted on 03-18-2016 03:08 PM
Posted on 03-19-2016 02:07 AM
Thanks @donmontalvo but I think/agree that @sean's method is better in some ways - my script is contingent on the application path of the two different tracks being static and predictable (which, it may be.. usually). Sean's script accounts for the way Adobe does versioning internally.
The bash and python script I posted may unintentionally work out for the two different tracks due to the way Adobe versions the tracks and the dumb pure integer comparison, haven't thought it about it much yet.
Posted on 04-06-2016 10:07 AM