New version, new tarball, new man page. This version hopefully brings inxi closer to

at least making good guesses when the data is bad for ram, and hopefully will not break
too many cases where it was actually right but seemed wrong.

Unfortunately, dmidecode data simply cannot be relied on, and is FAR inferior to the type
of data inxi tries in general to present users, ie, taken directly from the system, and,
ideally, more accurate than most other tools. But in this case, there is just no way to get
the data truly accurate no matter how many hacks I add.

But if you have bad data, then submit: inxi -xx@ 14 so I can take a look at the system,
and see if I can modify the hacks to improve that data.
This commit is contained in:
inxi-svn 2014-08-15 00:44:47 +00:00
parent 5af0c33bac
commit bd12b27526
3 changed files with 208 additions and 97 deletions

279
inxi
View file

@ -1,9 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
######################################################################## ########################################################################
#### Script Name: inxi #### Script Name: inxi
#### Version: 2.1.95 #### Version: 2.1.96
#### Date: 2014-08-14 #### Date: 2014-08-14
#### Patch Number: 04 #### Patch Number: 00
######################################################################## ########################################################################
#### SPECIAL THANKS #### SPECIAL THANKS
######################################################################## ########################################################################
@ -4939,7 +4939,7 @@ get_dmidecode_data()
# To Be Filled By O.E.M. # To Be Filled By O.E.M.
# strip out starting white space so that the following stuff will clear properly # strip out starting white space so that the following stuff will clear properly
sub(/^[[:space:]]+/, "", twoData) sub(/^[[:space:]]+/, "", twoData)
sub(/^Base Board .*|^Chassis .*|.*O\.E\.M\..*|.*OEM.*|^Not .*|^System .*|.*unknow.*|.*N\/A.*|none|^To be filled.*|^0x[0]+$|\[Empty\]|<Bad Index>/, "", twoData) sub(/^Base Board .*|^Chassis .*|.*O\.E\.M\..*|.*OEM.*|^Not .*|^System .*|.*unknow.*|.*N\/A.*|none|^To be filled.*|^0x[0]+$|\[Empty\]|<Bad Index>|^\.\.$/, "", twoData)
sub(/.*(AssetTagNum|Manufacturer| Or Motherboard|PartNum.*|SerNum).*/, "", twoData) sub(/.*(AssetTagNum|Manufacturer| Or Motherboard|PartNum.*|SerNum).*/, "", twoData)
gsub(/bios|acpi/, "", twoData) gsub(/bios|acpi/, "", twoData)
sub(/http:\/\/www.abit.com.tw\//, "Abit", twoData) sub(/http:\/\/www.abit.com.tw\//, "Abit", twoData)
@ -8144,8 +8144,10 @@ get_ram_data()
locator="" locator=""
aDerivedModuleSize[0]=0 aDerivedModuleSize[0]=0
aFoundModules[0]=0 aFoundModules[0]=0
aMaxCapacity[0]=0 aMaxCapacity1[0]=0
aMaxCapacity2[0]=0
aMaxModuleSize[0]=0 aMaxModuleSize[0]=0
aUsedCapacity[0]=0
moduleVoltage="" moduleVoltage=""
numberOfDevices="" numberOfDevices=""
primaryType="" primaryType=""
@ -8153,6 +8155,8 @@ get_ram_data()
use="" use=""
i=0 i=0
k=0 k=0
bDebugger1="false"
dDebugger2="false"
} }
function calculateSize(data,size) { function calculateSize(data,size) {
if ( data ~ /^[0-9]+[[:space:]]*[GMTP]B/) { if ( data ~ /^[0-9]+[[:space:]]*[GMTP]B/) {
@ -8180,6 +8184,9 @@ get_ram_data()
aMaxModuleSize[k]=calculateSize($2,aMaxModuleSize[k]) aMaxModuleSize[k]=calculateSize($2,aMaxModuleSize[k])
# print "mms:" aMaxModuleSize[k] ":" $2 # print "mms:" aMaxModuleSize[k] ":" $2
} }
if ($1 == "Maximum Total Memory Size") {
aMaxCapacity1[k]=calculateSize($2,aMaxCapacity1[k])
}
if ( $1 == "Memory Module Voltage" ) { if ( $1 == "Memory Module Voltage" ) {
moduleVoltage=$2 moduleVoltage=$2
} }
@ -8191,8 +8198,8 @@ get_ram_data()
while ( getline && !/^$/ ) { while ( getline && !/^$/ ) {
# print $0 # print $0
if ( $1 == "Maximum Capacity") { if ( $1 == "Maximum Capacity") {
aMaxCapacity[k]=calculateSize($2,aMaxCapacity[k]) aMaxCapacity2[k]=calculateSize($2,aMaxCapacity2[k])
#print "mc:" aMaxCapacity[k] ":" $2 #print "mc:" aMaxCapacity2[k] ":" $2
} }
# note: these 3 have cleaned data in get_dmidecode_data, so replace stuff manually # note: these 3 have cleaned data in get_dmidecode_data, so replace stuff manually
if ( $1 == "Location") { if ( $1 == "Location") {
@ -8218,15 +8225,15 @@ get_ram_data()
numberOfDevices=$2 numberOfDevices=$2
} }
} }
a_memory[i,0]=primaryType aMemory[i,0]=primaryType
a_memory[i,1]=arrayHandle aMemory[i,1]=arrayHandle
a_memory[i,2]=location aMemory[i,2]=location
a_memory[i,3]=aMaxCapacity[k] aMemory[i,3]=aMaxCapacity2[k]
a_memory[i,4]=numberOfDevices aMemory[i,4]=numberOfDevices
a_memory[i,5]=use aMemory[i,5]=use
a_memory[i,6]=errorCorrection aMemory[i,6]=errorCorrection
a_memory[i,7]=aMaxModuleSize[k] aMemory[i,7]=aMaxModuleSize[k]
a_memory[i,8]=moduleVoltage aMemory[i,8]=moduleVoltage
# reset # reset
primaryType="" primaryType=""
@ -8238,10 +8245,11 @@ get_ram_data()
moduleVoltage="" moduleVoltage=""
i++ i++
k++ k++
aMaxCapacity[k]=0
aMaxModuleSize[k]=0
aDerivedModuleSize[k]=0 aDerivedModuleSize[k]=0
aFoundModules[k]=0 aFoundModules[k]=0
aMaxCapacity1[k]=0
aMaxCapacity2[k]=0
aMaxModuleSize[k]=0
} }
/^Handle .* DMI type 17/ { /^Handle .* DMI type 17/ {
primaryType="memory-device" primaryType="memory-device"
@ -8258,10 +8266,13 @@ get_ram_data()
if ( $1 == "Size") { if ( $1 == "Size") {
# do not try to guess from installed modules, only use this to correct type 5 data # do not try to guess from installed modules, only use this to correct type 5 data
aDerivedModuleSize[k-1]=calculateSize($2,aDerivedModuleSize[k-1]) aDerivedModuleSize[k-1]=calculateSize($2,aDerivedModuleSize[k-1])
if ( aDerivedModuleSize[k-1] ~ /^[0-9]+$/ ){ workingSize=calculateSize($2,0)
if ( workingSize ~ /^[0-9][0-9]+$/ ){
aFoundModules[k-1]++ aFoundModules[k-1]++
# build up actual capacity found for override tests
aUsedCapacity[k-1]=workingSize + aUsedCapacity[k-1]
} }
#print aDerivedModuleSize[k-1] " dm:"k":mm " aMaxModuleSize[k-1] # print aDerivedModuleSize[k-1] " dm:" k-1 ":mm " aMaxModuleSize[k-1] " uc:" aUsedCapacity[k-1]
deviceSize=$2 deviceSize=$2
} }
if ( $1 == "Locator") { if ( $1 == "Locator") {
@ -8327,22 +8338,22 @@ get_ram_data()
dataWidth=totalWidth dataWidth=totalWidth
totalWidth=tempWidth totalWidth=tempWidth
} }
a_memory[i,0]=primaryType aMemory[i,0]=primaryType
a_memory[i,1]=arrayHandle aMemory[i,1]=arrayHandle
a_memory[i,2]=deviceSize aMemory[i,2]=deviceSize
a_memory[i,3]=bankLocator aMemory[i,3]=bankLocator
a_memory[i,4]=locator aMemory[i,4]=locator
a_memory[i,5]=formFactor aMemory[i,5]=formFactor
a_memory[i,6]=deviceType aMemory[i,6]=deviceType
a_memory[i,7]=deviceTypeDetail aMemory[i,7]=deviceTypeDetail
a_memory[i,8]=deviceSpeed aMemory[i,8]=deviceSpeed
a_memory[i,9]=configuredClockSpeed aMemory[i,9]=configuredClockSpeed
a_memory[i,10]=dataWidth aMemory[i,10]=dataWidth
a_memory[i,11]=totalWidth aMemory[i,11]=totalWidth
a_memory[i,12]=deviceManufacturer aMemory[i,12]=deviceManufacturer
a_memory[i,13]=devicePartNumber aMemory[i,13]=devicePartNumber
a_memory[i,14]=deviceSerialNumber aMemory[i,14]=deviceSerialNumber
a_memory[i,15]=mainLocator aMemory[i,15]=mainLocator
primaryType="" primaryType=""
arrayHandle="" arrayHandle=""
@ -8364,88 +8375,164 @@ get_ram_data()
i++ i++
} }
END { END {
## CRITICAL: gawk keeps changing integers to strings, so be explicit with int() in math
# print primaryType "," arrayHandle "," location "," maxCapacity "," numberOfDevices "," use "," errorCorrection "," maxModuleSize "," moduleVoltage # print primaryType "," arrayHandle "," location "," maxCapacity "," numberOfDevices "," use "," errorCorrection "," maxModuleSize "," moduleVoltage
# print primaryType "," arrayHandle "," deviceSize "," bankLocator "," locator "," formFactor "," deviceType "," deviceTypeDetail "," deviceSpeed "," configuredClockSpeed "," dataWidth "," totalWidth "," deviceManufacturer "," devicePartNumber "," deviceSerialNumber "," mainLocator # print primaryType "," arrayHandle "," deviceSize "," bankLocator "," locator "," formFactor "," deviceType "," deviceTypeDetail "," deviceSpeed "," configuredClockSpeed "," dataWidth "," totalWidth "," deviceManufacturer "," devicePartNumber "," deviceSerialNumber "," mainLocator
m=0 m=0
bPrint="true"
for ( j=0;j<i;j++ ) { for ( j=0;j<i;j++ ) {
estCap="" estCap=""
estModuleSize="" estMod=""
unit="" unit=""
altCap=0
if (a_memory[j,0] == "memory-array" ) { if (aMemory[j,0] == "memory-array" ) {
if ( a_memory[j,3] == 0 ) { if ( bDebugger1 == "true" ){
a_memory[j,3] = "" print ""
print "count: " m+1
print "1: mmods: " aMaxModuleSize[m] " :dmmods: " aDerivedModuleSize[m] " :mcap: " aMemory[j,3] " :ucap: " aUsedCapacity[m]
} }
else { # 1: if max cap 1 is null, and max cap 2 not null, use 2
a_memory[j,3]=int(a_memory[j,3]) # some weird cases believe they are strings! if ( aMemory[j,3] == 0 ) {
if ( aMaxCapacity2[m] != 0 ) {
aMemory[j,3]=aMaxCapacity2[m]
}
} }
# if ( m < 8 ) { if ( aMemory[j,4] == "" ) {
# bPrint="true" aMemory[j,4] = 0
# } }
# else { if ( bDebugger1 == "true" ){
# bPrint="false" print "2: mmods: " aMaxModuleSize[m] " :dmmods: " aDerivedModuleSize[m] " :mcap: " aMemory[j,3] " :ucap: " aUsedCapacity[m]
# } }
#print "mms:" aMaxModuleSize[m] ":dms:" aDerivedModuleSize[m] ":mc:" a_memory[j,3] # 2: now check to see if actually found module sizes are > than listed max module, replace if >
if (aMaxModuleSize[m] != 0 && aDerivedModuleSize[m] != 0 && aDerivedModuleSize[m] > aMaxModuleSize[m]){ if (aMaxModuleSize[m] != 0 && aDerivedModuleSize[m] != 0 && int(aDerivedModuleSize[m]) > int(aMaxModuleSize[m]) ) {
aMaxModuleSize[m]=aDerivedModuleSize[m] aMaxModuleSize[m]=aDerivedModuleSize[m]
estModuleSize=" (est)" estMod=" (est)"
} }
aMaxModuleSize[m]=int(aMaxModuleSize[m])
aDerivedModuleSize[m]=int(aDerivedModuleSize[m])
aUsedCapacity[m]=int(aUsedCapacity[m])
aMemory[j,3]=int(aMemory[j,3])
# note: some cases memory capacity == max module size, so one stick will fill it
# but I think only with cases of 2 slots does this happen, so if > 2, use the count of slots.
if ( bDebugger1 == "true" ){
print "3: fmod: " aFoundModules[m] " :modc: " aMemory[j,4] " :maxc1: " aMaxCapacity1[m] " :maxc2: " aMaxCapacity2[m]
}
if (aMemory[j,3] != 0 && ( aFoundModules[m] != 0 || aMemory[j,4] != 0 ) ) {
aMemory[j,4]=int(aMemory[j,4])
## first check that actual memory found is not greater than listed max cap, or
## checking to see module count * max mod size is not > used capacity
if ( aUsedCapacity[m] != 0 && aMaxCapacity2[m] != 0 ) {
if ( aUsedCapacity[m] > aMemory[j,3] ) {
if ( aMaxModuleSize[m] != 0 &&
aUsedCapacity[m] < aMemory[j,4] * aMaxModuleSize[m] ) {
aMemory[j,3]=aMemory[j,4] * aMaxModuleSize[m]
estCap=" (est)"
if ( bDebugger1 == "true" ){
print "A"
}
}
else if ( aDerivedModuleSize[m] != 0 &&
aUsedCapacity[m] < aMemory[j,4] * aDerivedModuleSize[m] ) {
aMemory[j,3]=aMemory[j,4] * aDerivedModuleSize[m]
estCap=" (est)"
if ( bDebugger1 == "true" ){
print "B"
}
}
else {
aMemory[j,3]=aUsedCapacity[m]
estCap=" (est)"
if ( bDebugger1 == "true" ){
print "C"
}
}
}
}
# note that second case will never really activate except on virtual machines and maybe
# mobile devices
if ( estCap == "" ) {
# do not do this for only single modules found, max mod size can be equal to the array size
if ( ( aMemory[j,4] > 1 && aFoundModules[m] > 1 ) &&
( aMemory[j,3] < aDerivedModuleSize[m] * aMemory[j,4] ) ) {
aMemory[j,3] = aDerivedModuleSize[m] * aMemory[j,4]
estCap=" (est)"
if ( bDebugger1 == "true" ){
print "D"
}
}
else if ( ( aFoundModules[m] > 0 ) &&
( aMemory[j,3] < aDerivedModuleSize[m] * aFoundModules[m] ) ) {
aMemory[j,3] = aDerivedModuleSize[m] * aFoundModules[m]
estCap=" (est)"
if ( bDebugger1 == "true" ){
print "E"
}
}
## handle cases where we have type 5 data: mms x device count equals type 5 max cap
# however do not use it if cap / devices equals the derived module size
else if ( aMaxModuleSize[m] > 0 &&
( aMaxModuleSize[m] * aMemory[j,4] == aMaxCapacity1[m] ) &&
aMaxCapacity1[m] != aMaxCapacity2[m] &&
aMaxCapacity2[m] / aMemory[j,4] != aDerivedModuleSize[m] ) {
aMemory[j,3] = aMaxCapacity1[m]
altCap=aMaxCapacity1[m] # not used
estCap=" (check)"
if ( bDebugger1 == "true" ){
print "F"
}
}
}
}
altCap=int(altCap)
aMemory[j,3]=int(aMemory[j,3])
if ( bDebugger1 == "true" ){
print "4: mmods: " aMaxModuleSize[m] " :dmmods: " aDerivedModuleSize[m] " :mcap: " aMemory[j,3] " :ucap: " aUsedCapacity[m]
}
# some cases of type 5 have too big module max size, just dump the data then since
# we cannot know if it is valid or not, and a guess can be wrong easily
if ( aMaxModuleSize[m] != 0 && aMemory[j,3] != "" &&
( aMaxModuleSize[m] > aMemory[j,3] ) ){
aMaxModuleSize[m] = 0
# print "yes"
}
## prep for output ##
if (aMaxModuleSize[m] == 0 ){ if (aMaxModuleSize[m] == 0 ){
aMaxModuleSize[m]="" aMaxModuleSize[m]=""
} }
if (aMaxModuleSize[m] != "") { else {
aMaxModuleSize[m]=int(aMaxModuleSize[m])
}
# note: some cases memory capacity == max module size, so one stick will fill it
# but I think only with cases of 2 slots does this happen, so if > 2, use the count of slots.
if (a_memory[j,3] != "" && ( aFoundModules[m] != 0 || a_memory[j,4] != "" ) ) {
# not using this logic for now, too complicated and will not always work, grr.
# so use just count x biggest module found
if ( ( a_memory[j,4] > 1 ) && ( a_memory[j,3] < aDerivedModuleSize[m] * a_memory[j,4] ) ) {
a_memory[j,3] = aDerivedModuleSize[m] * a_memory[j,4]
estCap=" (est)"
}
else if ( ( aFoundModules[m] > 0 ) && ( a_memory[j,3] < aDerivedModuleSize[m] * aFoundModules[m] ) ) {
a_memory[j,3] = aDerivedModuleSize[m] * aFoundModules[m]
estCap=" (est)"
}
}
# print "mms:" aMaxModuleSize[m] ":dms:" aDerivedModuleSize[m] ":mc:" a_memory[j,3]
# some cases of type 5 have too big module max size, just dump the data then
if ( aMaxModuleSize[m] != "" && a_memory[j,3] != "" && ( aMaxModuleSize[m] > a_memory[j,3] ) ){
aMaxModuleSize[m] = ""
# print "yes"
}
if (a_memory[j,3] != "" ) {
if ( a_memory[j,3] < 1024 ) {
a_memory[j,3] = a_memory[j,3]
unit=" MB"
}
else if ( a_memory[j,3] < 1024000 ) {
a_memory[j,3] = a_memory[j,3] / 1024
unit=" GB"
}
else if ( a_memory[j,3] < 1024000000 ) {
a_memory[j,3] = a_memory[j,3] / 1024000
unit=" TB"
}
a_memory[j,3]=gensub(/([0-9]+\.[0-9][0-9]).*/,"\\1",1,a_memory[j,3])
a_memory[j,3] = a_memory[j,3] unit estCap
}
if ( aMaxModuleSize[m] != "" ){
aMaxModuleSize[m]=aMaxModuleSize[m] " MB" aMaxModuleSize[m]=aMaxModuleSize[m] " MB"
} }
if ( bPrint == "true" ){ if ( aMemory[j,4] == 0 ) {
print a_memory[j,0] "," a_memory[j,1] "," a_memory[j,2] "," a_memory[j,3] "," a_memory[j,4] "," a_memory[j,5] "," a_memory[j,6] "," aMaxModuleSize[m] estModuleSize "," a_memory[j,8] aMemory[j,4] = ""
} }
if (aMemory[j,3] != 0 ) {
if ( aMemory[j,3] < 1024 ) {
aMemory[j,3] = aMemory[j,3]
unit=" MB"
}
else if ( aMemory[j,3] < 1024000 ) {
aMemory[j,3] = aMemory[j,3] / 1024
unit=" GB"
}
else if ( aMemory[j,3] < 1024000000 ) {
aMemory[j,3] = aMemory[j,3] / 1024000
unit=" TB"
}
# we only want a max 2 decimal places, this trick gives 0 to 2
aMemory[j,3]=gensub(/([0-9]+\.[0-9][0-9]).*/,"\\1",1,aMemory[j,3])
aMemory[j,3] = aMemory[j,3] unit estCap
}
else {
aMemory[j,3] == ""
}
print aMemory[j,0] "," aMemory[j,1] "," aMemory[j,2] "," aMemory[j,3] "," aMemory[j,4] "," aMemory[j,5] "," aMemory[j,6] "," aMaxModuleSize[m] estMod "," aMemory[j,8]
m++ m++
} }
else { else {
if ( bPrint == "true" ){ print aMemory[j,0] "," aMemory[j,1] "," aMemory[j,2] "," aMemory[j,3] "," aMemory[j,4] "," aMemory[j,5] "," aMemory[j,6] "," aMemory[j,7] "," aMemory[j,8] "," aMemory[j,9] "," aMemory[j,10] "," aMemory[j,11] "," aMemory[j,12] "," aMemory[j,13] "," aMemory[j,14] "," aMemory[j,15]
print a_memory[j,0] "," a_memory[j,1] "," a_memory[j,2] "," a_memory[j,3] "," a_memory[j,4] "," a_memory[j,5] "," a_memory[j,6] "," a_memory[j,7] "," a_memory[j,8] "," a_memory[j,9] "," a_memory[j,10] "," a_memory[j,11] "," a_memory[j,12] "," a_memory[j,13] "," a_memory[j,14] "," a_memory[j,15]
}
} }
} }
}' <<< "$DMIDECODE_DATA" ) ) }' <<< "$DMIDECODE_DATA" ) )

