roku-debug 0.21.22 → 0.21.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/LaunchConfiguration.d.ts +6 -0
- package/dist/adapters/DebugProtocolAdapter.d.ts +2 -1
- package/dist/adapters/DebugProtocolAdapter.js +7 -6
- package/dist/adapters/DebugProtocolAdapter.js.map +1 -1
- package/dist/adapters/TelnetAdapter.d.ts +4 -2
- package/dist/adapters/TelnetAdapter.js +9 -6
- package/dist/adapters/TelnetAdapter.js.map +1 -1
- package/dist/adapters/customVariables/ifDeviceInfo.js +0 -8
- package/dist/adapters/customVariables/ifDeviceInfo.js.map +1 -1
- package/dist/debugSession/BrightScriptDebugSession.d.ts +12 -2
- package/dist/debugSession/BrightScriptDebugSession.js +171 -123
- package/dist/debugSession/BrightScriptDebugSession.js.map +1 -1
- package/package.json +1 -1
- package/roku-debug-0.21.23.tgz +0 -0
- package/roku-debug-0.21.22.tgz +0 -0
|
@@ -49,7 +49,6 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
|
|
|
49
49
|
this.evaluateRefIdLookup = {};
|
|
50
50
|
this.evaluateRefIdCounter = 1;
|
|
51
51
|
this.variables = {};
|
|
52
|
-
this.variableHandles = new debugadapter_1.Handles();
|
|
53
52
|
this.tempVarPrefix = '__rokudebug__';
|
|
54
53
|
/**
|
|
55
54
|
* A magic number to represent a fake thread that will be used for showing compile errors in the UI as if they were runtime crashes
|
|
@@ -258,7 +257,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
|
|
|
258
257
|
* @returns
|
|
259
258
|
*/
|
|
260
259
|
normalizeLaunchConfig(config) {
|
|
261
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
260
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
262
261
|
(_a = config.cwd) !== null && _a !== void 0 ? _a : (config.cwd = process.cwd());
|
|
263
262
|
(_b = config.outDir) !== null && _b !== void 0 ? _b : (config.outDir = (0, FileUtils_1.standardizePath) `${config.cwd}/out`);
|
|
264
263
|
(_c = config.stagingDir) !== null && _c !== void 0 ? _c : (config.stagingDir = (0, FileUtils_1.standardizePath) `${config.outDir}/.roku-deploy-staging`);
|
|
@@ -273,6 +272,11 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
|
|
|
273
272
|
(_m = config.rewriteDevicePathsInLogs) !== null && _m !== void 0 ? _m : (config.rewriteDevicePathsInLogs = true);
|
|
274
273
|
(_o = config.autoResolveVirtualVariables) !== null && _o !== void 0 ? _o : (config.autoResolveVirtualVariables = false);
|
|
275
274
|
(_p = config.enhanceREPLCompletions) !== null && _p !== void 0 ? _p : (config.enhanceREPLCompletions = true);
|
|
275
|
+
// migrate the old `enableVariablesPanel` setting to the new `deferScopeLoading` setting
|
|
276
|
+
if (typeof config.enableVariablesPanel !== 'boolean') {
|
|
277
|
+
config.enableVariablesPanel = true;
|
|
278
|
+
}
|
|
279
|
+
(_q = config.deferScopeLoading) !== null && _q !== void 0 ? _q : (config.deferScopeLoading = config.enableVariablesPanel === false);
|
|
276
280
|
return config;
|
|
277
281
|
}
|
|
278
282
|
async launchRequest(response, config) {
|
|
@@ -990,56 +994,49 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
|
|
|
990
994
|
this.logger.error('Error getting stacktrace', { error, args });
|
|
991
995
|
}
|
|
992
996
|
}
|
|
993
|
-
|
|
997
|
+
scopesRequest(response, args) {
|
|
994
998
|
const logger = this.logger.createLogger(`scopesRequest ${this.idCounter}`);
|
|
995
999
|
logger.info('begin', { args });
|
|
996
1000
|
try {
|
|
997
1001
|
const scopes = new Array();
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
v = this.variables[refId];
|
|
1004
|
-
}
|
|
1005
|
-
else {
|
|
1006
|
-
let result = await this.rokuAdapter.getLocalVariables(args.frameId);
|
|
1007
|
-
if (!result) {
|
|
1008
|
-
throw new Error(`Could not get scopes`);
|
|
1009
|
-
}
|
|
1010
|
-
v = await this.getVariableFromResult(result, args.frameId);
|
|
1011
|
-
//TODO - testing something, remove later
|
|
1012
|
-
// eslint-disable-next-line camelcase
|
|
1013
|
-
v.request_seq = response.request_seq;
|
|
1014
|
-
v.frameId = args.frameId;
|
|
1015
|
-
}
|
|
1016
|
-
scopes.push({
|
|
1017
|
-
name: 'Local',
|
|
1018
|
-
variablesReference: v.variablesReference,
|
|
1019
|
-
expensive: false,
|
|
1020
|
-
presentationHint: 'locals'
|
|
1021
|
-
});
|
|
1002
|
+
let v;
|
|
1003
|
+
// create the locals scope
|
|
1004
|
+
let localsRefId = this.getEvaluateRefId('$$locals', args.frameId);
|
|
1005
|
+
if (this.variables[localsRefId]) {
|
|
1006
|
+
v = this.variables[localsRefId];
|
|
1022
1007
|
}
|
|
1023
1008
|
else {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
name: '
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1009
|
+
v = {
|
|
1010
|
+
variablesReference: localsRefId,
|
|
1011
|
+
name: 'Locals',
|
|
1012
|
+
value: '',
|
|
1013
|
+
type: '$$Locals',
|
|
1014
|
+
frameId: args.frameId,
|
|
1015
|
+
isScope: true,
|
|
1016
|
+
childVariables: []
|
|
1017
|
+
};
|
|
1018
|
+
this.variables[localsRefId] = v;
|
|
1031
1019
|
}
|
|
1032
|
-
|
|
1020
|
+
scopes.push({
|
|
1021
|
+
name: 'Local',
|
|
1022
|
+
variablesReference: v.variablesReference,
|
|
1023
|
+
// Flag the locals scope as expensive if the client asked that it be loaded lazily
|
|
1024
|
+
expensive: this.launchConfiguration.deferScopeLoading,
|
|
1025
|
+
presentationHint: 'locals'
|
|
1026
|
+
});
|
|
1027
|
+
// create the registry scope
|
|
1028
|
+
let registryRefId = this.getEvaluateRefId('$$registry', Infinity);
|
|
1033
1029
|
scopes.push({
|
|
1034
1030
|
name: 'Registry',
|
|
1035
|
-
variablesReference:
|
|
1031
|
+
variablesReference: registryRefId,
|
|
1036
1032
|
expensive: true
|
|
1037
1033
|
});
|
|
1038
|
-
this.variables[
|
|
1039
|
-
variablesReference:
|
|
1034
|
+
this.variables[registryRefId] = {
|
|
1035
|
+
variablesReference: registryRefId,
|
|
1040
1036
|
name: 'Registry',
|
|
1041
1037
|
value: '',
|
|
1042
1038
|
type: '$$Registry',
|
|
1039
|
+
isScope: true,
|
|
1043
1040
|
childVariables: []
|
|
1044
1041
|
};
|
|
1045
1042
|
response.body = {
|
|
@@ -1160,99 +1157,77 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
|
|
|
1160
1157
|
response.message = 'Debug session is not paused';
|
|
1161
1158
|
return this.sendResponse(response);
|
|
1162
1159
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
for (const varName of vars) {
|
|
1170
|
-
let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: varName, frameId: -1 }, util_1.util.getVariablePath(varName));
|
|
1171
|
-
let result = await this.rokuAdapter.getVariable(evalArgs.expression, -1);
|
|
1172
|
-
let tempVar = await this.getVariableFromResult(result, -1);
|
|
1173
|
-
updatedVariables.push(tempVar);
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
else {
|
|
1177
|
-
updatedVariables.push(new debugadapter_1.Variable('variables disabled by launch.json setting', 'enableVariablesPanel: false'));
|
|
1178
|
-
}
|
|
1179
|
-
this.variables[args.variablesReference] = new debugadapter_1.Variable('', '', args.variablesReference, 0, updatedVariables.length);
|
|
1180
|
-
this.variables[args.variablesReference].childVariables = updatedVariables;
|
|
1160
|
+
//find the variable with this reference
|
|
1161
|
+
let v = this.variables[args.variablesReference];
|
|
1162
|
+
if (!v) {
|
|
1163
|
+
response.success = false;
|
|
1164
|
+
response.message = `Variable reference has expired`;
|
|
1165
|
+
return this.sendResponse(response);
|
|
1181
1166
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
if (!v.isResolved) {
|
|
1200
|
-
// Evaluate the variable
|
|
1201
|
-
try {
|
|
1202
|
-
let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: v.evaluateName, frameId: v.frameId }, util_1.util.getVariablePath(v.evaluateName));
|
|
1203
|
-
let result = await this.rokuAdapter.getVariable(evalArgs.expression, v.frameId);
|
|
1204
|
-
tempVar = await this.getVariableFromResult(result, v.frameId);
|
|
1205
|
-
tempVar.frameId = v.frameId;
|
|
1206
|
-
// Determine if the variable has changed
|
|
1207
|
-
sendInvalidatedEvent = v.type !== tempVar.type || v.indexedVariables !== tempVar.indexedVariables;
|
|
1208
|
-
}
|
|
1209
|
-
catch (error) {
|
|
1210
|
-
logger.error('Error getting variables', error);
|
|
1211
|
-
tempVar = new debugadapter_1.Variable('Error', `❌ Error: ${error.message}`);
|
|
1212
|
-
tempVar.type = '';
|
|
1213
|
-
tempVar.childVariables = [];
|
|
1214
|
-
sendInvalidatedEvent = true;
|
|
1215
|
-
response.success = false;
|
|
1216
|
-
response.message = error.message;
|
|
1217
|
-
}
|
|
1218
|
-
// Merge the resulting updates together
|
|
1219
|
-
v.childVariables = tempVar.childVariables;
|
|
1220
|
-
v.value = tempVar.value;
|
|
1221
|
-
v.type = tempVar.type;
|
|
1222
|
-
v.indexedVariables = tempVar.indexedVariables;
|
|
1223
|
-
v.namedVariables = tempVar.namedVariables;
|
|
1167
|
+
logger.log('variable', v);
|
|
1168
|
+
// Populate scope level values if needed
|
|
1169
|
+
if (v.isScope) {
|
|
1170
|
+
await this.populateScopeVariables(v, args);
|
|
1171
|
+
}
|
|
1172
|
+
//query for child vars if we haven't done it yet or DAP is asking to resolve a lazy variable
|
|
1173
|
+
if (v.childVariables.length === 0 || v.isResolved) {
|
|
1174
|
+
let tempVar;
|
|
1175
|
+
if (!v.isResolved) {
|
|
1176
|
+
// Evaluate the variable
|
|
1177
|
+
try {
|
|
1178
|
+
let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: v.evaluateName, frameId: v.frameId }, util_1.util.getVariablePath(v.evaluateName));
|
|
1179
|
+
let result = await this.rokuAdapter.getVariable(evalArgs.expression, v.frameId);
|
|
1180
|
+
tempVar = await this.getVariableFromResult(result, v.frameId);
|
|
1181
|
+
tempVar.frameId = v.frameId;
|
|
1182
|
+
// Determine if the variable has changed
|
|
1183
|
+
sendInvalidatedEvent = v.type !== tempVar.type || v.indexedVariables !== tempVar.indexedVariables;
|
|
1224
1184
|
}
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
}
|
|
1234
|
-
v.isResolved = true;
|
|
1185
|
+
catch (error) {
|
|
1186
|
+
logger.error('Error getting variables', error);
|
|
1187
|
+
tempVar = new debugadapter_1.Variable('Error', `❌ Error: ${error.message}`);
|
|
1188
|
+
tempVar.type = '';
|
|
1189
|
+
tempVar.childVariables = [];
|
|
1190
|
+
sendInvalidatedEvent = true;
|
|
1191
|
+
response.success = false;
|
|
1192
|
+
response.message = error.message;
|
|
1235
1193
|
}
|
|
1236
|
-
|
|
1194
|
+
// Merge the resulting updates together
|
|
1195
|
+
v.childVariables = tempVar.childVariables;
|
|
1196
|
+
v.value = tempVar.value;
|
|
1197
|
+
v.type = tempVar.type;
|
|
1198
|
+
v.indexedVariables = tempVar.indexedVariables;
|
|
1199
|
+
v.namedVariables = tempVar.namedVariables;
|
|
1200
|
+
}
|
|
1201
|
+
frameId = v.frameId;
|
|
1202
|
+
if (((_b = v === null || v === void 0 ? void 0 : v.presentationHint) === null || _b === void 0 ? void 0 : _b.lazy) || v.isResolved) {
|
|
1203
|
+
// If this was a lazy variable we need to respond with the updated variable and not the children
|
|
1204
|
+
if (v.isResolved && v.childVariables.length > 0) {
|
|
1237
1205
|
updatedVariables = v.childVariables;
|
|
1238
1206
|
}
|
|
1239
|
-
// If the variable has no children, set the reference to 0
|
|
1240
|
-
// so it does not look expandable in the Ui
|
|
1241
|
-
if (v.childVariables.length === 0) {
|
|
1242
|
-
v.variablesReference = 0;
|
|
1243
|
-
}
|
|
1244
|
-
// If the variable was resolve in the past we may not have fetched a new temp var
|
|
1245
|
-
tempVar !== null && tempVar !== void 0 ? tempVar : (tempVar = v);
|
|
1246
|
-
if (v === null || v === void 0 ? void 0 : v.presentationHint) {
|
|
1247
|
-
v.presentationHint.lazy = (_c = tempVar.presentationHint) === null || _c === void 0 ? void 0 : _c.lazy;
|
|
1248
|
-
}
|
|
1249
1207
|
else {
|
|
1250
|
-
|
|
1208
|
+
updatedVariables = [v];
|
|
1251
1209
|
}
|
|
1210
|
+
v.isResolved = true;
|
|
1252
1211
|
}
|
|
1253
1212
|
else {
|
|
1254
1213
|
updatedVariables = v.childVariables;
|
|
1255
1214
|
}
|
|
1215
|
+
// If the variable has no children, set the reference to 0
|
|
1216
|
+
// so it does not look expandable in the Ui
|
|
1217
|
+
if (v.childVariables.length === 0) {
|
|
1218
|
+
v.variablesReference = 0;
|
|
1219
|
+
}
|
|
1220
|
+
// If the variable was resolve in the past we may not have fetched a new temp var
|
|
1221
|
+
tempVar !== null && tempVar !== void 0 ? tempVar : (tempVar = v);
|
|
1222
|
+
if (v === null || v === void 0 ? void 0 : v.presentationHint) {
|
|
1223
|
+
v.presentationHint.lazy = (_c = tempVar.presentationHint) === null || _c === void 0 ? void 0 : _c.lazy;
|
|
1224
|
+
}
|
|
1225
|
+
else {
|
|
1226
|
+
v.presentationHint = tempVar.presentationHint;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
else {
|
|
1230
|
+
updatedVariables = v.childVariables;
|
|
1256
1231
|
}
|
|
1257
1232
|
// Only send the updated variables if we are not going to trigger an invalidated event.
|
|
1258
1233
|
// This is to prevent the UI from updating twice and makes the experience much smoother to the end user.
|
|
@@ -1310,6 +1285,79 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
|
|
|
1310
1285
|
}
|
|
1311
1286
|
return filteredUpdatedVariables;
|
|
1312
1287
|
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Takes a scope variable and populates its child variables based on the scope type and the current adapter type.
|
|
1290
|
+
* @param v scope variable to populate
|
|
1291
|
+
* @param args
|
|
1292
|
+
*/
|
|
1293
|
+
async populateScopeVariables(v, args) {
|
|
1294
|
+
if (v.childVariables.length > 0) {
|
|
1295
|
+
// Already populated
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1298
|
+
let tempVar;
|
|
1299
|
+
try {
|
|
1300
|
+
if (v.type === '$$Locals') {
|
|
1301
|
+
if (this.rokuAdapter.isDebugProtocolAdapter()) {
|
|
1302
|
+
let result = await this.rokuAdapter.getLocalVariables(v.frameId);
|
|
1303
|
+
tempVar = await this.getVariableFromResult(result, v.frameId);
|
|
1304
|
+
}
|
|
1305
|
+
else if (this.rokuAdapter.isTelnetAdapter()) {
|
|
1306
|
+
// NOTE: Legacy telnet support
|
|
1307
|
+
let variables = [];
|
|
1308
|
+
const varNames = await this.rokuAdapter.getScopeVariables();
|
|
1309
|
+
// Fetch each variable individually
|
|
1310
|
+
for (const varName of varNames) {
|
|
1311
|
+
let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: varName, frameId: -1 }, util_1.util.getVariablePath(varName));
|
|
1312
|
+
let result = await this.rokuAdapter.getVariable(evalArgs.expression, -1);
|
|
1313
|
+
let tempLocalsVar = await this.getVariableFromResult(result, -1);
|
|
1314
|
+
variables.push(tempLocalsVar);
|
|
1315
|
+
}
|
|
1316
|
+
tempVar = {
|
|
1317
|
+
...v,
|
|
1318
|
+
childVariables: variables,
|
|
1319
|
+
namedVariables: variables.length,
|
|
1320
|
+
indexedVariables: 0
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
// Merge the resulting updates together onto the original variable
|
|
1324
|
+
v.childVariables = tempVar.childVariables;
|
|
1325
|
+
v.namedVariables = tempVar.namedVariables;
|
|
1326
|
+
v.indexedVariables = tempVar.indexedVariables;
|
|
1327
|
+
}
|
|
1328
|
+
else if (v.type === '$$Registry') {
|
|
1329
|
+
// This is a special scope variable used to load registry data via an ECP call
|
|
1330
|
+
// Send the registry ECP call for the `dev` app as side loaded apps are always `dev`
|
|
1331
|
+
await (0, ecpRegistryUtils_1.populateVariableFromRegistryEcp)({ host: this.launchConfiguration.host, remotePort: this.launchConfiguration.remotePort, appId: 'dev' }, v, this.variables, this.getEvaluateRefId.bind(this));
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
catch (error) {
|
|
1335
|
+
logging_1.logger.error(`Error getting variables for scope ${v.type}`, error);
|
|
1336
|
+
tempVar = {
|
|
1337
|
+
name: '',
|
|
1338
|
+
value: `❌ Error: ${error.message}`,
|
|
1339
|
+
variablesReference: 0,
|
|
1340
|
+
childVariables: []
|
|
1341
|
+
};
|
|
1342
|
+
v.childVariables = [tempVar];
|
|
1343
|
+
v.namedVariables = 1;
|
|
1344
|
+
v.indexedVariables = 0;
|
|
1345
|
+
}
|
|
1346
|
+
// Mark the scope as resolved so we don't re-fetch the variables
|
|
1347
|
+
v.isResolved = true;
|
|
1348
|
+
// If the scope has no children, add a single child to indicate there are no values
|
|
1349
|
+
if (v.childVariables.length === 0) {
|
|
1350
|
+
tempVar = {
|
|
1351
|
+
name: '',
|
|
1352
|
+
value: `No values for scope '${v.name}'`,
|
|
1353
|
+
variablesReference: 0,
|
|
1354
|
+
childVariables: []
|
|
1355
|
+
};
|
|
1356
|
+
v.childVariables = [tempVar];
|
|
1357
|
+
v.namedVariables = 1;
|
|
1358
|
+
v.indexedVariables = 0;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1313
1361
|
getNextVarIndex(frameId) {
|
|
1314
1362
|
if (!this.evaluateVarIndexByFrameId.has(frameId)) {
|
|
1315
1363
|
this.evaluateVarIndexByFrameId.set(frameId, 0);
|
|
@@ -1323,7 +1371,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
|
|
|
1323
1371
|
//ensure the rokuAdapter is loaded
|
|
1324
1372
|
await this.getRokuAdapter();
|
|
1325
1373
|
let deferred = (0, util_1.defer)();
|
|
1326
|
-
if (args.context === 'repl' &&
|
|
1374
|
+
if (args.context === 'repl' && this.rokuAdapter.isTelnetAdapter() && args.expression.trim().startsWith('>')) {
|
|
1327
1375
|
this.clearState();
|
|
1328
1376
|
this.rokuAdapter.clearCache();
|
|
1329
1377
|
const expression = args.expression.replace(/^\s*>\s*/, '');
|
|
@@ -1893,7 +1941,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
|
|
|
1893
1941
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
1894
1942
|
let v;
|
|
1895
1943
|
if (result) {
|
|
1896
|
-
if (this.
|
|
1944
|
+
if (this.rokuAdapter.isDebugProtocolAdapter()) {
|
|
1897
1945
|
let refId = this.getEvaluateRefId(result.evaluateName, frameId);
|
|
1898
1946
|
if (result.isCustom && !((_a = result.presentationHint) === null || _a === void 0 ? void 0 : _a.lazy) && result.evaluateNow) {
|
|
1899
1947
|
try {
|
|
@@ -1953,7 +2001,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
|
|
|
1953
2001
|
}
|
|
1954
2002
|
this.variables[refId] = v;
|
|
1955
2003
|
}
|
|
1956
|
-
else {
|
|
2004
|
+
else if (this.rokuAdapter.isTelnetAdapter()) {
|
|
1957
2005
|
if (result.highLevelType === 'primative' || result.highLevelType === 'uninitialized') {
|
|
1958
2006
|
v = new debugadapter_1.Variable(result.name, `${result.value}`);
|
|
1959
2007
|
}
|