unleash-client
Advanced tools
Comparing version 3.5.0 to 3.6.0
# Changelog | ||
# 3.6.0 | ||
- feat: flexible rollout - custom stickiness (#201) | ||
- fix: add another test-script | ||
- fix: add test for variants validation | ||
- fix: Keep fetching if customHeadersFunction fails. (#210) | ||
- fix: emit warn if initialize is called multiple times | ||
- fix tests for node 10 | ||
- fix: add meta to test-script | ||
# 3.5.0 | ||
@@ -4,0 +14,0 @@ |
@@ -15,2 +15,4 @@ const { initialize, isEnabled, getFeatureToggleDefinitions } = require('../lib'); | ||
client.on('warn', console.log); | ||
client.on('unchanged', () => console.error('NOT CHANGED')); | ||
client.on('changed', () => console.log('changed')); | ||
@@ -17,0 +19,0 @@ console.log('Fetching toggles from: https://unleash.herokuapp.com'); |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -9,0 +9,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
{ "name": "unleash-client-node", "version": "3.5.0", "sdkVersion": "unleash-client-node:3.5.0" } | ||
{ "name": "unleash-client-node", "version": "3.6.0", "sdkVersion": "unleash-client-node:3.6.0" } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.resolveContextValue = exports.createFallbackFunction = void 0; | ||
function createFallbackFunction(name, context, fallback) { | ||
@@ -5,0 +4,0 @@ if (typeof fallback === 'function') { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.countVariant = exports.count = exports.getVariant = exports.getFeatureToggleDefinitions = exports.getFeatureToggleDefinition = exports.destroy = exports.isEnabled = exports.initialize = exports.Unleash = exports.Strategy = void 0; | ||
var unleash_1 = require("./unleash"); | ||
Object.defineProperty(exports, "Unleash", { enumerable: true, get: function () { return unleash_1.Unleash; } }); | ||
exports.Unleash = unleash_1.Unleash; | ||
var variant_1 = require("./variant"); | ||
var index_1 = require("./strategy/index"); | ||
Object.defineProperty(exports, "Strategy", { enumerable: true, get: function () { return index_1.Strategy; } }); | ||
exports.Strategy = index_1.Strategy; | ||
var instance; | ||
function initialize(options) { | ||
if (instance) { | ||
instance.emit('warn', 'This global unleash instance is initialized multiple times.'); | ||
} | ||
instance = new unleash_1.Unleash(options); | ||
@@ -12,0 +14,0 @@ instance.on('error', function () { }); |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -9,0 +9,0 @@ }; |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -111,16 +111,16 @@ }; | ||
} | ||
_b.label = 1; | ||
case 1: | ||
_b.trys.push([1, 11, 12, 13]); | ||
url = url_1.resolve(this.url, './client/features'); | ||
if (!this.customHeadersFunction) return [3 /*break*/, 2]; | ||
if (!this.customHeadersFunction) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, this.customHeadersFunction()]; | ||
case 1: | ||
case 2: | ||
_a = _b.sent(); | ||
return [3 /*break*/, 3]; | ||
case 2: | ||
return [3 /*break*/, 4]; | ||
case 3: | ||
_a = this.headers; | ||
_b.label = 3; | ||
case 3: | ||
headers = _a; | ||
_b.label = 4; | ||
case 4: | ||
_b.trys.push([4, 11, , 12]); | ||
headers = _a; | ||
return [4 /*yield*/, request_1.get({ | ||
@@ -136,3 +136,2 @@ url: url, | ||
res = _b.sent(); | ||
this.timedFetch(); | ||
if (!(res.status === 304)) return [3 /*break*/, 6]; | ||
@@ -168,9 +167,11 @@ // No new data | ||
return [3 /*break*/, 10]; | ||
case 10: return [3 /*break*/, 12]; | ||
case 10: return [3 /*break*/, 13]; | ||
case 11: | ||
err_2 = _b.sent(); | ||
this.emit('error', err_2); | ||
return [3 /*break*/, 13]; | ||
case 12: | ||
this.timedFetch(); | ||
return [3 /*break*/, 12]; | ||
case 12: return [2 /*return*/]; | ||
return [7 /*endfinally*/]; | ||
case 13: return [2 /*return*/]; | ||
} | ||
@@ -177,0 +178,0 @@ }); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.get = exports.post = exports.getAgent = void 0; | ||
var node_fetch_1 = require("node-fetch"); | ||
@@ -17,5 +16,4 @@ var http = require("http"); | ||
}); | ||
var getAgent = function (url) { return (url.protocol === 'https:' ? httpsAgent : httpAgent); }; | ||
exports.getAgent = getAgent; | ||
var post = function (_a) { | ||
exports.getAgent = function (url) { return (url.protocol === 'https:' ? httpsAgent : httpAgent); }; | ||
exports.post = function (_a) { | ||
var url = _a.url, appName = _a.appName, timeout = _a.timeout, instanceId = _a.instanceId, headers = _a.headers, json = _a.json; | ||
@@ -35,4 +33,3 @@ return node_fetch_1.default(url, { | ||
}; | ||
exports.post = post; | ||
var get = function (_a) { | ||
exports.get = function (_a) { | ||
var url = _a.url, etag = _a.etag, appName = _a.appName, timeout = _a.timeout, instanceId = _a.instanceId, headers = _a.headers; | ||
@@ -54,3 +51,2 @@ var optHeaders = Object.assign({ | ||
}; | ||
exports.get = get; | ||
//# sourceMappingURL=request.js.map |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,3 +17,2 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Storage = void 0; | ||
var events_1 = require("events"); | ||
@@ -20,0 +19,0 @@ var path_1 = require("path"); |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,3 +17,2 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ApplicationHostnameStrategy = void 0; | ||
var strategy_1 = require("./strategy"); | ||
@@ -20,0 +19,0 @@ var os_1 = require("os"); |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,3 +17,2 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.DefaultStrategy = void 0; | ||
var strategy_1 = require("./strategy"); | ||
@@ -20,0 +19,0 @@ var DefaultStrategy = /** @class */ (function (_super) { |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,9 +17,7 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.FlexibleRolloutStrategy = void 0; | ||
var strategy_1 = require("./strategy"); | ||
var util_1 = require("./util"); | ||
var helpers_1 = require("../helpers"); | ||
var STICKINESS = { | ||
default: 'default', | ||
userId: 'userId', | ||
sessionId: 'sessionId', | ||
random: 'random', | ||
@@ -39,10 +37,8 @@ }; | ||
switch (stickiness) { | ||
case STICKINESS.userId: | ||
return context.userId; | ||
case STICKINESS.sessionId: | ||
return context.sessionId; | ||
case STICKINESS.default: | ||
return context.userId || context.sessionId || this.randomGenerator(); | ||
case STICKINESS.random: | ||
return this.randomGenerator(); | ||
default: | ||
return context.userId || context.sessionId || this.randomGenerator(); | ||
return helpers_1.resolveContextValue(context, stickiness); | ||
} | ||
@@ -49,0 +45,0 @@ }; |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,3 +17,2 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.GradualRolloutRandomStrategy = void 0; | ||
var strategy_1 = require("./strategy"); | ||
@@ -20,0 +19,0 @@ var GradualRolloutRandomStrategy = /** @class */ (function (_super) { |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,3 +17,2 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.GradualRolloutSessionIdStrategy = void 0; | ||
var strategy_1 = require("./strategy"); | ||
@@ -20,0 +19,0 @@ var util_1 = require("./util"); |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,3 +17,2 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.GradualRolloutUserIdStrategy = void 0; | ||
var strategy_1 = require("./strategy"); | ||
@@ -20,0 +19,0 @@ var util_1 = require("./util"); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.defaultStrategies = exports.Strategy = void 0; | ||
var default_strategy_1 = require("./default-strategy"); | ||
@@ -13,3 +12,3 @@ var application_hostname_strategy_1 = require("./application-hostname-strategy"); | ||
var strategy_1 = require("./strategy"); | ||
Object.defineProperty(exports, "Strategy", { enumerable: true, get: function () { return strategy_1.Strategy; } }); | ||
exports.Strategy = strategy_1.Strategy; | ||
exports.defaultStrategies = [ | ||
@@ -16,0 +15,0 @@ new default_strategy_1.DefaultStrategy(), |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,3 +17,2 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.RemoteAddressStrategy = void 0; | ||
var strategy_1 = require("./strategy"); | ||
@@ -20,0 +19,0 @@ var ip = require('ip'); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Operator = exports.Strategy = void 0; | ||
var helpers_1 = require("../helpers"); | ||
@@ -5,0 +4,0 @@ var Strategy = /** @class */ (function () { |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,3 +17,2 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.UserWithIdStrategy = void 0; | ||
var strategy_1 = require("./strategy"); | ||
@@ -20,0 +19,0 @@ var UserWithIdStrategy = /** @class */ (function (_super) { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.normalizedValue = void 0; | ||
var murmurHash3 = require("murmurhash3js"); | ||
@@ -5,0 +4,0 @@ function normalizedValue(id, groupId, normalizer) { |
@@ -6,3 +6,3 @@ "use strict"; | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
@@ -17,3 +17,2 @@ }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Unleash = exports.Strategy = void 0; | ||
var client_1 = require("./client"); | ||
@@ -23,3 +22,3 @@ var repository_1 = require("./repository"); | ||
var strategy_1 = require("./strategy"); | ||
Object.defineProperty(exports, "Strategy", { enumerable: true, get: function () { return strategy_1.Strategy; } }); | ||
exports.Strategy = strategy_1.Strategy; | ||
var os_1 = require("os"); | ||
@@ -26,0 +25,0 @@ var events_1 = require("events"); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.selectVariant = exports.getDefaultVariant = void 0; | ||
var util_1 = require("./strategy/util"); | ||
@@ -5,0 +4,0 @@ var helpers_1 = require("./helpers"); |
{ | ||
"name": "unleash-client", | ||
"version": "3.5.0", | ||
"version": "3.6.0", | ||
"description": "Unleash Client for Node", | ||
@@ -44,9 +44,9 @@ "license": "Apache-2.0", | ||
"devDependencies": { | ||
"@ava/babel": "^1.0.1", | ||
"@types/ip": "^1.1.0", | ||
"@types/murmurhash3js": "^3.0.2", | ||
"@types/nock": "^11.1.0", | ||
"@types/node": "^14.0.1", | ||
"@types/node-fetch": "^2.5.8", | ||
"@unleash/client-specification": "^3.3.1", | ||
"ava": "^2.2.0", | ||
"ava": "^3.15.0", | ||
"coveralls": "^3.0.3", | ||
@@ -60,3 +60,3 @@ "cross-env": "^7.0.0", | ||
"mkdirp": "^1.0.4", | ||
"nock": "^12.0.0", | ||
"nock": "^13.0.7", | ||
"nyc": "^15.1.0", | ||
@@ -95,10 +95,4 @@ "prettier": "^1.17.1", | ||
"lint-staged": { | ||
"*.js": [ | ||
"eslint --fix", | ||
"git add" | ||
], | ||
"*.{ts,md,json}": [ | ||
"prettier --write", | ||
"git add" | ||
] | ||
"*.js": "eslint --fix", | ||
"*.{ts,md,json}": "prettier --write" | ||
}, | ||
@@ -111,7 +105,4 @@ "husky": { | ||
"ava": { | ||
"helpers": [ | ||
"**/helpers/**/*", | ||
"**/fixtures/**/*" | ||
] | ||
"babel": true | ||
} | ||
} |
@@ -5,3 +5,2 @@ # Unleash Client SDK for Node.js | ||
![npm](https://img.shields.io/npm/dm/unleash-client) | ||
[![Greenkeeper badge](https://badges.greenkeeper.io/Unleash/unleash-client-node.svg)](https://greenkeeper.io/) | ||
[![Build Status](https://github.com/Unleash/unleash-client-node/workflows/Build/badge.svg)](https://github.com/Unleash/unleash-client-node/actions) | ||
@@ -31,3 +30,3 @@ [![Code Climate](https://codeclimate.com/github/Unleash/unleash-client-node/badges/gpa.svg)](https://codeclimate.com/github/Unleash/unleash-client-node) | ||
const { initialize } = require('unleash-client'); | ||
const instance = initialize({ | ||
const unleash = initialize({ | ||
url: 'http://unleash.herokuapp.com/api/', | ||
@@ -39,12 +38,16 @@ appName: 'my-app-name', | ||
// optional events | ||
instance.on('error', console.error); | ||
instance.on('warn', console.warn); | ||
instance.on('ready', console.log); | ||
unleash.on('error', console.error); | ||
unleash.on('warn', console.warn); | ||
unleash.on('ready', console.log); | ||
// metrics hooks | ||
instance.on('registered', clientData => console.log('registered', clientData)); | ||
instance.on('sent', payload => console.log('metrics bucket/payload sent', payload)); | ||
instance.on('count', (name, enabled) => console.log(`isEnabled(${name}) returned ${enabled}`)); | ||
unleash.on('registered', clientData => console.log('registered', clientData)); | ||
unleash.on('sent', payload => console.log('metrics bucket/payload sent', payload)); | ||
unleash.on('count', (name, enabled) => console.log(`isEnabled(${name}) returned ${enabled}`)); | ||
``` | ||
Be aware that the `initialize` function will configure a global Unleash instance. If you call this | ||
method multiple times the global instance will be changed. If you prefer to handle the instance | ||
yourself you should [construct your own Unleash instance](#alternative-usage). | ||
### 3. Use unleash | ||
@@ -87,2 +90,3 @@ | ||
- UserIdStrategy | ||
- FlexibleRolloutStrategy | ||
- GradualRolloutUserIdStrategy | ||
@@ -165,3 +169,3 @@ - GradualRolloutSessionIdStrategy | ||
const instance = new Unleash({ | ||
const unleash = new Unleash({ | ||
appName: 'my-app-name', | ||
@@ -171,5 +175,5 @@ url: 'http://unleash.herokuapp.com', | ||
instance.on('ready', console.log.bind(console, 'ready')); | ||
// required error handling when using instance directly | ||
instance.on('error', console.error); | ||
unleash.on('ready', console.log.bind(console, 'ready')); | ||
// required error handling when using unleash directly | ||
unleash.on('error', console.error); | ||
``` | ||
@@ -181,12 +185,12 @@ | ||
| event | payload | description | | ||
| ---------- | -------------------------------- | ------------------------------------------------------------------------------------------- | | ||
| ready | - | is emitted once the fs-cache is ready. if no cache file exists it will still be emitted. | | ||
| registered | - | is emitted after the app has been registered at the api server | | ||
| sent | `object` data | key/value pair of delivered metrics | | ||
| count | `string` name, `boolean` enabled | is emitted when a feature is evaluated | | ||
| warn | `string` msg | is emitted on a warning | | ||
| error | `Error` err | is emitted on a error | | ||
| unchanged | - | is emitted each time the client gets new toggle state from server, but nothing has changed | | ||
| changed | `object` data | is emitted each time the client gets new toggle state from server and changes has been made | | ||
| event | payload | description | | ||
| ---------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| ready | - | is emitted once the fs-cache is ready. if no cache file exists it will still be emitted. The client is ready to use, but might not have synchronized with the Unleash API yet. This means the SDK still can operate on stale configurations. | | ||
| registered | - | is emitted after the app has been registered at the api server | | ||
| sent | `object` data | key/value pair of delivered metrics | | ||
| count | `string` name, `boolean` enabled | is emitted when a feature is evaluated | | ||
| warn | `string` msg | is emitted on a warning | | ||
| error | `Error` err | is emitted on a error | | ||
| unchanged | - | is emitted each time the client gets new toggle state from server, but nothing has changed | | ||
| changed | `object` data | is emitted each time the client gets new toggle state from server and changes has been made | | ||
| | | ||
@@ -193,0 +197,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
158582
219
2
102
1961