Added an empty 10Mb disk image formatted by PC-DOS 2.0 (currently used by one machine: 5160/cga/640kb); also fixed some issues uncovered in the process of creating the disk image (eg, a bug in the HDC's save logic when no image has been loaded), and made some fixes and optimizations in DiskDump

This commit is contained in:
Jeff Parsons 2017-06-01 15:32:17 -07:00 committed by Jeff Parsons
commit 3e1aa196bd
13 changed files with 1871 additions and 1832 deletions

View file

@ -13,7 +13,7 @@
<keyboard ref="/devices/pcx86/keyboard/us83-buttons-minimal.xml"/>
<debugger id="debugger"/>
<panel ref="/devices/pcx86/panel/wide.xml"/>
<hdc id="hdcXT" drives='[{name:"10Mb Hard Disk",type:3}]'>
<hdc id="hdcXT" drives='[{name:"10Mb Hard Disk",type:3,path:"/disks/pcx86/fixed/10mb/PCDOS200-EMPTY.json"}]'>
<control type="button" binding="saveHD0">Save HD</control>
</hdc>
<chipset id="chipset" model="5160" sw1="01001001" pos="left" padLeft="8px" padBottom="8px">

View file

@ -14,7 +14,7 @@
<control type="button" binding="reset">Reset</control>
</cpu>
<keyboard ref="/devices/pcx86/keyboard/us83-buttons-minimal.xml"/>
<hdc id="hdcXT" drives='[{name:"10Mb Hard Disk",type:3}]'>
<hdc id="hdcXT" drives='[{name:"10Mb Hard Disk",type:3,path:"/disks/pcx86/fixed/10mb/PCDOS200-EMPTY.json"}]'>
<control type="button" binding="saveHD0">Save HD</control>
</hdc>
<chipset id="chipset" model="5160" sw1="01001001"/>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -539,12 +539,17 @@ DiskDump.aDefaultBPBs = [
0x03, 0x51, // 0x13: number of sectors (0x5103 or 20739; * 512 bytes/sector = 10,618,368 bytes = 10,369Kb = 10Mb)
0xF8, // 0x15: media type (eg, 0xF8: hard drive w/FAT12)
0x08, 0x00, // 0x16: sectors per FAT (8)
// Wikipedia (http://en.wikipedia.org/wiki/File_Allocation_Table#BIOS_Parameter_Block) implies everything past this point was introduced
// post-DOS 2.0. I think that's wrong, because I just formatted a diskette with PC-DOS 2.0 and it properly initialized the next 3 fields as well.
//
// Wikipedia (http://en.wikipedia.org/wiki/File_Allocation_Table#BIOS_Parameter_Block) implies everything past
// this point was introduced post-DOS 2.0. I think that's wrong, because I just formatted a diskette with PC-DOS 2.0
// and it properly initialized the next 3 fields as well. TODO: Investigate PC-DOS 2.0 BPB behavior.
//
0x11, 0x00, // 0x18: sectors per track (17)
0x04, 0x00, // 0x1A: number of heads (4)
// PC-DOS 2.0 actually stored 0x01, 0x00, 0x80, 0x00 here, so you can't always assume that anything past offset 0x1E is part of the BPB;
// requires further investigation.
//
// PC-DOS 2.0 actually stored 0x01, 0x00, 0x80, 0x00 here, so you can't always assume that anything past offset
// 0x1E is part of the BPB. TODO: Investigate PC-DOS 2.0 BPB behavior.
//
0x01, 0x00, 0x00, 0x00 // 0x1C: number of hidden sectors (always 0 for non-partitioned media)
]
];
@ -2488,7 +2493,9 @@ DiskDump.prototype.convertToJSON = function()
}
var json = null;
var fOptimize = true; // if true, leave out any properties that are defaults
try {
var fMBR = false;
var nHeads = 0;
var nCylinders = 0;
var nSectorsPerTrack = 0;
@ -2510,6 +2517,7 @@ DiskDump.prototype.convertToJSON = function()
if (this.bufDisk.readUInt8(offEntry) >= 0x80) {
offBootSector = this.bufDisk.readUInt32LE(offEntry + 0x08) * cbSector;
cbDiskData = this.bufDisk.readUInt32LE(offEntry + 0x0C) * cbSector;
fMBR = true;
break;
}
}
@ -2568,22 +2576,25 @@ DiskDump.prototype.convertToJSON = function()
fBPBExists = true;
var bMediaTypeBPB = this.bufDisk.readUInt8(offBootSector + DiskAPI.BPB.MEDIA_TYPE);
var nSectorsTotalBPB = this.bufDisk.readUInt16LE(offBootSector + DiskAPI.BPB.TOTAL_SECS);
var nSectorsPerCylinderBPB = nSectorsPerTrackBPB * nHeadsBPB;
var nCylindersBPB = Math.floor(nSectorsTotalBPB / nSectorsPerCylinderBPB);
/*
* TODO: Detect newer BPBs (ie, where the HIDDEN_SECS and LARGE_SECS fields are valid),
* so that we can determine the true geometry of the disk, instead of having to rely on our
* DISK_FORMATS table.
*/
if (diskFormat) {
if (nCylinders != nCylindersBPB) {
DiskDump.logWarning("BPB cylinders (" + nCylindersBPB + ") do not match actual cylinders: " + nCylinders);
DiskDump.logWarning("BPB cylinders (" + nCylindersBPB + ") do not match actual cylinders (" + nCylinders + ")");
}
if (nHeads != nHeadsBPB) {
DiskDump.logWarning("BPB heads (" + nHeadsBPB + ") do not match actual heads: " + nHeads);
DiskDump.logWarning("BPB heads (" + nHeadsBPB + ") do not match actual heads (" + nHeads + ")");
}
if (nSectorsPerTrack != nSectorsPerTrackBPB) {
DiskDump.logWarning("BPB sectors/track (" + nSectorsPerTrackBPB + ") do not match actual sectors/track: " + nSectorsPerTrack);
DiskDump.logWarning("BPB sectors/track (" + nSectorsPerTrackBPB + ") do not match actual sectors/track (" + nSectorsPerTrack + ")");
}
if (bMediaType && bMediaType != bMediaTypeBPB) {
DiskDump.logWarning("BPB media type (" + bMediaTypeBPB + ") do not match actual media type: " + bMediaType);
DiskDump.logWarning("BPB media type (" + bMediaTypeBPB + ") do not match actual media type (" + bMediaType + ")");
}
}
else {
@ -2640,7 +2651,11 @@ DiskDump.prototype.convertToJSON = function()
}
if (iBPB >= 0) {
if (fBPBExists) {
for (i = DiskAPI.BPB.SECTOR_BYTES; i < DiskAPI.BPB.LARGE_SECS; i++) {
/*
* In deference to the PC-DOS 2.0 anomaly noted above (see "Investigate PC-DOS 2.0 BPB behavior" above),
* we limit the following byte verification to the offset of LARGE_SECS, less two bytes.
*/
for (i = DiskAPI.BPB.SECTOR_BYTES; i < DiskAPI.BPB.LARGE_SECS - 2; i++) {
var bDefault = DiskDump.aDefaultBPBs[iBPB][i];
var bActual = this.bufDisk.readUInt8(offBootSector + i);
if (bDefault != bActual) {
@ -2841,21 +2856,25 @@ DiskDump.prototype.convertToJSON = function()
bufSector = bufTrack.slice(offSector, offSector + cbSectorThisTrack);
if (bMediaType && !iCylinder && !iHead && iSector == 2) {
if (bMediaType && !iCylinder && !iHead && iSector == ((offBootSector/cbSector)|0) + 2) {
var bFATType = bufSector.readUInt8(0);
if (bMediaType != bFATType) {
DiskDump.logWarning("wrong media type (" + str.toHexByte(bFATType) + ") in FAT, expected " + str.toHexByte(bMediaType));
DiskDump.logWarning("media byte mismatch (" + str.toHexByte(bFATType) + ") in FAT, expected " + str.toHexByte(bMediaType));
}
bMediaType = 0;
}
if (this.fJSONNative) {
sector['sector'] = nSector;
sector['length'] = cbSectorThisTrack;
if (!fOptimize || cbSectorThisTrack != 512) {
sector['length'] = cbSectorThisTrack;
}
} else {
json += (iSector == 1? this.dumpLine(2, "{") : "");
json += this.dumpLine(0, '"sector":' + this.sJSONWhitespace + nSector + ",");
json += this.dumpLine(0, '"length":' + this.sJSONWhitespace + cbSectorThisTrack + ",");
if (!fOptimize || cbSectorThisTrack != 512) {
json += this.dumpLine(0, '"length":' + this.sJSONWhitespace + cbSectorThisTrack + ",");
}
}
var aTrim = this.trimSector(bufSector, cbSectorThisTrack);
@ -2863,28 +2882,33 @@ DiskDump.prototype.convertToJSON = function()
var cbBuffer = cbSectorThisTrack;
if (dwPattern !== null) {
cbBuffer = aTrim[1];
if (this.fJSONNative) {
sector['pattern'] = dwPattern;
} else {
json += this.dumpLine(0, '"pattern":' + this.sJSONWhitespace + dwPattern + ",");
if (!fOptimize || dwPattern) {
if (this.fJSONNative) {
sector['pattern'] = dwPattern;
} else {
json += this.dumpLine(0, '"pattern":' + this.sJSONWhitespace + dwPattern + ",");
}
}
}
if (this.fJSONNative) {
var dataSector = [];
sector['data'] = dataSector;
for (var off = 0; off < cbBuffer; off += 4) {
dataSector.push(bufSector.readInt32LE(off));
if (!fOptimize || cbBuffer) {
var dataSector = [];
sector['data'] = dataSector;
for (var off = 0; off < cbBuffer; off += 4) {
dataSector.push(bufSector.readInt32LE(off));
}
}
aSectors[iSector-1] = sector;
aSectors[iSector - 1] = sector;
} else {
if (this.sFormat == DumpAPI.FORMAT.BYTES) {
json += this.dumpBuffer("bytes", bufSector, cbBuffer, 1, offSector);
} else {
/*
* TODO: Assert that sFormat is FORMAT_JSON or FORMAT_DATA (both use the same dword format)
*/
json += this.dumpBuffer("data", bufSector, cbBuffer, 4, offSector);
if (!fOptimize || cbBuffer) {
if (this.sFormat == DumpAPI.FORMAT.BYTES) {
json += this.dumpBuffer("bytes", bufSector, cbBuffer, 1, offSector);
} else {
/*
* TODO: Assert that sFormat is FORMAT_JSON or FORMAT_DATA (both use the same dword format)
*/
json += this.dumpBuffer("data", bufSector, cbBuffer, 4, offSector);
}
}
json += (iSector < nSectorsThisTrack? this.dumpLine(0, "},{") : this.dumpLine(-2, "}"));
}

View file

@ -340,7 +340,8 @@ class FDC extends Component {
var drive = fdc.aDrives[iDriveSelected];
if (drive) {
/*
* Note the similarity (and hence factoring opportunity) between this code and the HDC's "saveHD*" binding.
* Note the similarity (and hence factoring opportunity) between this code and the HDC's
* "saveHD*" binding.
*/
var disk = drive.disk;
if (disk) {

View file

@ -134,11 +134,22 @@ class HDC extends Component {
var drive = hdc.aDrives && hdc.aDrives[iDrive];
if (drive && drive.disk) {
/*
* Note the similarity (and hence factoring opportunity) between this code and the FDC's "saveDisk" binding.
* Note the similarity (and hence factoring opportunity) between this code and the FDC's
* "saveDisk" binding.
*
* One important difference between the FDC and the HDC is that an FDC may or may not contain
* a disk, whereas an HDC always contains a disk. However, the contents of an HDC's disk may
* never have been initialized with the contents of an external disk image, and therefore the
* disk's sDiskFile/sDiskPath properties may be undefined. sDiskName should always be defined
* though, defaulting to the name of the drive (eg, "10Mb Hard Disk").
*/
var disk = drive.disk;
if (DEBUG) hdc.println("saving disk " + disk.sDiskPath + "...");
var sAlert = Web.downloadFile(disk.encodeAsBase64(), "octet-stream", true, disk.sDiskFile.replace(".json", ".img"));
var sDiskName = disk.sDiskFile || disk.sDiskName;
var i = sDiskName.lastIndexOf('.');
if (i >= 0) sDiskName = sDiskName.substr(0, i);
sDiskName += ".img";
if (DEBUG) hdc.println("saving disk " + sDiskName + "...");
var sAlert = Web.downloadFile(disk.encodeAsBase64(), "octet-stream", true, sDiskName);
Component.alertUser(sAlert);
} else {
hdc.notice("Hard drive " + iDrive + " is not available.");

View file

@ -89,8 +89,10 @@ DiskAPI.DISK_FORMATS = {
1474560: [80,2,18,,0xF0], // media type 0xF0: 80 cylinders, 2 heads (double-sided), 18 sectors/track, (2880 total sectors x 512 bytes/sector == 1474560)
2949120: [80,2,36,,0xF0], // media type 0xF0: 80 cylinders, 2 heads (double-sided), 36 sectors/track, (5760 total sectors x 512 bytes/sector == 2949120)
/*
* The following are common early hard drive sizes, which we explicitly map to CHS values, since the BPB can mislead us when attempting to calculate total cylinders
* The following are some common partition sizes, which we explicitly map to CHS values, since the MBR and/or BPB
* can mislead us when attempting to calculate total cylinders.
*/
10618368:[306,4,17], // PC XT 10Mb hard drive (type 3)
21368320:[615,4,17], // PC AT 20Mb hard drive (type 2)
/*
* Assorted DEC disk formats.
@ -164,7 +166,7 @@ DiskAPI.BPB = {
TRACK_SECS: 0x018, // 2 bytes: sectors per track (eg, 8)
TOTAL_HEADS: 0x01A, // 2 bytes: number of heads (eg, 1)
HIDDEN_SECS: 0x01C, // 4 bytes: number of hidden sectors (always 0 for non-partitioned media)
LARGE_SECS: 0x020 // 4 bytes: number of sectors if TOTAL_SECS is zero
LARGE_SECS: 0x020 // 4 bytes: number of sectors if TOTAL_SECS is zero (TODO: Verify the true extent of DOS 2.0 BPBs; they may have stopped with HIDDEN_SECS, which is what DiskDump assumes)
};
/*

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -38,9 +38,9 @@ var h,aa="function"==typeof Object.defineProperties?Object.defineProperty:functi
function fa(){ca();var a=ba.Symbol.iterator;a||(a=ba.Symbol.iterator=ba.Symbol("iterator"));"function"!=typeof Array.prototype[a]&&aa(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return ga(this)}});fa=function(){}}function ga(a){var b=0;return ha(function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}})}function ha(a){fa();a={next:a};a[ba.Symbol.iterator]=function(){return this};return a}function ia(a){fa();ca();fa();var b=a[Symbol.iterator];return b?b.call(a):ga(a)}
function p(a,b){function c(){}c.prototype=b.prototype;a.prototype=new c;a.prototype.constructor=a;for(var d in b)if(Object.defineProperties){var e=Object.getOwnPropertyDescriptor(b,d);e&&Object.defineProperty(a,d,e)}else a[d]=b[d]}function ja(a,b){if(b){var c=ba;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];e in c||(c[e]={});c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&aa(c,a,{configurable:!0,writable:!0,value:b})}}
ja("Math.trunc",function(a){return a?a:function(a){a=Number(a);if(isNaN(a)||Infinity===a||-Infinity===a||!a)return a;var b=Math.floor(Math.abs(a));return 0>a?-b:b}});ja("Math.log2",function(a){return a?a:function(a){return Math.log(a)/Math.LN2}});ja("Array.prototype.fill",function(a){return a?a:function(a,c,d){var b=this.length||0;0>c&&(c=Math.max(0,b+c));if(null==d||d>b)d=b;d=Number(d);0>d&&(d=Math.max(0,b+d));for(c=Number(c||0);c<d;c++)this[c]=a;return this}});
var ka={163840:[40,1,8,,254],184320:[40,1,9,,252],327680:[40,2,8,,255],368640:[40,2,9,,253],737280:[80,2,9,,249],1228800:[80,2,15,,249],1474560:[80,2,18,,240],2949120:[80,2,36,,240],21368320:[615,4,17],256256:[77,1,26,128],2494464:[203,2,12,512],5242880:[256,2,40,256],10485760:[512,2,40,256]},la={Bi:0,Fe:1,Ii:2,Ji:3,Ki:4,Li:5,Mi:6,Ni:7,Od:8,Oi:9,Ge:10,Pi:11,Qi:12,He:13,Ri:14,Si:15,Ti:16,Ui:17,Vi:18,Wi:19,Xi:20,Yi:21,Zi:22,$i:23,aj:24,bj:25,cj:26," ":32,"!":33,'"':34,"#":35,$:36,"%":37,"&":38,"'":39,
"(":40,")":41,"*":42,"+":43,",":44,"-":45,".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,Kd:65,xi:66,Di:67,dj:68,E:69,jj:70,mj:71,yj:72,Aj:73,Bj:74,Cj:75,Dj:76,Gj:77,Ij:78,Oj:79,Rj:80,Q:81,Tj:82,Wj:83,ek:84,gk:85,ik:86,jk:87,nk:88,pk:89,xf:90,"[":91,"\\":92,"]":93,"^":94,_:95,"`":96,qk:97,sk:98,vk:99,d:100,e:101,wk:102,xk:103,yk:104,zk:105,Dk:106,k:107,Ek:108,Fk:109,n:110,Gk:111,p:112,q:113,r:114,Hk:115,t:116,Kk:117,Lk:118,Mk:119,x:120,
y:121,z:122,"{":123,"|":124,"}":125,"~":126,cc:127};
var ka={163840:[40,1,8,,254],184320:[40,1,9,,252],327680:[40,2,8,,255],368640:[40,2,9,,253],737280:[80,2,9,,249],1228800:[80,2,15,,249],1474560:[80,2,18,,240],2949120:[80,2,36,,240],10618368:[306,4,17],21368320:[615,4,17],256256:[77,1,26,128],2494464:[203,2,12,512],5242880:[256,2,40,256],10485760:[512,2,40,256]},la={Bi:0,Fe:1,Ii:2,Ji:3,Ki:4,Li:5,Mi:6,Ni:7,Od:8,Oi:9,Ge:10,Pi:11,Qi:12,He:13,Ri:14,Si:15,Ti:16,Ui:17,Vi:18,Wi:19,Xi:20,Yi:21,Zi:22,$i:23,aj:24,bj:25,cj:26," ":32,"!":33,'"':34,"#":35,$:36,
"%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,"-":45,".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,Kd:65,xi:66,Di:67,dj:68,E:69,jj:70,mj:71,yj:72,Aj:73,Bj:74,Cj:75,Dj:76,Gj:77,Ij:78,Oj:79,Rj:80,Q:81,Tj:82,Wj:83,ek:84,gk:85,ik:86,jk:87,nk:88,pk:89,xf:90,"[":91,"\\":92,"]":93,"^":94,_:95,"`":96,qk:97,sk:98,vk:99,d:100,e:101,wk:102,xk:103,yk:104,zk:105,Dk:106,k:107,Ek:108,Fk:109,n:110,Gk:111,p:112,q:113,r:114,Hk:115,t:116,Kk:117,
Lk:118,Mk:119,x:120,y:121,z:122,"{":123,"|":124,"}":125,"~":126,cc:127};
function ma(a,b){var c;if(a){b||(b=10);var d,e,f=0<a.indexOf(",");f&&(a=a.replace(/,/g,""));d=e=a.charAt(0);"#"==e?(b=8,e=""):"$"==e&&(b=16,e="");d!=e?a=a.substr(1):(d=e=a.substr(0,2),"0b"==e&&f||"^B"==e?(b=2,e=""):"0o"==e||"^O"==e?(b=8,e=""):"^D"==e?(b=10,e=""):"0x"==e&&(b=16,e=""),d!=e&&(a=a.substr(2)));d=e=a.slice(-1);"Y"==e||"y"==e?(b=2,e=""):"."==e?(b=10,e=""):"H"==e||"h"==e?(b=16,e=""):"K"==e?e="000":"M"==e?e="000000":"G"==e&&(e="000000000");d!=e&&(a=a.slice(0,-1)+e);var g;d=0;10>=b&&(e=a.match(/(-?[0-9]+)B([0-9]*)/))&&
(a=e[1],d=35-((e[2]||35)&255));e=a;((f=b)&&10!=f?16==f?e.match(/^-?[0-9a-f]+$/i):8==f?e.match(/^-?[0-7]+$/):2==f&&e.match(/^-?[01]+$/):e.match(/^-?[0-9]+$/))&&!isNaN(g=parseInt(a,b))&&(d&&(0>g&&(g+=Math.pow(2,36)),g=0<d?g*Math.pow(2,d):Math.trunc(g/Math.pow(2,-d))),c=g)}return c}
function na(a,b,c,d,e){e=void 0===e?0:e;var f="";isNaN(a)?a=null:null!=a&&(0>a&&-1<a&&(a=-1),0>a&&(a+=Math.pow(b,c)),a>=Math.pow(b,c)&&(c=Math.ceil(Math.log(a)/Math.log(b))));for(var g=e||-1;0<c--;){g||(f=","+f,g=e);if(null==a)f="?"+f;else{var k=a%b,k=k+(0<=k&&9>=k?48:55),f=String.fromCharCode(k)+f;a=Math.trunc(a/b)}g--}return(void 0===d?"":d)+f}function pa(a,b,c){b?36<b&&(b=36):(b=Math.abs(a),b=255>=b?8:262143>=b?18:36);return na(a,2,b,"",c)}

View file

@ -38,9 +38,9 @@ var h,aa="function"==typeof Object.defineProperties?Object.defineProperty:functi
function fa(){ca();var a=ba.Symbol.iterator;a||(a=ba.Symbol.iterator=ba.Symbol("iterator"));"function"!=typeof Array.prototype[a]&&aa(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return ga(this)}});fa=function(){}}function ga(a){var b=0;return ha(function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}})}function ha(a){fa();a={next:a};a[ba.Symbol.iterator]=function(){return this};return a}function ia(a){fa();ca();fa();var b=a[Symbol.iterator];return b?b.call(a):ga(a)}
function n(a,b){function c(){}c.prototype=b.prototype;a.prototype=new c;a.prototype.constructor=a;for(var d in b)if(Object.defineProperties){var e=Object.getOwnPropertyDescriptor(b,d);e&&Object.defineProperty(a,d,e)}else a[d]=b[d]}function ja(a,b){if(b){var c=ba;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];e in c||(c[e]={});c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&aa(c,a,{configurable:!0,writable:!0,value:b})}}
ja("Math.trunc",function(a){return a?a:function(a){a=Number(a);if(isNaN(a)||Infinity===a||-Infinity===a||!a)return a;var b=Math.floor(Math.abs(a));return 0>a?-b:b}});ja("Math.log2",function(a){return a?a:function(a){return Math.log(a)/Math.LN2}});ja("Array.prototype.fill",function(a){return a?a:function(a,c,d){var b=this.length||0;0>c&&(c=Math.max(0,b+c));if(null==d||d>b)d=b;d=Number(d);0>d&&(d=Math.max(0,b+d));for(c=Number(c||0);c<d;c++)this[c]=a;return this}});
var ka={163840:[40,1,8,,254],184320:[40,1,9,,252],327680:[40,2,8,,255],368640:[40,2,9,,253],737280:[80,2,9,,249],1228800:[80,2,15,,249],1474560:[80,2,18,,240],2949120:[80,2,36,,240],21368320:[615,4,17],256256:[77,1,26,128],2494464:[203,2,12,512],5242880:[256,2,40,256],10485760:[512,2,40,256]},la={Ph:0,Ud:1,Wh:2,Xh:3,Yh:4,Zh:5,$h:6,ai:7,ld:8,bi:9,Vd:10,ci:11,di:12,Wd:13,ei:14,fi:15,gi:16,hi:17,ii:18,ji:19,ki:20,li:21,mi:22,ni:23,oi:24,pi:25,ri:26," ":32,"!":33,'"':34,"#":35,$:36,"%":37,"&":38,"'":39,
"(":40,")":41,"*":42,"+":43,",":44,"-":45,".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,jd:65,Lh:66,Rh:67,si:68,E:69,yi:70,Bi:71,Ni:72,Pi:73,Qi:74,Ri:75,Si:76,Vi:77,Xi:78,cj:79,fj:80,Q:81,hj:82,kj:83,tj:84,vj:85,xj:86,yj:87,Cj:88,Dj:89,Ke:90,"[":91,"\\":92,"]":93,"^":94,_:95,"`":96,Ej:97,Gj:98,Jj:99,d:100,e:101,Kj:102,Lj:103,Mj:104,Nj:105,Rj:106,k:107,Sj:108,Tj:109,n:110,Uj:111,p:112,q:113,r:114,Vj:115,t:116,Xj:117,Yj:118,Zj:119,x:120,
y:121,z:122,"{":123,"|":124,"}":125,"~":126,Cb:127};
var ka={163840:[40,1,8,,254],184320:[40,1,9,,252],327680:[40,2,8,,255],368640:[40,2,9,,253],737280:[80,2,9,,249],1228800:[80,2,15,,249],1474560:[80,2,18,,240],2949120:[80,2,36,,240],10618368:[306,4,17],21368320:[615,4,17],256256:[77,1,26,128],2494464:[203,2,12,512],5242880:[256,2,40,256],10485760:[512,2,40,256]},la={Ph:0,Ud:1,Wh:2,Xh:3,Yh:4,Zh:5,$h:6,ai:7,ld:8,bi:9,Vd:10,ci:11,di:12,Wd:13,ei:14,fi:15,gi:16,hi:17,ii:18,ji:19,ki:20,li:21,mi:22,ni:23,oi:24,pi:25,ri:26," ":32,"!":33,'"':34,"#":35,$:36,
"%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,"-":45,".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,jd:65,Lh:66,Rh:67,si:68,E:69,yi:70,Bi:71,Ni:72,Pi:73,Qi:74,Ri:75,Si:76,Vi:77,Xi:78,cj:79,fj:80,Q:81,hj:82,kj:83,tj:84,vj:85,xj:86,yj:87,Cj:88,Dj:89,Ke:90,"[":91,"\\":92,"]":93,"^":94,_:95,"`":96,Ej:97,Gj:98,Jj:99,d:100,e:101,Kj:102,Lj:103,Mj:104,Nj:105,Rj:106,k:107,Sj:108,Tj:109,n:110,Uj:111,p:112,q:113,r:114,Vj:115,t:116,Xj:117,
Yj:118,Zj:119,x:120,y:121,z:122,"{":123,"|":124,"}":125,"~":126,Cb:127};
function na(a,b){var c;if(a){b||(b=10);var d,e,f=0<a.indexOf(",");f&&(a=a.replace(/,/g,""));d=e=a.charAt(0);"#"==e?(b=8,e=""):"$"==e&&(b=16,e="");d!=e?a=a.substr(1):(d=e=a.substr(0,2),"0b"==e&&f||"^B"==e?(b=2,e=""):"0o"==e||"^O"==e?(b=8,e=""):"^D"==e?(b=10,e=""):"0x"==e&&(b=16,e=""),d!=e&&(a=a.substr(2)));d=e=a.slice(-1);"Y"==e||"y"==e?(b=2,e=""):"."==e?(b=10,e=""):"H"==e||"h"==e?(b=16,e=""):"K"==e?e="000":"M"==e?e="000000":"G"==e&&(e="000000000");d!=e&&(a=a.slice(0,-1)+e);var g;d=0;10>=b&&(e=a.match(/(-?[0-9]+)B([0-9]*)/))&&
(a=e[1],d=35-((e[2]||35)&255));e=a;((f=b)&&10!=f?16==f?e.match(/^-?[0-9a-f]+$/i):8==f?e.match(/^-?[0-7]+$/):2==f&&e.match(/^-?[01]+$/):e.match(/^-?[0-9]+$/))&&!isNaN(g=parseInt(a,b))&&(d&&(0>g&&(g+=Math.pow(2,36)),g=0<d?g*Math.pow(2,d):Math.trunc(g/Math.pow(2,-d))),c=g)}return c}
function oa(a,b,c,d){var e;e=void 0===e?0:e;var f="";isNaN(a)?a=null:null!=a&&(0>a&&-1<a&&(a=-1),0>a&&(a+=Math.pow(b,c)),a>=Math.pow(b,c)&&(c=Math.ceil(Math.log(a)/Math.log(b))));for(var g=e||-1;0<c--;){g||(f=","+f,g=e);if(null==a)f="?"+f;else{var k=a%b,k=k+(0<=k&&9>=k?48:55),f=String.fromCharCode(k)+f;a=Math.trunc(a/b)}g--}return(void 0===d?"":d)+f}function pa(a,b){b?12<b&&(b=12):(b=Math.abs(a),b=262143>=b?6:16777215>=b?8:12);return oa(a,8,b,"")}