diff options
Diffstat (limited to 'trunk/etherpad/src/etherpad/pad/easysync2migration.js')
-rw-r--r-- | trunk/etherpad/src/etherpad/pad/easysync2migration.js | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/trunk/etherpad/src/etherpad/pad/easysync2migration.js b/trunk/etherpad/src/etherpad/pad/easysync2migration.js new file mode 100644 index 0000000..c2a1523 --- /dev/null +++ b/trunk/etherpad/src/etherpad/pad/easysync2migration.js @@ -0,0 +1,675 @@ +/** + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import("etherpad.collab.ace.easysync1"); +import("etherpad.collab.ace.easysync2"); +import("sqlbase.sqlbase"); +import("fastJSON"); +import("sqlbase.sqlcommon.*"); +import("etherpad.collab.ace.contentcollector.sanitizeUnicode"); + +function _getPadStringArrayNumId(padId, arrayName) { + var stmnt = "SELECT NUMID FROM "+btquote("PAD_"+arrayName.toUpperCase()+"_META")+ + " WHERE ("+btquote("ID")+" = ?)"; + + return withConnection(function(conn) { + var pstmnt = conn.prepareStatement(stmnt); + return closing(pstmnt, function() { + pstmnt.setString(1, padId); + var resultSet = pstmnt.executeQuery(); + return closing(resultSet, function() { + if (! resultSet.next()) { + return -1; + } + return resultSet.getInt(1); + }); + }); + }); +} + +function _getEntirePadStringArray(padId, arrayName) { + var numId = _getPadStringArrayNumId(padId, arrayName); + if (numId < 0) { + return []; + } + + var stmnt = "SELECT PAGESTART, OFFSETS, DATA FROM "+btquote("PAD_"+arrayName.toUpperCase()+"_TEXT")+ + " WHERE ("+btquote("NUMID")+" = ?)"; + + return withConnection(function(conn) { + var pstmnt = conn.prepareStatement(stmnt); + return closing(pstmnt, function() { + pstmnt.setInt(1, numId); + var resultSet = pstmnt.executeQuery(); + return closing(resultSet, function() { + var array = []; + while (resultSet.next()) { + var pageStart = resultSet.getInt(1); + var lengthsString = resultSet.getString(2); + var dataString = resultSet.getString(3); + var dataIndex = 0; + var arrayIndex = pageStart; + lengthsString.split(',').forEach(function(len) { + if (len) { + len = Number(len); + array[arrayIndex] = dataString.substr(dataIndex, len); + dataIndex += len; + } + arrayIndex++; + }); + } + return array; + }); + }); + }); +} + +function _overwriteEntirePadStringArray(padId, arrayName, array) { + var numId = _getPadStringArrayNumId(padId, arrayName); + if (numId < 0) { + // generate numId + withConnection(function(conn) { + var ps = conn.prepareStatement("INSERT INTO "+btquote("PAD_"+arrayName.toUpperCase()+"_META")+ + " ("+btquote("ID")+") VALUES (?)", + java.sql.Statement.RETURN_GENERATED_KEYS); + closing(ps, function() { + ps.setString(1, padId); + ps.executeUpdate(); + var keys = ps.getGeneratedKeys(); + if ((! keys) || (! keys.next())) { + throw new Error("Couldn't generate key for "+arrayName+" table for pad "+padId); + } + closing(keys, function() { + numId = keys.getInt(1); + }); + }); + }); + } + + withConnection(function(conn) { + + var stmnt1 = "DELETE FROM "+btquote("PAD_"+arrayName.toUpperCase()+"_TEXT")+ + " WHERE ("+btquote("NUMID")+" = ?)"; + var pstmnt1 = conn.prepareStatement(stmnt1); + closing(pstmnt1, function() { + pstmnt1.setInt(1, numId); + pstmnt1.executeUpdate(); + }); + + var PAGE_SIZE = 20; + var numPages = Math.floor((array.length-1) / PAGE_SIZE + 1); + + var PAGES_PER_BATCH = 20; + var curPage = 0; + + while (curPage < numPages) { + var stmnt2 = "INSERT INTO "+btquote("PAD_"+arrayName.toUpperCase()+"_TEXT")+ + " ("+btquote("NUMID")+", "+btquote("PAGESTART")+", "+btquote("OFFSETS")+ + ", "+btquote("DATA")+") VALUES (?, ?, ?, ?)"; + var pstmnt2 = conn.prepareStatement(stmnt2); + closing(pstmnt2, function() { + for(var n=0;n<PAGES_PER_BATCH && curPage < numPages;n++) { + var pageStart = curPage*PAGE_SIZE; + var r = pageStart; + var lengthPieces = []; + var dataPieces = []; + for(var i=0;i<PAGE_SIZE;i++) { + var str = (array[r] || ''); + dataPieces.push(str); + lengthPieces.push(String(str.length || '')); + r++; + } + var lengthsString = lengthPieces.join(','); + var dataString = dataPieces.join(''); + pstmnt2.setInt(1, numId); + pstmnt2.setInt(2, pageStart); + pstmnt2.setString(3, lengthsString); + pstmnt2.setString(4, dataString); + pstmnt2.addBatch(); + + curPage++; + } + pstmnt2.executeBatch(); + }); + } + }); + +} + +function _getEntirePadJSONArray(padId, arrayName) { + var array = _getEntirePadStringArray(padId, arrayName); + for(var k in array) { + if (array[k]) { + array[k] = fastJSON.parse(array[k]); + } + } + return array; +} + +function _overwriteEntirePadJSONArray(padId, arrayName, objArray) { + var array = []; + for(var k in objArray) { + if (objArray[k]) { + array[k] = fastJSON.stringify(objArray[k]); + } + } + _overwriteEntirePadStringArray(padId, arrayName, array); +} + +function _getMigrationPad(padId) { + var oldRevs = _getEntirePadStringArray(padId, "revs"); + var oldRevMeta = _getEntirePadJSONArray(padId, "revmeta"); + var oldAuthors = _getEntirePadJSONArray(padId, "authors"); + var oldMeta = sqlbase.getJSON("PAD_META", padId); + + var oldPad = { + getHeadRevisionNumber: function() { + return oldMeta.head; + }, + getRevisionChangesetString: function(r) { + return oldRevs[r]; + }, + getRevisionAuthor: function(r) { + return oldMeta.numToAuthor[oldRevMeta[r].a]; + }, + getId: function() { return padId; }, + getKeyRevisionNumber: function(r) { + return Math.floor(r / oldMeta.keyRevInterval) * oldMeta.keyRevInterval; + }, + getInternalRevisionText: function(r) { + if (r != oldPad.getKeyRevisionNumber(r)) { + throw new Error("Assertion error: "+r+" != "+oldPad.getKeyRevisionNumber(r)); + } + return oldRevMeta[r].atext.text; + }, + _meta: oldMeta, + getAuthorArrayEntry: function(n) { + return oldAuthors[n]; + }, + getRevMetaArrayEntry: function(r) { + return oldRevMeta[r]; + } + }; + + var apool = new easysync2.AttribPool(); + var newRevMeta = []; + var newAuthors = []; + var newRevs = []; + var metaPropsToDelete = []; + + var newPad = { + pool: function() { return apool; }, + setAuthorArrayEntry: function(n, obj) { + newAuthors[n] = obj; + }, + setRevMetaArrayEntry: function(r, obj) { + newRevMeta[r] = obj; + }, + setRevsArrayEntry: function(r, cs) { + newRevs[r] = cs; + }, + deleteMetaProp: function(propName) { + metaPropsToDelete.push(propName); + } + }; + + function writeToDB() { + var newMeta = {}; + for(var k in oldMeta) { + newMeta[k] = oldMeta[k]; + } + metaPropsToDelete.forEach(function(p) { + delete newMeta[p]; + }); + + sqlbase.putJSON("PAD_META", padId, newMeta); + sqlbase.putJSON("PAD_APOOL", padId, apool.toJsonable()); + + _overwriteEntirePadStringArray(padId, "revs", newRevs); + _overwriteEntirePadJSONArray(padId, "revmeta", newRevMeta); + _overwriteEntirePadJSONArray(padId, "authors", newAuthors); + } + + return {oldPad:oldPad, newPad:newPad, writeToDB:writeToDB}; +} + +function migratePad(padId) { + + var mpad = _getMigrationPad(padId); + var oldPad = mpad.oldPad; + var newPad = mpad.newPad; + + var headRev = oldPad.getHeadRevisionNumber(); + var txt = "\n"; + var newChangesets = []; + var newChangesetAuthorNums = []; + var cumCs = easysync2.Changeset.identity(1); + + var pool = newPad.pool(); + + var isExtraFinalNewline = false; + + function authorToNewNum(author) { + return pool.putAttrib(['author',author||'']); + } + + //S var oldTotalChangesetSize = 0; + //S var newTotalChangesetSize = 0; + //S function stringSize(str) { + //S return new java.lang.String(str).getBytes("UTF-8").length; + //S } + + //P var diffTotals = []; + for(var r=0;r<=headRev;r++) { + //P var times = []; + //P times.push(+new Date); + var author = oldPad.getRevisionAuthor(r); + //P times.push(+new Date); + newChangesetAuthorNums.push(authorToNewNum(author)); + + var newCs, newText; + if (r == 0) { + newText = oldPad.getInternalRevisionText(0); + newCs = getInitialChangeset(newText, pool, author); + //S oldTotalChangesetSize += stringSize(pad.getRevisionChangesetString(0)); + } + else { + var oldCsStr = oldPad.getRevisionChangesetString(r); + //S oldTotalChangesetSize += stringSize(oldCsStr); + //P times.push(+new Date); + var oldCs = easysync1.Changeset.decodeFromString(oldCsStr); + //P times.push(+new Date); + + /*var newTextFromOldCs = oldCs.applyToText(txt); + if (newTextFromOldCs.charAt(newTextFromOldCs.length-1) != '\n') { + var e = new Error("Violation of final newline property at revision "+r); + e.finalNewlineMissing = true; + throw e; + }*/ + //var newCsNewTxt1 = upgradeChangeset(oldCs, txt, pool, author); + var oldIsExtraFinalNewline = isExtraFinalNewline; + var newCsNewTxt2 = upgradeChangeset(oldCs, txt, pool, author, isExtraFinalNewline); + //P times.push(+new Date); + /*if (newCsNewTxt1[1] != newCsNewTxt2[1]) { + _putFile(newCsNewTxt1[1], "/tmp/file1"); + _putFile(newCsNewTxt2[1], "/tmp/file2"); + throw new Error("MISMATCH 1"); + } + if (newCsNewTxt1[0] != newCsNewTxt2[0]) { + _putFile(newCsNewTxt1[0], "/tmp/file1"); + _putFile(newCsNewTxt2[0], "/tmp/file2"); + throw new Error("MISMATCH 0"); + }*/ + newCs = newCsNewTxt2[0]; + newText = newCsNewTxt2[1]; + isExtraFinalNewline = newCsNewTxt2[2]; + + /*if (oldIsExtraFinalNewline || isExtraFinalNewline) { + System.out.print("\nnewline fix for rev "+r+"/"+headRev+"... "); + }*/ + } + + var oldText = txt; + newChangesets.push(newCs); + txt = newText; + //System.out.println(easysync2.Changeset.toBaseTen(cumCs)+" * "+ + //easysync2.Changeset.toBaseTen(newCs)); + /*cumCs = easysync2.Changeset.checkRep(easysync2.Changeset.compose(cumCs, newCs)); + if (easysync2.Changeset.applyToText(cumCs, "\n") != txt) { + throw new Error("cumCs mismatch"); + }*/ + + //P times.push(+new Date); + + easysync2.Changeset.checkRep(newCs); + //P times.push(+new Date); + var origText = txt; + if (isExtraFinalNewline) { + origText = origText.slice(0, -1); + } + if (r == oldPad.getKeyRevisionNumber(r)) { + // only check key revisions (and final outcome), for speed + if (oldPad.getInternalRevisionText(r) != origText) { + var expected = oldPad.getInternalRevisionText(r); + var actual = origText; + //_putFile(expected, "/tmp/file1"); + //_putFile(actual, "/tmp/file2"); + //_putFile(oldText, "/tmp/file3"); + //java.lang.System.out.println(String(oldCs)); + //java.lang.System.out.println(easysync2.Changeset.toBaseTen(newCs)); + throw new Error("Migration mismatch, pad "+padId+", revision "+r); + } + } + + //S newTotalChangesetSize += stringSize(newCs); + + //P if (r > 0) { + //P var diffs = []; + //P for(var i=0;i<times.length-1;i++) { + //P diffs[i] = times[i+1] - times[i]; + //P } + //P for(var i=0;i<diffs.length;i++) { + //P diffTotals[i] = (diffTotals[i] || 0) + diffs[i]*1000/headRev; + //P } + //P } + } + //P System.out.println(String(diffTotals)); + + //S System.out.println("New data is "+(newTotalChangesetSize/oldTotalChangesetSize*100)+ + //S "% size of old data (average "+(newTotalChangesetSize/(headRev+1))+ + //S " bytes instead of "+(oldTotalChangesetSize/(headRev+1))+")"); + + var atext = easysync2.Changeset.makeAText("\n"); + for(var r=0; r<=headRev; r++) { + newPad.setRevsArrayEntry(r, newChangesets[r]); + + atext = easysync2.Changeset.applyToAText(newChangesets[r], atext, pool); + + var rm = oldPad.getRevMetaArrayEntry(r); + rm.a = newChangesetAuthorNums[r]; + if (rm.atext) { + rm.atext = easysync2.Changeset.cloneAText(atext); + } + newPad.setRevMetaArrayEntry(r, rm); + } + + var newAuthors = []; + var newAuthorDatas = []; + for(var k in oldPad._meta.numToAuthor) { + var n = Number(k); + var authorData = oldPad.getAuthorArrayEntry(n) || {}; + var authorName = oldPad._meta.numToAuthor[n]; + var newAuthorNum = pool.putAttrib(['author',authorName]); + newPad.setAuthorArrayEntry(newAuthorNum, authorData); + } + + newPad.deleteMetaProp('numToAuthor'); + newPad.deleteMetaProp('authorToNum'); + + mpad.writeToDB(); +} + +function getInitialChangeset(txt, pool, author) { + var txt2 = txt.substring(0, txt.length-1); // strip off final newline + + var assem = easysync2.Changeset.smartOpAssembler(); + assem.appendOpWithText('+', txt2, pool && author && [['author',author]], pool); + assem.endDocument(); + return easysync2.Changeset.pack(1, txt2.length+1, assem.toString(), txt2); +} + +function upgradeChangeset(cs, inputText, pool, author, isExtraNewlineInSource) { + var attribs = ''; + if (pool && author) { + attribs = '*'+easysync2.Changeset.numToString(pool.putAttrib(['author', author])); + } + + function keepLastCharacter(c) { + if (! c[c.length-1] && c[c.length-3] + c[c.length-2] >= (c.oldLen() - 1)) { + c[c.length-2] = c.oldLen() - c[c.length-3]; + } + else { + c.push(c.oldLen() - 1, 1, ""); + } + } + + var isExtraNewlineInOutput = false; + if (isExtraNewlineInSource) { + cs[1] += 1; // oldLen ++ + } + if ((cs[cs.length-1] && cs[cs.length-1].slice(-1) != '\n') || + ((! cs[cs.length-1]) && inputText.charAt(cs[cs.length-3] + cs[cs.length-2] - 1) != '\n')) { + // new text won't end with newline! + if (isExtraNewlineInSource) { + keepLastCharacter(cs); + } + else { + cs[cs.length-1] += "\n"; + } + cs[2] += 1; // newLen ++ + isExtraNewlineInOutput = true; + } + + var oldLen = cs.oldLen(); + var newLen = cs.newLen(); + + // final-newline-preserving modifications to changeset {{{ + // These fixes are required for changesets that don't respect the + // new rule that the final newline of the document not be touched, + // and also for changesets tweaked above. It is important that the + // fixed changesets obey all the constraints on version 1 changesets + // so that they may become valid version 2 changesets. + { + function collapsePotentialEmptyLastTake(c) { + if (c[c.length-2] == 0 && c.length > 6) { + if (! c[c.length-1]) { + // last strip doesn't take or insert now + c.length -= 3; + } + else { + // the last two strips should be merged + // e.g. fo\n -> rock\nbar\n: then in this block, + // "Changeset,3,9,0,0,r,1,1,ck,2,0,\nbar" becomes + // "Changeset,3,9,0,0,r,1,1,ck\nbar" + c[c.length-4] += c[c.length-1]; + c.length -= 3; + } + } + } + var lastStripStart = cs[cs.length-3]; + var lastStripTake = cs[cs.length-2]; + var lastStripInsert = cs[cs.length-1]; + if (lastStripStart + lastStripTake == oldLen && lastStripInsert) { + // an insert at end + // e.g. foo\n -> foo\nbar\n: + // "Changeset,4,8,0,4,bar\n" becomes "Changeset,4,8,0,3,\nbar,3,1," + // first make the previous newline part of the insertion + cs[cs.length-2] -= 1; + cs[cs.length-1] = '\n'+cs[cs.length-1].slice(0,-1); + collapsePotentialEmptyLastTake(cs); + keepLastCharacter(cs); + } + else if (lastStripStart + lastStripTake < oldLen && ! lastStripInsert) { + // ends with pure deletion + cs[cs.length-2] -= 1; + collapsePotentialEmptyLastTake(cs); + keepLastCharacter(cs); + } + else if (lastStripStart + lastStripTake < oldLen) { + // ends with replacement + cs[cs.length-1] = cs[cs.length-1].slice(0,-1); + keepLastCharacter(cs); + } + } + // }}} + + var ops = []; + var lastOpcode = ''; + function appendOp(opcode, text, startChar, endChar) { + function num(n) { + return easysync2.Changeset.numToString(n); + } + var lines = 0; + var lastNewlineEnd = startChar; + for (;;) { + var index = text.indexOf('\n', lastNewlineEnd); + if (index < 0 || index >= endChar) { + break; + } + lines++; + lastNewlineEnd = index+1; + } + var a = (opcode == '+' ? attribs : ''); + var multilineChars = (lastNewlineEnd - startChar); + var seqLength = endChar - startChar; + var op = ''; + if (lines > 0) { + op = [a, '|', num(lines), opcode, num(multilineChars)].join(''); + } + if (multilineChars < seqLength) { + op += [a, opcode, num(seqLength - multilineChars)].join(''); + } + if (op) { + // we reorder a single - and a single + + if (opcode == '-' && lastOpcode == '+') { + ops.splice(ops.length-1, 0, op); + } + else { + ops.push(op); + lastOpcode = opcode; + } + } + } + + var oldPos = 0; + + var textPieces = []; + var charBankPieces = []; + cs.eachStrip(function(start, take, insert) { + if (start > oldPos) { + appendOp('-', inputText, oldPos, start); + } + if (take) { + if (start+take < oldLen || insert) { + appendOp('=', inputText, start, start+take); + } + textPieces.push(inputText.substring(start, start+take)); + } + if (insert) { + appendOp('+', insert, 0, insert.length); + textPieces.push(insert); + charBankPieces.push(insert); + } + oldPos = start+take; + }); + // ... and no final deletions after the newline fixing. + + var newCs = easysync2.Changeset.pack(oldLen, newLen, ops.join(''), + sanitizeUnicode(charBankPieces.join(''))); + var newText = textPieces.join(''); + + return [newCs, newText, isExtraNewlineInOutput]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// unicode issues: 5SaYQp7cKV + +// // hard-coded just for testing; any pad is allowed to have corruption. +// var newlineCorruptedPads = [ +// '0OCGFKkjDv', '14dWjOiOxP', '1LL8XQCBjC', '1jMnjEEK6e', '21', +// '23DytOPN7d', '32YzfdT2xS', '3E6GB7l7FZ', '3Un8qaCfJh', '3YAj3rC9em', +// '3vY2eaHSw5', '4834RRTLlg', '4Fm1iVSTWI', '5NpTNqWHGC', '7FYNSdYQVa', +// '7RZCbvgw1z', '8EVpyN6HyY', '8P5mPRxPVr', '8aHFRmLxKR', '8dsj9eGQfP', +// 'BSoGobOJZZ', 'Bf0uVghKy0', 'C2f3umStKd', 'CHlu2CA8F3', 'D2WEwgvg1W', +// 'DNLTpuP2wl', 'DwNpm2TDgu', 'EKPByZ3EGZ', 'FwQxu6UKQx', 'HUn9O34rFl', +// 'JKZhxMo20E', 'JVjuukL42N', 'JVuBlWxaxL', 'Jmw5lPNYcl', 'KnZHz6jE2P', +// 'Luyp6ylbgR', 'MB6lPoN1eI', 'McsCrQUM6c', 'NWIuVobIw9', 'OKERTLQCCn', +// 'OchiOchi', 'OfhKHCB8jJ', 'OkM3Jv3XY9', 'PX5Z89mx29', 'PdmKQIvOEd', +// 'R9NQNB66qt', 'RvULFSvCbV', 'RyLJC6Qo1x', 'SBlKLwr2Ag', 'SavD72Q9P7', +// 'SfXyxseAeF', 'TTGZ4yO2PI', 'U3U7rT3d6w', 'UFmqpQIDAi', 'V7Or0QQk4m', +// 'VPCM5ReAQm', 'VvIYHzIJUY', 'W0Ccc3BVGb', 'Wv3cGgSgjg', 'WwVPgaZUK5', +// 'WyIFUJXfm5', 'XxESEsgQ6R', 'Yc5Yq3WCuU', 'ZRqCFaRx6h', 'ZepX6TLFbD', +// 'bSeImT5po4', 'bqIlTkFDiH', 'btt9vNPSQ9', 'c97YJj8PSN', 'd9YV3sypKF', +// 'eDzzkrwDRU', 'eFQJZWclzo', 'eaz44OhFDu', 'ehKkx1YpLA', 'ep', +// 'foNq3v3e9T', 'form6rooma', 'fqhtIHG0Ii', 'fvZyCRZjv2', 'gZnadICPYV', +// 'gvGXtMKhQk', 'h7AYuTxUOd', 'hc1UZSti3J', 'hrFQtae2jW', 'i8rENUZUMu', +// 'iFW9dceEmh', 'iRNEc8SlOc', 'jEDsDgDlaK', 'jo8ngXlSJh', 'kgJrB9Gh2M', +// 'klassennetz76da2661f8ceccfe74faf97d25a4b418', +// 'klassennetzf06d4d8176d0804697d9650f836cb1f7', 'lDHgmfyiSu', +// 'mA1cbvxFwA', 'mSJpW1th29', 'mXHAqv1Emu', 'monocles12', 'n0NhU3FxxT', +// 'ng7AlzPb5b', 'ntbErnnuyz', 'oVnMO0dX80', 'omOTPVY3Gl', 'p5aNFCfYG9', +// 'pYxjVCILuL', 'phylab', 'pjVBFmnhf1', 'qGohFW3Lbr', 'qYlbjeIHDs', +// 'qgf4OwkFI6', 'qsi', 'rJQ09pRexM', 'snNjlS1aLC', 'tYKC53TDF9', +// 'u1vZmL8Yjv', 'ur4sb7DBJB', 'vesti', 'w9NJegEAZt', 'wDwlSCby2s', +// 'wGFJJRT514', 'wTgEoQGqng', 'xomMZGhius', 'yFEFYWBSvr', 'z7tGFKsGk6', +// 'zIJWNK8Z4i', 'zNMGJYI7hq']; + +// function _time(f) { +// var t1 = +(new Date); +// f(); +// var t2 = +(new Date); +// return t2 - t1; +// } + +// function listAllRevisionCounts() { +// var padList = sqlbase.getAllJSONKeys("PAD_META"); +// //padList.length = 10; +// padList = padList.slice(68000, 68100); +// padList.forEach(function(id) { +// model.accessPadGlobal(id, function(pad) { +// System.out.println((new java.lang.Integer(pad.getHeadRevisionNumber()).toString())+ +// " "+id); +// dbwriter.writePadNow(pad, true); +// }, 'r'); +// }); +// } + +// function verifyAllPads() { +// //var padList = sqlbase.getAllJSONKeys("PAD_META"); +// //padList = newlineCorruptedPads; +// var padList = ['0OCGFKkjDv']; +// //padList = ['form6rooma']; +// //padList.length = 10; +// var numOks = 0; +// var numErrors = 0; +// var numNewlineBugs = 0; +// var longestPad; +// var longestPadTime = -1; +// System.out.println(padList.length+" pads."); +// var totalTime = _time(function() { +// padList.forEach(function(id) { +// model.accessPadGlobal(id, function(pad) { +// var padTime = _time(function() { +// System.out.print(id+"... "); +// try { +// verifyMigration(pad); +// System.out.println("OK ("+(++numOks)+")"); +// } +// catch (e) { +// System.out.println("ERROR ("+(++numErrors)+")"+(e.finalNewlineMissing?" [newline]":"")); +// System.out.println(e.toString()); +// if (e.finalNewlineMissing) { +// numNewlineBugs++; +// } +// } +// }); +// if (padTime > longestPadTime) { +// longestPadTime = padTime; +// longestPad = id; +// } +// }, 'r'); +// }); +// }); +// System.out.println("finished verifyAllPads in "+(totalTime/1000)+" seconds."); +// System.out.println(numOks+" OK"); +// System.out.println(numErrors+" ERROR"); +// System.out.println("Most time-consuming pad: "+longestPad+" / "+longestPadTime+" ms"); +// } + +// function _literal(v) { +// if ((typeof v) == "string") { +// return '"'+v.replace(/[\\\"]/g, '\\$1').replace(/\n/g, '\\n')+'"'; +// } +// else return v.toSource(); +// } + +// function _putFile(str, path) { +// var writer = new java.io.FileWriter(path); +// writer.write(str); +// writer.close(); +// } |