@niledatabase/server 3.0.0-alpha.20 → 3.0.0-alpha.21

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.
@@ -9,5 +9,6 @@ declare class NileDatabase {
9
9
  timer: NodeJS.Timeout | undefined;
10
10
  constructor(config: Config, id: string);
11
11
  startTimeout(): void;
12
+ shutdown(): void;
12
13
  }
13
14
  export default NileDatabase;
@@ -426,6 +426,11 @@ var baseLogger = function baseLogger(config) {
426
426
  console.info("[niledb][DEBUG]" + params.join('') + " " + message, meta ? "\n" + JSON.stringify(meta, null, 2) : '');
427
427
  }
428
428
  },
429
+ debug: function debug(message, meta) {
430
+ if (config != null && config.debug) {
431
+ console.debug("[niledb][DEBUG]" + params.join('') + " " + message, meta ? "\n" + JSON.stringify(meta, null, 2) : '');
432
+ }
433
+ },
429
434
  warn: function warn(message, meta) {
430
435
  if (config != null && config.debug) {
431
436
  console.warn(yellow + "[niledb][WARN]" + reset + params.join('') + " " + message, JSON.stringify(meta, null, 2));
@@ -437,18 +442,20 @@ var baseLogger = function baseLogger(config) {
437
442
  };
438
443
  };
439
444
  function Logger(config) {
440
- var _config$logger$info, _config$logger, _config$logger$warn, _config$logger2, _config$logger$error, _config$logger3;
445
+ var _config$logger$info, _config$logger, _config$logger$debug, _config$logger2, _config$logger$warn, _config$logger3, _config$logger$error, _config$logger4;
441
446
  for (var _len2 = arguments.length, params = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
442
447
  params[_key2 - 1] = arguments[_key2];
443
448
  }
444
449
  var base = baseLogger(config, params);
445
450
  var info = (_config$logger$info = config == null || (_config$logger = config.logger) == null ? void 0 : _config$logger.info) != null ? _config$logger$info : base.info;
446
- var warn = (_config$logger$warn = config == null || (_config$logger2 = config.logger) == null ? void 0 : _config$logger2.warn) != null ? _config$logger$warn : base.warn;
447
- var error = (_config$logger$error = config == null || (_config$logger3 = config.logger) == null ? void 0 : _config$logger3.error) != null ? _config$logger$error : base.error;
451
+ var debug = (_config$logger$debug = config == null || (_config$logger2 = config.logger) == null ? void 0 : _config$logger2.debug) != null ? _config$logger$debug : base.debug;
452
+ var warn = (_config$logger$warn = config == null || (_config$logger3 = config.logger) == null ? void 0 : _config$logger3.warn) != null ? _config$logger$warn : base.warn;
453
+ var error = (_config$logger$error = config == null || (_config$logger4 = config.logger) == null ? void 0 : _config$logger4.error) != null ? _config$logger$error : base.error;
448
454
  return {
449
455
  info: info,
450
456
  warn: warn,
451
- error: error
457
+ error: error,
458
+ debug: debug
452
459
  };
453
460
  }
454
461
 
@@ -667,6 +674,7 @@ var Config = /*#__PURE__*/function () {
667
674
  this.databaseName = void 0;
668
675
  this.routePrefix = void 0;
669
676
  this.routes = void 0;
677
+ this.logger = void 0;
670
678
  this.debug = void 0;
671
679
  this.db = void 0;
672
680
  this.api = void 0;
@@ -675,11 +683,11 @@ var Config = /*#__PURE__*/function () {
675
683
  this.configure = /*#__PURE__*/function () {
676
684
  var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(config) {
677
685
  var _config$db, _config$api$cookieKey2, _config$api2;
678
- var _Logger, info, error, envVarConfig, _ref3, host, port, dbConfig, configuredHost, configuredPort, basePath, _config$api$cookieKey, _config$api, cp, databaseName, url, res, database, possibleError, json, message, _database, apiHost, dbHost, name, id, dburl;
686
+ var _Logger, info, error, debug, envVarConfig, _ref3, host, port, dbConfig, configuredHost, configuredPort, basePath, _config$api$cookieKey, _config$api, cp, databaseName, url, res, database, possibleError, json, message, _database, apiHost, dbHost, name, id, dburl;
679
687
  return _regeneratorRuntime().wrap(function _callee$(_context) {
680
688
  while (1) switch (_context.prev = _context.next) {
681
689
  case 0:
682
- _Logger = Logger(config, '[init]'), info = _Logger.info, error = _Logger.error;
690
+ _Logger = Logger(config, '[init]'), info = _Logger.info, error = _Logger.error, debug = _Logger.debug;
683
691
  envVarConfig = {
684
692
  config: config
685
693
  };
@@ -748,7 +756,7 @@ var Config = /*#__PURE__*/function () {
748
756
  } else {
749
757
  database = json;
750
758
  }
751
- _context.next = 36;
759
+ _context.next = 37;
752
760
  break;
753
761
  case 29:
754
762
  _context.prev = 29;
@@ -757,25 +765,26 @@ var Config = /*#__PURE__*/function () {
757
765
  return possibleError.text();
758
766
  case 33:
759
767
  message = _context.sent;
768
+ debug('Unable to auto-configure');
760
769
  error(message);
761
770
  database = {
762
771
  message: message
763
772
  };
764
- case 36:
773
+ case 37:
765
774
  info('[fetched database]', database);
766
775
  if (!('message' in database)) {
767
- _context.next = 45;
776
+ _context.next = 46;
768
777
  break;
769
778
  }
770
779
  if (!('statusCode' in database)) {
771
- _context.next = 44;
780
+ _context.next = 45;
772
781
  break;
773
782
  }
774
783
  error(database);
775
784
  throw new Error('HTTP error has occurred');
776
- case 44:
777
- throw new Error('Unable to auto-configure. Please remove NILEDB_NAME, NILEDB_API_URL, NILEDB_POSTGRES_URL, and/or NILEDB_HOST from your environment variables.');
778
785
  case 45:
786
+ throw new Error('Unable to auto-configure. Please remove NILEDB_NAME, NILEDB_API_URL, NILEDB_POSTGRES_URL, and/or NILEDB_HOST from your environment variables.');
787
+ case 46:
779
788
  if (typeof database === 'object') {
780
789
  _database = database, apiHost = _database.apiHost, dbHost = _database.dbHost, name = _database.name, id = _database.id;
781
790
  basePath = basePath || apiHost;
@@ -784,7 +793,7 @@ var Config = /*#__PURE__*/function () {
784
793
  dburl = new URL(dbHost);
785
794
  configuredHost = dburl.host;
786
795
  }
787
- case 46:
796
+ case 47:
788
797
  _this.api = new ApiConfig({
789
798
  basePath: basePath,
790
799
  cookieKey: (_config$api$cookieKey2 = config == null || (_config$api2 = config.api) == null ? void 0 : _config$api2.cookieKey) != null ? _config$api$cookieKey2 : 'token',
@@ -804,7 +813,7 @@ var Config = /*#__PURE__*/function () {
804
813
  api: _this.api
805
814
  });
806
815
  return _context.abrupt("return", _this);
807
- case 50:
816
+ case 51:
808
817
  case "end":
809
818
  return _context.stop();
810
819
  }
@@ -819,6 +828,7 @@ var Config = /*#__PURE__*/function () {
819
828
  logger: logger
820
829
  };
821
830
  this.user = getUsername(_envVarConfig);
831
+ this.logger = _config == null ? void 0 : _config.logger;
822
832
  this.password = getPassword(_envVarConfig);
823
833
  {
824
834
  if (!this.user) {
@@ -990,7 +1000,8 @@ var NileDatabase = /*#__PURE__*/function () {
990
1000
  this.timer = void 0;
991
1001
  var _Logger = Logger(config, '[NileInstance]'),
992
1002
  warn = _Logger.warn,
993
- info = _Logger.info;
1003
+ info = _Logger.info,
1004
+ debug = _Logger.debug;
994
1005
  this.id = id;
995
1006
  var poolConfig = _extends({
996
1007
  min: 0,
@@ -1001,7 +1012,7 @@ var NileDatabase = /*#__PURE__*/function () {
1001
1012
  remaining = _objectWithoutPropertiesLoose(poolConfig, _excluded$1);
1002
1013
  config.db = poolConfig;
1003
1014
  this.config = config;
1004
- info(JSON.stringify(this.config.db));
1015
+ debug(JSON.stringify(this.config.db));
1005
1016
  this.pool = createProxyForPool(new pg.Pool(remaining), this.config);
1006
1017
  if (typeof afterCreate === 'function') {
1007
1018
  warn('Providing an pool configuration will stop automatic tenant context setting.');
@@ -1014,12 +1025,14 @@ var NileDatabase = /*#__PURE__*/function () {
1014
1025
  return _regeneratorRuntime().wrap(function _callee$(_context) {
1015
1026
  while (1) switch (_context.prev = _context.next) {
1016
1027
  case 0:
1017
- info('pool connected');
1018
- afterCreate = makeAfterCreate(config);
1028
+ debug('pool connected');
1029
+ _this.startTimeout();
1030
+ afterCreate = makeAfterCreate(config, _this.id + "-" + _this.timer);
1019
1031
  afterCreate(client, function (err) {
1020
1032
  var _Logger2 = Logger(config, '[after create callback]'),
1021
1033
  error = _Logger2.error;
1022
1034
  if (err) {
1035
+ clearTimeout(_this.timer);
1023
1036
  error('after create failed', {
1024
1037
  message: err.message,
1025
1038
  stack: err.stack
@@ -1027,7 +1040,6 @@ var NileDatabase = /*#__PURE__*/function () {
1027
1040
  evictPool(_this.id);
1028
1041
  }
1029
1042
  });
1030
- _this.startTimeout();
1031
1043
  case 4:
1032
1044
  case "end":
1033
1045
  return _context.stop();
@@ -1038,62 +1050,57 @@ var NileDatabase = /*#__PURE__*/function () {
1038
1050
  return _ref.apply(this, arguments);
1039
1051
  };
1040
1052
  }());
1041
- this.pool.on('error', /*#__PURE__*/function () {
1042
- var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee2(err) {
1043
- return _regeneratorRuntime().wrap(function _callee2$(_context2) {
1044
- while (1) switch (_context2.prev = _context2.next) {
1045
- case 0:
1046
- info('pool failed', {
1047
- message: err.message,
1048
- stack: err.stack
1049
- });
1050
- if (_this.timer) {
1051
- clearTimeout(_this.timer);
1052
- }
1053
- evictPool(_this.id);
1054
- case 3:
1055
- case "end":
1056
- return _context2.stop();
1057
- }
1058
- }, _callee2);
1059
- }));
1060
- return function (_x2) {
1061
- return _ref2.apply(this, arguments);
1062
- };
1063
- }());
1053
+ this.pool.on('error', function (err) {
1054
+ clearTimeout(_this.timer);
1055
+ info("pool " + _this.id + " failed", {
1056
+ message: err.message,
1057
+ stack: err.stack
1058
+ });
1059
+ evictPool(_this.id);
1060
+ });
1064
1061
  }
1065
1062
  var _proto = NileDatabase.prototype;
1066
1063
  _proto.startTimeout = function startTimeout() {
1067
1064
  var _this2 = this,
1068
1065
  _Number2;
1069
1066
  var _Logger3 = Logger(this.config, '[NileInstance]'),
1070
- info = _Logger3.info;
1067
+ debug = _Logger3.debug;
1071
1068
  if (this.timer) {
1072
1069
  clearTimeout(this.timer);
1073
1070
  }
1074
1071
  this.timer = setTimeout(function () {
1075
1072
  var _Number;
1076
- info("Pool reached idleTimeoutMillis. " + _this2.id + " evicted after " + ((_Number = Number(_this2.config.db.idleTimeoutMillis)) != null ? _Number : 30000) + "ms");
1073
+ debug("Pool reached idleTimeoutMillis. " + _this2.id + " evicted after " + ((_Number = Number(_this2.config.db.idleTimeoutMillis)) != null ? _Number : 30000) + "ms");
1077
1074
  _this2.pool.end(function () {
1075
+ clearTimeout(_this2.timer);
1078
1076
  evictPool(_this2.id);
1079
- info("Pool end called for " + _this2.id);
1080
- // something odd going on here. Without the callback, pool.end() is flakey
1081
1077
  });
1082
1078
  }, (_Number2 = Number(this.config.db.idleTimeoutMillis)) != null ? _Number2 : 30000);
1083
1079
  };
1080
+ _proto.shutdown = function shutdown() {
1081
+ var _this3 = this;
1082
+ var _Logger4 = Logger(this.config, '[NileInstance]'),
1083
+ debug = _Logger4.debug;
1084
+ debug("attempting to shut down " + this.id);
1085
+ clearTimeout(this.timer);
1086
+ this.pool.end(function () {
1087
+ debug(_this3.id + " has been shut down");
1088
+ });
1089
+ };
1084
1090
  return NileDatabase;
1085
1091
  }();
1086
- function makeAfterCreate(config) {
1087
- var _Logger4 = Logger(config, '[afterCreate]'),
1088
- warn = _Logger4.warn,
1089
- info = _Logger4.info;
1092
+ function makeAfterCreate(config, id) {
1093
+ var _Logger5 = Logger(config, '[afterCreate]'),
1094
+ error = _Logger5.error,
1095
+ warn = _Logger5.warn,
1096
+ debug = _Logger5.debug;
1090
1097
  return function (conn, done) {
1091
- conn.on('error', function errorHandler(error) {
1092
- warn('Connection was terminated by server', {
1093
- message: error.message,
1094
- stack: error.stack
1098
+ conn.on('error', function errorHandler(e) {
1099
+ error("Connection " + id + " was terminated by server", {
1100
+ message: e.message,
1101
+ stack: e.stack
1095
1102
  });
1096
- done(error, conn);
1103
+ done(e, conn);
1097
1104
  });
1098
1105
  if (config.tenantId) {
1099
1106
  var query = ["SET nile.tenant_id = '" + config.tenantId + "'"];
@@ -1106,10 +1113,19 @@ function makeAfterCreate(config) {
1106
1113
  // in this example we use pg driver's connection API
1107
1114
  conn.query(query.join(';'), function (err) {
1108
1115
  if (query.length === 1) {
1109
- info("[tenant id] " + config.tenantId);
1116
+ debug("connection context set: tenantId=" + config.tenantId);
1110
1117
  }
1111
1118
  if (query.length === 2) {
1112
- info("[user id] " + config.userId);
1119
+ debug("connection context set: tenantId=" + config.tenantId + " userId=" + config.userId);
1120
+ }
1121
+ if (err) {
1122
+ error('query connection failed', {
1123
+ cause: err.cause,
1124
+ stack: err.stack,
1125
+ message: err.message,
1126
+ name: err.name,
1127
+ id: id
1128
+ });
1113
1129
  }
1114
1130
  done(err, conn);
1115
1131
  });
@@ -1131,6 +1147,8 @@ var DBManager = /*#__PURE__*/function () {
1131
1147
  warn = _Logger.warn;
1132
1148
  if (id && _this.connections.has(id)) {
1133
1149
  info("Removing " + id + " from db connection pool.");
1150
+ var connection = _this.connections.get(id);
1151
+ connection == null || connection.shutdown();
1134
1152
  _this.connections["delete"](id);
1135
1153
  } else {
1136
1154
  warn("missed eviction of " + id);
@@ -3239,7 +3257,7 @@ var appRoutes = function appRoutes(prefix) {
3239
3257
  };
3240
3258
 
3241
3259
  // url host does not matter, we only match on the 1st leg by path
3242
- var ORIGIN = 'http://localhost';
3260
+ var ORIGIN = 'https://us-west-2.api.dev.thenile.dev';
3243
3261
  /**
3244
3262
  * a helper function to log in server side.
3245
3263
  */
@@ -3251,7 +3269,7 @@ function serverAuth(config, handlers) {
3251
3269
  return /*#__PURE__*/function () {
3252
3270
  var _login = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref) {
3253
3271
  var _providers, _exec;
3254
- var email, password, sessionUrl, sessionReq, sessionRes, providers, csrf, csrfReq, csrfRes, csrfToken, _yield$csrfRes$json, json, _ref2, credentials, csrfCookie, signInUrl, postReq, loginRes, authCookie, _ref3, token;
3272
+ var email, password, sessionUrl, baseHeaders, sessionReq, sessionRes, providers, csrf, csrfReq, csrfRes, csrfToken, _yield$csrfRes$json, json, _ref2, credentials, csrfCookie, signInUrl, postReq, loginRes, authCookie, _ref3, token;
3255
3273
  return _regeneratorRuntime().wrap(function _callee$(_context) {
3256
3274
  while (1) switch (_context.prev = _context.next) {
3257
3275
  case 0:
@@ -3262,102 +3280,101 @@ function serverAuth(config, handlers) {
3262
3280
  }
3263
3281
  throw new Error('Server side login requires a user email and password.');
3264
3282
  case 3:
3265
- info("Obtaining providers for " + email);
3266
3283
  sessionUrl = new URL("" + ORIGIN + routes.PROVIDERS);
3267
- sessionReq = new Request(sessionUrl, {
3268
- method: 'GET',
3269
- headers: new Headers({
3270
- host: sessionUrl.host
3271
- })
3272
- });
3273
- _context.next = 8;
3284
+ baseHeaders = {
3285
+ host: sessionUrl.host,
3286
+ 'niledb-origin': ORIGIN
3287
+ };
3288
+ info("Obtaining providers for " + email);
3289
+ sessionReq = new Request(sessionUrl, _extends({
3290
+ method: 'GET'
3291
+ }, baseHeaders));
3292
+ _context.next = 9;
3274
3293
  return handlers.POST(sessionReq);
3275
- case 8:
3294
+ case 9:
3276
3295
  sessionRes = _context.sent;
3277
3296
  if (!((sessionRes == null ? void 0 : sessionRes.status) === 404)) {
3278
- _context.next = 11;
3297
+ _context.next = 12;
3279
3298
  break;
3280
3299
  }
3281
3300
  throw new Error('Unable to login, cannot find region api.');
3282
- case 11:
3283
- _context.prev = 11;
3284
- _context.next = 14;
3301
+ case 12:
3302
+ _context.prev = 12;
3303
+ _context.next = 15;
3285
3304
  return sessionRes == null ? void 0 : sessionRes.json();
3286
- case 14:
3305
+ case 15:
3287
3306
  providers = _context.sent;
3288
- _context.next = 21;
3307
+ _context.next = 22;
3289
3308
  break;
3290
- case 17:
3291
- _context.prev = 17;
3292
- _context.t0 = _context["catch"](11);
3309
+ case 18:
3310
+ _context.prev = 18;
3311
+ _context.t0 = _context["catch"](12);
3293
3312
  info(sessionUrl, {
3294
3313
  sessionRes: sessionRes
3295
3314
  });
3296
3315
  error(_context.t0);
3297
- case 21:
3316
+ case 22:
3298
3317
  info('Obtaining csrf');
3299
3318
  csrf = new URL("" + ORIGIN + routes.CSRF);
3300
3319
  csrfReq = new Request(csrf, {
3301
3320
  method: 'GET',
3302
- headers: new Headers({
3303
- host: sessionUrl.host
3304
- })
3321
+ headers: new Headers(_extends({}, baseHeaders))
3305
3322
  });
3306
- _context.next = 26;
3323
+ _context.next = 27;
3307
3324
  return handlers.POST(csrfReq);
3308
- case 26:
3325
+ case 27:
3309
3326
  csrfRes = _context.sent;
3310
- _context.prev = 27;
3311
- _context.next = 30;
3327
+ _context.prev = 28;
3328
+ _context.next = 31;
3312
3329
  return csrfRes == null ? void 0 : csrfRes.json();
3313
- case 30:
3330
+ case 31:
3314
3331
  _context.t1 = _yield$csrfRes$json = _context.sent;
3315
3332
  if (!(_context.t1 != null)) {
3316
- _context.next = 35;
3333
+ _context.next = 36;
3317
3334
  break;
3318
3335
  }
3319
3336
  _context.t2 = _yield$csrfRes$json;
3320
- _context.next = 36;
3337
+ _context.next = 37;
3321
3338
  break;
3322
- case 35:
3323
- _context.t2 = {};
3324
3339
  case 36:
3340
+ _context.t2 = {};
3341
+ case 37:
3325
3342
  json = _context.t2;
3326
3343
  csrfToken = json == null ? void 0 : json.csrfToken;
3327
- _context.next = 44;
3344
+ _context.next = 45;
3328
3345
  break;
3329
- case 40:
3330
- _context.prev = 40;
3331
- _context.t3 = _context["catch"](27);
3346
+ case 41:
3347
+ _context.prev = 41;
3348
+ _context.t3 = _context["catch"](28);
3332
3349
  info(sessionUrl, {
3333
3350
  csrfRes: csrfRes
3334
3351
  });
3335
3352
  error(_context.t3, {
3336
3353
  csrfRes: csrfRes
3337
3354
  });
3338
- case 44:
3355
+ case 45:
3339
3356
  _ref2 = (_providers = providers) != null ? _providers : {}, credentials = _ref2.credentials;
3340
3357
  csrfCookie = csrfRes == null ? void 0 : csrfRes.headers.get('set-cookie');
3341
3358
  if (credentials) {
3342
- _context.next = 48;
3359
+ _context.next = 49;
3343
3360
  break;
3344
3361
  }
3345
3362
  throw new Error('Unable to obtain credential provider. Aborting server side login.');
3346
- case 48:
3363
+ case 49:
3347
3364
  signInUrl = new URL(credentials.callbackUrl);
3348
3365
  if (csrfCookie) {
3349
- _context.next = 51;
3366
+ _context.next = 52;
3350
3367
  break;
3351
3368
  }
3352
3369
  throw new Error('Unable to authenticate REST');
3353
- case 51:
3370
+ case 52:
3354
3371
  info("Attempting sign in with email " + email);
3355
3372
  postReq = new Request(signInUrl, {
3356
3373
  method: 'POST',
3357
- headers: new Headers({
3374
+ headers: new Headers(_extends({
3358
3375
  'content-type': 'application/json',
3359
3376
  cookie: csrfCookie
3360
- }),
3377
+ }, baseHeaders)),
3361
3378
  body: JSON.stringify({
3362
3379
  email: email,
3363
3380
  password: password,
@@ -3365,36 +3382,36 @@ function serverAuth(config, handlers) {
3365
3382
  callbackUrl: credentials.callbackUrl
3366
3383
  })
3367
3384
  });
3368
- _context.next = 55;
3385
+ _context.next = 56;
3369
3386
  return handlers.POST(postReq);
3370
- case 55:
3387
+ case 56:
3371
3388
  loginRes = _context.sent;
3372
3389
  authCookie = loginRes == null ? void 0 : loginRes.headers.get('set-cookie');
3373
3390
  if (authCookie) {
3374
- _context.next = 59;
3391
+ _context.next = 60;
3375
3392
  break;
3376
3393
  }
3377
3394
  throw new Error('authentication failed');
3378
- case 59:
3379
- _ref3 = (_exec = /(nile\.session-token=.+?);/.exec(authCookie)) != null ? _exec : [], token = _ref3[1];
3395
+ case 60:
3396
+ _ref3 = (_exec = /((__Secure-)?nile\.session-token=.+?);/.exec(authCookie)) != null ? _exec : [], token = _ref3[1];
3380
3397
  if (token) {
3381
- _context.next = 62;
3398
+ _context.next = 63;
3382
3399
  break;
3383
3400
  }
3384
3401
  throw new Error('Server login failed');
3385
- case 62:
3402
+ case 63:
3386
3403
  info('Server login successful', {
3387
3404
  authCookie: authCookie,
3388
3405
  csrfCookie: csrfCookie
3389
3406
  });
3390
- return _context.abrupt("return", new Headers({
3407
+ return _context.abrupt("return", new Headers(_extends({
3391
3408
  cookie: [token, csrfCookie].join('; ')
3392
- }));
3393
- case 64:
3409
+ }, baseHeaders)));
3410
+ case 65:
3394
3411
  case "end":
3395
3412
  return _context.stop();
3396
3413
  }
3397
- }, _callee, null, [[11, 17], [27, 40]]);
3414
+ }, _callee, null, [[12, 18], [28, 41]]);
3398
3415
  }));
3399
3416
  function login(_x) {
3400
3417
  return _login.apply(this, arguments);