4
inxi.1
View file

@ -1,4 +1,4 @@
.TH INXI 1 "2014\-08\-13" inxi "inxi manual" .TH INXI 1 "2014\-08\-14" inxi "inxi manual"
.SH NAME .SH NAME
inxi \- Command line system information script for console and IRC inxi \- Command line system information script for console and IRC
.SH SYNOPSIS .SH SYNOPSIS
@ -129,6 +129,8 @@ Show partition labels. Default: short partition \fB\-P\fR. For full \fB\-p\fR ou
Memory (RAM) data. Does not show with \fB\-b\fR or \fB\-F\fR unless you use \fB\-m\fR explicitly. Ordered by system board physical system memory array(s) (\fBArray\-[number] capacity:\fR), and individual memory devices (\fBDevice\-[number]\fR). Physical memory array(s) data shows array capacity, and number of devices supported, and Error Correction information. Devices shows locator data (highly variable in syntax), size, speed, type (eg: \fBtype: DDR3\fR). Memory (RAM) data. Does not show with \fB\-b\fR or \fB\-F\fR unless you use \fB\-m\fR explicitly. Ordered by system board physical system memory array(s) (\fBArray\-[number] capacity:\fR), and individual memory devices (\fBDevice\-[number]\fR). Physical memory array(s) data shows array capacity, and number of devices supported, and Error Correction information. Devices shows locator data (highly variable in syntax), size, speed, type (eg: \fBtype: DDR3\fR).
Note that \fB\-m\fR uses \fBdmidecode\fR, which must be run as root (or start \fBinxi\fR with \fBsudo\fR), unless you figure out how to set up sudo to permit dmidecode to read \fB/dev/mem\fR as user. Note that speed will not show if \fBNo Module Installed\fR is found in size. This will also turn off Bus Width data output if it is null. Note that \fB\-m\fR uses \fBdmidecode\fR, which must be run as root (or start \fBinxi\fR with \fBsudo\fR), unless you figure out how to set up sudo to permit dmidecode to read \fB/dev/mem\fR as user. Note that speed will not show if \fBNo Module Installed\fR is found in size. This will also turn off Bus Width data output if it is null.
Because dmidecode data is extremely unreliable, inxi will try to make best guesses. If you see \fB(check)\fR after capacity number, you should check it for sure with specifications. \fB(est)\fR is slightly more reliable, but you should still check the real specifications before buying ram. Unfortunately there is nothing \fBinxi can do to get truly reliable data about the system ram, maybe one day the kernel devs will put this data into \fB/sys\fR, and make it real data, taken from the actual system, not dmi data. For most people, the data will be right, but a significant percentage of users will have either wron max module size, if present, or max capacity.
.TP .TP
.B \-M .B \-M
Show machine data. Motherboard, Bios, and if present, System Builder (Like Lenovo). Show machine data. Motherboard, Bios, and if present, System Builder (Like Lenovo).

View file

@ -1,3 +1,25 @@
=====================================================================================
Version: 2.1.96
Patch Version: 00
Script Date: 2014-08-14
-----------------------------------
Changes:
-----------------------------------
New version, new tarball, new man page. This version hopefully brings inxi closer to
at least making good guesses when the data is bad for ram, and hopefully will not break
too many cases where it was actually right but seemed wrong.
Unfortunately, dmidecode data simply cannot be relied on, and is FAR inferior to the type
of data inxi tries in general to present users, ie, taken directly from the system, and,
ideally, more accurate than most other tools. But in this case, there is just no way to get
the data truly accurate no matter how many hacks I add.
But if you have bad data, then submit: inxi -xx@ 14 so I can take a look at the system,
and see if I can modify the hacks to improve that data.
-----------------------------------
-- Harald Hope - Thu, 14 Aug 2014 17:41:42 -0700
===================================================================================== =====================================================================================
Version: 2.1.95 Version: 2.1.95
Patch Version: 04 Patch Version: 04