mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-27 19:06:15 -04:00
prepare to async: trivial reformatting
This change is only cosmetic. Its aim is do make it easier to understand the async changes that are going to be merged later on. It was extracted from the original work from Ray Bellis. To verify that nothing has changed, you can run the following command on each file touched by this commit: npm install uglify-es diff --unified <(uglify-js --beautify bracketize <BEFORE.js>) <(uglify-js --beautify bracketize <AFTER.js>) This is a complete script that does the same automatically (works from a mercurial clone): ```bash #!/usr/bin/env bash set -eu REVISION=<THIS_REVISION> PARENT_REV=$(hg identify --rev "${REVISION}" --template '{p1rev}') FILE_LIST=$(hg status --no-status --change ${REVISION}) UGLIFYJS="node_modules/uglify-es/bin/uglifyjs" for FILE_NAME in ${FILE_LIST[@]}; do echo "Checking ${FILE_NAME}" diff --unified \ <("${UGLIFYJS}" --beautify bracketize <(hg cat --rev "${PARENT_REV}" "${FILE_NAME}")) \ <("${UGLIFYJS}" --beautify bracketize <(hg cat --rev "${REVISION}" "${FILE_NAME}")) done ```
This commit is contained in:
parent
cc23bd18a4
commit
9497ee734f
33 changed files with 2706 additions and 2943 deletions
|
@ -1,144 +1,133 @@
|
|||
/*
|
||||
This is a debug tool. It checks all revisions for data corruption
|
||||
*/
|
||||
* This is a debug tool. It checks all revisions for data corruption
|
||||
*/
|
||||
|
||||
if(process.argv.length != 2)
|
||||
{
|
||||
if (process.argv.length != 2) {
|
||||
console.error("Use: node bin/checkAllPads.js");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
//initialize the variables
|
||||
// initialize the variables
|
||||
var db, settings, padManager;
|
||||
var npm = require("../src/node_modules/npm");
|
||||
var async = require("../src/node_modules/async");
|
||||
var npm = require('../src/node_modules/npm');
|
||||
var async = require('../src/node_modules/async');
|
||||
|
||||
var Changeset = require("../src/static/js/Changeset");
|
||||
var Changeset = require('../src/static/js/Changeset');
|
||||
|
||||
async.series([
|
||||
//load npm
|
||||
// load npm
|
||||
function(callback) {
|
||||
npm.load({}, callback);
|
||||
},
|
||||
//load modules
|
||||
|
||||
// load modules
|
||||
function(callback) {
|
||||
settings = require('../src/node/utils/Settings');
|
||||
db = require('../src/node/db/DB');
|
||||
|
||||
//initialize the database
|
||||
// initialize the database
|
||||
db.init(callback);
|
||||
},
|
||||
//load pads
|
||||
function (callback)
|
||||
{
|
||||
|
||||
// load pads
|
||||
function (callback) {
|
||||
padManager = require('../src/node/db/PadManager');
|
||||
|
||||
padManager.listAllPads(function(err, res)
|
||||
{
|
||||
|
||||
padManager.listAllPads(function(err, res) {
|
||||
padIds = res.padIDs;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
function (callback)
|
||||
{
|
||||
async.forEach(padIds, function(padId, callback)
|
||||
{
|
||||
padManager.getPad(padId, function(err, pad) {
|
||||
|
||||
function (callback) {
|
||||
async.forEach(padIds, function(padId, callback) {
|
||||
padManager.getPad(padId, function(err, pad) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
}
|
||||
|
||||
// check if the pad has a pool
|
||||
if (pad.pool === undefined ) {
|
||||
console.error("[" + pad.id + "] Missing attribute pool");
|
||||
callback();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// create an array with key kevisions
|
||||
// key revisions always save the full pad atext
|
||||
var head = pad.getHeadRevisionNumber();
|
||||
var keyRevisions = [];
|
||||
for (var i = 0; i < head; i += 100) {
|
||||
keyRevisions.push(i);
|
||||
}
|
||||
|
||||
// run through all key revisions
|
||||
async.forEachSeries(keyRevisions, function(keyRev, callback) {
|
||||
// create an array of revisions we need till the next keyRevision or the End
|
||||
var revisionsNeeded = [];
|
||||
|
||||
for(var i = keyRev; i <= keyRev + 100 && i <= head; i++) {
|
||||
revisionsNeeded.push(i);
|
||||
}
|
||||
|
||||
// this array will hold all revision changesets
|
||||
var revisions = [];
|
||||
|
||||
// run through all needed revisions and get them from the database
|
||||
async.forEach(revisionsNeeded, function(revNum, callback) {
|
||||
db.db.get("pad:" + pad.id + ":revs:" + revNum, function(err, revision) {
|
||||
revisions[revNum] = revision;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
|
||||
function(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
//check if the pad has a pool
|
||||
if(pad.pool === undefined )
|
||||
{
|
||||
console.error("[" + pad.id + "] Missing attribute pool");
|
||||
|
||||
// check if the revision exists
|
||||
if (revisions[keyRev] == null) {
|
||||
console.error("[" + pad.id + "] Missing revision " + keyRev);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// check if there is a atext in the keyRevisions
|
||||
if (revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined) {
|
||||
console.error("[" + pad.id + "] Missing atext in revision " + keyRev);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var apool = pad.pool;
|
||||
var atext = revisions[keyRev].meta.atext;
|
||||
|
||||
for(var i = keyRev + 1; i <= keyRev + 100 && i <= head; i++) {
|
||||
try {
|
||||
// console.log("[" + pad.id + "] check revision " + i);
|
||||
var cs = revisions[i].changeset;
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
} catch(e) {
|
||||
console.error("[" + pad.id + "] Bad changeset at revision " + i + " - " + e.message);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//create an array with key kevisions
|
||||
//key revisions always save the full pad atext
|
||||
var head = pad.getHeadRevisionNumber();
|
||||
var keyRevisions = [];
|
||||
for(var i=0;i<head;i+=100)
|
||||
{
|
||||
keyRevisions.push(i);
|
||||
}
|
||||
|
||||
//run trough all key revisions
|
||||
async.forEachSeries(keyRevisions, function(keyRev, callback)
|
||||
{
|
||||
//create an array of revisions we need till the next keyRevision or the End
|
||||
var revisionsNeeded = [];
|
||||
for(var i=keyRev;i<=keyRev+100 && i<=head; i++)
|
||||
{
|
||||
revisionsNeeded.push(i);
|
||||
}
|
||||
|
||||
//this array will hold all revision changesets
|
||||
var revisions = [];
|
||||
|
||||
//run trough all needed revisions and get them from the database
|
||||
async.forEach(revisionsNeeded, function(revNum, callback)
|
||||
{
|
||||
db.db.get("pad:"+pad.id+":revs:" + revNum, function(err, revision)
|
||||
{
|
||||
revisions[revNum] = revision;
|
||||
callback(err);
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
if(err)
|
||||
{
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
//check if the revision exists
|
||||
if (revisions[keyRev] == null) {
|
||||
console.error("[" + pad.id + "] Missing revision " + keyRev);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
//check if there is a atext in the keyRevisions
|
||||
if(revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined)
|
||||
{
|
||||
console.error("[" + pad.id + "] Missing atext in revision " + keyRev);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var apool = pad.pool;
|
||||
var atext = revisions[keyRev].meta.atext;
|
||||
|
||||
for(var i=keyRev+1;i<=keyRev+100 && i<=head; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
//console.log("[" + pad.id + "] check revision " + i);
|
||||
var cs = revisions[i].changeset;
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
console.error("[" + pad.id + "] Bad changeset at revision " + i + " - " + e.message);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
}, callback);
|
||||
});
|
||||
callback();
|
||||
});
|
||||
}, callback);
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
], function (err)
|
||||
{
|
||||
if(err) throw err;
|
||||
else
|
||||
{
|
||||
],
|
||||
function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log("finished");
|
||||
process.exit(0);
|
||||
}
|
||||
|
|
130
bin/checkPad.js
130
bin/checkPad.js
|
@ -1,140 +1,126 @@
|
|||
/*
|
||||
This is a debug tool. It checks all revisions for data corruption
|
||||
*/
|
||||
* This is a debug tool. It checks all revisions for data corruption
|
||||
*/
|
||||
|
||||
if(process.argv.length != 3)
|
||||
{
|
||||
if (process.argv.length != 3) {
|
||||
console.error("Use: node bin/checkPad.js $PADID");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
//get the padID
|
||||
var padId = process.argv[2];
|
||||
|
||||
//initialize the variables
|
||||
// initialize the variables
|
||||
var db, settings, padManager;
|
||||
var npm = require("../src/node_modules/npm");
|
||||
var async = require("../src/node_modules/async");
|
||||
var npm = require('../src/node_modules/npm');
|
||||
var async = require('../src/node_modules/async');
|
||||
|
||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
||||
var Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
||||
|
||||
async.series([
|
||||
//load npm
|
||||
// load npm
|
||||
function(callback) {
|
||||
npm.load({}, function(er) {
|
||||
callback(er);
|
||||
})
|
||||
});
|
||||
},
|
||||
//load modules
|
||||
|
||||
// load modules
|
||||
function(callback) {
|
||||
settings = require('../src/node/utils/Settings');
|
||||
db = require('../src/node/db/DB');
|
||||
|
||||
//initialize the database
|
||||
// initialize the database
|
||||
db.init(callback);
|
||||
},
|
||||
//get the pad
|
||||
function (callback)
|
||||
{
|
||||
|
||||
// get the pad
|
||||
function (callback) {
|
||||
padManager = require('../src/node/db/PadManager');
|
||||
|
||||
padManager.doesPadExists(padId, function(err, exists)
|
||||
{
|
||||
if(!exists)
|
||||
{
|
||||
|
||||
padManager.doesPadExists(padId, function(err, exists) {
|
||||
if (!exists) {
|
||||
console.error("Pad does not exist");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
padManager.getPad(padId, function(err, _pad)
|
||||
{
|
||||
|
||||
padManager.getPad(padId, function(err, _pad) {
|
||||
pad = _pad;
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
},
|
||||
function (callback)
|
||||
{
|
||||
//create an array with key revisions
|
||||
//key revisions always save the full pad atext
|
||||
|
||||
function (callback) {
|
||||
// create an array with key revisions
|
||||
// key revisions always save the full pad atext
|
||||
var head = pad.getHeadRevisionNumber();
|
||||
var keyRevisions = [];
|
||||
for(var i=0;i<head;i+=100)
|
||||
{
|
||||
for (var i = 0; i < head; i += 100) {
|
||||
keyRevisions.push(i);
|
||||
}
|
||||
|
||||
//run trough all key revisions
|
||||
async.forEachSeries(keyRevisions, function(keyRev, callback)
|
||||
{
|
||||
//create an array of revisions we need till the next keyRevision or the End
|
||||
|
||||
// run through all key revisions
|
||||
async.forEachSeries(keyRevisions, function(keyRev, callback) {
|
||||
// create an array of revisions we need till the next keyRevision or the End
|
||||
var revisionsNeeded = [];
|
||||
for(var i=keyRev;i<=keyRev+100 && i<=head; i++)
|
||||
{
|
||||
for(var i = keyRev; i <= keyRev + 100 && i <= head; i++) {
|
||||
revisionsNeeded.push(i);
|
||||
}
|
||||
|
||||
//this array will hold all revision changesets
|
||||
|
||||
// this array will hold all revision changesets
|
||||
var revisions = [];
|
||||
|
||||
//run trough all needed revisions and get them from the database
|
||||
async.forEach(revisionsNeeded, function(revNum, callback)
|
||||
{
|
||||
db.db.get("pad:"+padId+":revs:" + revNum, function(err, revision)
|
||||
{
|
||||
|
||||
// run through all needed revisions and get them from the database
|
||||
async.forEach(revisionsNeeded, function(revNum, callback) {
|
||||
db.db.get("pad:" + padId + ":revs:" + revNum, function(err, revision) {
|
||||
revisions[revNum] = revision;
|
||||
callback(err);
|
||||
});
|
||||
}, function(err)
|
||||
{
|
||||
if(err)
|
||||
{
|
||||
},
|
||||
function(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
//check if the pad has a pool
|
||||
if(pad.pool === undefined )
|
||||
{
|
||||
|
||||
// check if the pad has a pool
|
||||
if (pad.pool === undefined) {
|
||||
console.error("Attribute pool is missing");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
//check if there is an atext in the keyRevisions
|
||||
if(revisions[keyRev] === undefined || revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined)
|
||||
{
|
||||
|
||||
// check if there is an atext in the keyRevisions
|
||||
if (revisions[keyRev] === undefined || revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined) {
|
||||
console.error("No atext in key revision " + keyRev);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var apool = pad.pool;
|
||||
var atext = revisions[keyRev].meta.atext;
|
||||
|
||||
for(var i=keyRev+1;i<=keyRev+100 && i<=head; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
//console.log("check revision " + i);
|
||||
|
||||
for (var i = keyRev + 1; i <= keyRev + 100 && i <= head; i++) {
|
||||
try {
|
||||
// console.log("check revision " + i);
|
||||
var cs = revisions[i].changeset;
|
||||
atext = Changeset.applyToAText(cs, atext, apool);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
} catch(e) {
|
||||
console.error("Bad changeset at revision " + i + " - " + e.message);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
callback();
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
], function (err)
|
||||
{
|
||||
if(err) throw err;
|
||||
else
|
||||
{
|
||||
],
|
||||
function (err) {
|
||||
if(err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log("finished");
|
||||
process.exit(0);
|
||||
}
|
||||
|
|
|
@ -1,63 +1,63 @@
|
|||
/*
|
||||
A tool for deleting pads from the CLI, because sometimes a brick is required to fix a window.
|
||||
*/
|
||||
* A tool for deleting pads from the CLI, because sometimes a brick is required
|
||||
* to fix a window.
|
||||
*/
|
||||
|
||||
if(process.argv.length != 3)
|
||||
{
|
||||
if (process.argv.length != 3) {
|
||||
console.error("Use: node deletePad.js $PADID");
|
||||
process.exit(1);
|
||||
}
|
||||
//get the padID
|
||||
|
||||
// get the padID
|
||||
var padId = process.argv[2];
|
||||
|
||||
var db, padManager, pad, settings;
|
||||
var neededDBValues = ["pad:"+padId];
|
||||
|
||||
var npm = require("../src/node_modules/npm");
|
||||
var async = require("../src/node_modules/async");
|
||||
var npm = require('../src/node_modules/npm');
|
||||
var async = require('../src/node_modules/async');
|
||||
|
||||
async.series([
|
||||
// load npm
|
||||
function(callback) {
|
||||
npm.load({}, function(er) {
|
||||
if(er)
|
||||
{
|
||||
if (er) {
|
||||
console.error("Could not load NPM: " + er)
|
||||
process.exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
// load modules
|
||||
function(callback) {
|
||||
settings = require('../src/node/utils/Settings');
|
||||
db = require('../src/node/db/DB');
|
||||
callback();
|
||||
},
|
||||
|
||||
// initialize the database
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
db.init(callback);
|
||||
},
|
||||
|
||||
// delete the pad and its links
|
||||
function (callback)
|
||||
{
|
||||
function (callback) {
|
||||
padManager = require('../src/node/db/PadManager');
|
||||
|
||||
|
||||
padManager.removePad(padId, function(err){
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
|
||||
callback();
|
||||
}
|
||||
], function (err)
|
||||
{
|
||||
if(err) throw err;
|
||||
else
|
||||
{
|
||||
console.log("Finished deleting padId: "+padId);
|
||||
],
|
||||
function (err) {
|
||||
if(err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log("Finished deleting padId: " + padId);
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,109 +1,97 @@
|
|||
/*
|
||||
This is a debug tool. It helps to extract all datas of a pad and move it from an productive environment and to a develop environment to reproduce bugs there. It outputs a dirtydb file
|
||||
*/
|
||||
* This is a debug tool. It helps to extract all datas of a pad and move it from
|
||||
* a productive environment and to a develop environment to reproduce bugs
|
||||
* there. It outputs a dirtydb file
|
||||
*/
|
||||
|
||||
if(process.argv.length != 3)
|
||||
{
|
||||
if (process.argv.length != 3) {
|
||||
console.error("Use: node extractPadData.js $PADID");
|
||||
process.exit(1);
|
||||
}
|
||||
//get the padID
|
||||
|
||||
// get the padID
|
||||
var padId = process.argv[2];
|
||||
|
||||
var db, dirty, padManager, pad, settings;
|
||||
var neededDBValues = ["pad:"+padId];
|
||||
|
||||
var npm = require("../node_modules/ep_etherpad-lite/node_modules/npm");
|
||||
var async = require("../node_modules/ep_etherpad-lite/node_modules/async");
|
||||
var npm = require('../node_modules/ep_etherpad-lite/node_modules/npm');
|
||||
var async = require('../node_modules/ep_etherpad-lite/node_modules/async');
|
||||
|
||||
async.series([
|
||||
// load npm
|
||||
function(callback) {
|
||||
npm.load({}, function(er) {
|
||||
if(er)
|
||||
{
|
||||
if (er) {
|
||||
console.error("Could not load NPM: " + er)
|
||||
process.exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// load modules
|
||||
function(callback) {
|
||||
settings = require('../node_modules/ep_etherpad-lite/node/utils/Settings');
|
||||
db = require('../node_modules/ep_etherpad-lite/node/db/DB');
|
||||
dirty = require("../node_modules/ep_etherpad-lite/node_modules/ueberDB/node_modules/dirty")(padId + ".db");
|
||||
dirty = require('../node_modules/ep_etherpad-lite/node_modules/ueberDB/node_modules/dirty')(padId + ".db");
|
||||
callback();
|
||||
},
|
||||
//initialize the database
|
||||
function (callback)
|
||||
{
|
||||
|
||||
// initialize the database
|
||||
function (callback) {
|
||||
db.init(callback);
|
||||
},
|
||||
//get the pad
|
||||
function (callback)
|
||||
{
|
||||
|
||||
// get the pad
|
||||
function (callback) {
|
||||
padManager = require('../node_modules/ep_etherpad-lite/node/db/PadManager');
|
||||
|
||||
padManager.getPad(padId, function(err, _pad)
|
||||
{
|
||||
|
||||
padManager.getPad(padId, function(err, _pad) {
|
||||
pad = _pad;
|
||||
callback(err);
|
||||
});
|
||||
},
|
||||
function (callback)
|
||||
{
|
||||
//add all authors
|
||||
var authors = pad.getAllAuthors();
|
||||
for(var i=0;i<authors.length;i++)
|
||||
{
|
||||
neededDBValues.push("globalAuthor:" + authors[i]);
|
||||
}
|
||||
|
||||
//add all revisions
|
||||
var revHead = pad.head;
|
||||
for(var i=0;i<=revHead;i++)
|
||||
{
|
||||
neededDBValues.push("pad:"+padId+":revs:" + i);
|
||||
}
|
||||
|
||||
//get all chat values
|
||||
var chatHead = pad.chatHead;
|
||||
for(var i=0;i<=chatHead;i++)
|
||||
{
|
||||
neededDBValues.push("pad:"+padId+":chat:" + i);
|
||||
}
|
||||
|
||||
//get and set all values
|
||||
async.forEach(neededDBValues, function(dbkey, callback)
|
||||
{
|
||||
db.db.db.wrappedDB.get(dbkey, function(err, dbvalue)
|
||||
{
|
||||
if(err) { callback(err); return}
|
||||
|
||||
if(dbvalue && typeof dbvalue != 'object'){
|
||||
dbvalue=JSON.parse(dbvalue); // if it's not json then parse it as json
|
||||
function (callback) {
|
||||
// add all authors
|
||||
var authors = pad.getAllAuthors();
|
||||
for (var i = 0; i < authors.length; i++) {
|
||||
neededDBValues.push('globalAuthor:' + authors[i]);
|
||||
}
|
||||
|
||||
// add all revisions
|
||||
var revHead = pad.head;
|
||||
for (var i = 0; i <= revHead; i++) {
|
||||
neededDBValues.push('pad:' + padId + ':revs:' + i);
|
||||
}
|
||||
|
||||
// get all chat values
|
||||
var chatHead = pad.chatHead;
|
||||
for (var i = 0; i <= chatHead; i++) {
|
||||
neededDBValues.push('pad:' + padId + ':chat:' + i);
|
||||
}
|
||||
|
||||
// get and set all values
|
||||
async.forEach(neededDBValues, function(dbkey, callback) {
|
||||
db.db.db.wrappedDB.get(dbkey, function(err, dbvalue) {
|
||||
if (err) { callback(err); return}
|
||||
|
||||
if (dbvalue && typeof dbvalue != 'object') {
|
||||
dbvalue = JSON.parse(dbvalue); // if it's not json then parse it as json
|
||||
}
|
||||
|
||||
|
||||
dirty.set(dbkey, dbvalue, callback);
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
], function (err)
|
||||
{
|
||||
if(err) throw err;
|
||||
else
|
||||
{
|
||||
],
|
||||
function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log("finished");
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
|
||||
//get the pad object
|
||||
//get all revisions of this pad
|
||||
//get all authors related to this pad
|
||||
//get the readonly link related to this pad
|
||||
//get the chat entries related to this pad
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue