Comparing version 1.1.1 to 1.1.2
# Changelog | ||
### 1.1.2 | ||
* Fixed [#117](https://github.com/mweststrate/immer/issues/117), proxy was not finalized when returning a subset of the state | ||
* Fixed [#116](https://github.com/mweststrate/immer/issues/116), changes to arrays that ended up with the same length were not properly detected. | ||
### 1.1.1 | ||
@@ -5,0 +9,0 @@ |
@@ -247,3 +247,3 @@ 'use strict'; | ||
// and finalize the modified proxy | ||
var result = finalize(rootProxy); | ||
var result = void 0; | ||
// check whether the draft was modified and/or a value was returned | ||
@@ -253,3 +253,9 @@ if (returnValue !== undefined && returnValue !== rootProxy) { | ||
if (rootProxy[PROXY_STATE].modified) throw new Error(RETURNED_AND_MODIFIED_ERROR); | ||
result = returnValue; | ||
// See #117 | ||
// Should we just throw when returning a proxy which is not the root, but a subset of the original state? | ||
// Looks like a wrongly modeled reducer | ||
result = finalize(returnValue); | ||
} else { | ||
result = finalize(rootProxy); | ||
} | ||
@@ -377,3 +383,17 @@ // revoke all proxies | ||
function hasArrayChanges(state) { | ||
return state.proxy.length !== state.base.length; | ||
var proxy = state.proxy; | ||
if (proxy.length !== state.base.length) return true; | ||
// See #116 | ||
// If we first shorten the length, our array interceptors will be removed. | ||
// If after that new items are added, result in the same original length, | ||
// those last items will have no intercepting property. | ||
// So if there is no own descriptor on the last position, we know that items were removed and added | ||
// N.B.: splice, unshift, etc only shift values around, but not prop descriptors, so we only have to check | ||
// the last one | ||
var descriptor = Object.getOwnPropertyDescriptor(proxy, proxy.length - 1); | ||
// descriptor can be null, but only for newly created sparse arrays, eg. new Array(10) | ||
if (descriptor && !descriptor.get) return true; | ||
// For all other cases, we don't have to compare, as they would have been picked up by the index setters | ||
return false; | ||
} | ||
@@ -396,3 +416,3 @@ | ||
markChanges(); | ||
var result = finalize(rootProxy); | ||
var result = void 0; | ||
// check whether the draft was modified and/or a value was returned | ||
@@ -402,4 +422,4 @@ if (returnValue !== undefined && returnValue !== rootProxy) { | ||
if (rootProxy[PROXY_STATE].modified) throw new Error(RETURNED_AND_MODIFIED_ERROR); | ||
result = returnValue; | ||
} | ||
result = finalize(returnValue); | ||
} else result = finalize(rootProxy); | ||
// make sure all proxies become unusable | ||
@@ -471,3 +491,3 @@ each(states, function (_, state) { | ||
// it state is a primitive, don't bother proxying at all and just return whatever the producer returns on that value | ||
// if state is a primitive, don't bother proxying at all and just return whatever the producer returns on that value | ||
if ((typeof baseState === "undefined" ? "undefined" : _typeof(baseState)) !== "object" || baseState === null) return producer(baseState); | ||
@@ -474,0 +494,0 @@ if (!isProxyable(baseState)) throw new Error("the first argument to an immer producer should be a primitive, plain object or array, got " + (typeof baseState === "undefined" ? "undefined" : _typeof(baseState)) + ": \"" + baseState + "\""); |
@@ -243,3 +243,3 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { | ||
// and finalize the modified proxy | ||
var result = finalize(rootProxy); | ||
var result = void 0; | ||
// check whether the draft was modified and/or a value was returned | ||
@@ -249,3 +249,9 @@ if (returnValue !== undefined && returnValue !== rootProxy) { | ||
if (rootProxy[PROXY_STATE].modified) throw new Error(RETURNED_AND_MODIFIED_ERROR); | ||
result = returnValue; | ||
// See #117 | ||
// Should we just throw when returning a proxy which is not the root, but a subset of the original state? | ||
// Looks like a wrongly modeled reducer | ||
result = finalize(returnValue); | ||
} else { | ||
result = finalize(rootProxy); | ||
} | ||
@@ -373,3 +379,17 @@ // revoke all proxies | ||
function hasArrayChanges(state) { | ||
return state.proxy.length !== state.base.length; | ||
var proxy = state.proxy; | ||
if (proxy.length !== state.base.length) return true; | ||
// See #116 | ||
// If we first shorten the length, our array interceptors will be removed. | ||
// If after that new items are added, result in the same original length, | ||
// those last items will have no intercepting property. | ||
// So if there is no own descriptor on the last position, we know that items were removed and added | ||
// N.B.: splice, unshift, etc only shift values around, but not prop descriptors, so we only have to check | ||
// the last one | ||
var descriptor = Object.getOwnPropertyDescriptor(proxy, proxy.length - 1); | ||
// descriptor can be null, but only for newly created sparse arrays, eg. new Array(10) | ||
if (descriptor && !descriptor.get) return true; | ||
// For all other cases, we don't have to compare, as they would have been picked up by the index setters | ||
return false; | ||
} | ||
@@ -392,3 +412,3 @@ | ||
markChanges(); | ||
var result = finalize(rootProxy); | ||
var result = void 0; | ||
// check whether the draft was modified and/or a value was returned | ||
@@ -398,4 +418,4 @@ if (returnValue !== undefined && returnValue !== rootProxy) { | ||
if (rootProxy[PROXY_STATE].modified) throw new Error(RETURNED_AND_MODIFIED_ERROR); | ||
result = returnValue; | ||
} | ||
result = finalize(returnValue); | ||
} else result = finalize(rootProxy); | ||
// make sure all proxies become unusable | ||
@@ -467,3 +487,3 @@ each(states, function (_, state) { | ||
// it state is a primitive, don't bother proxying at all and just return whatever the producer returns on that value | ||
// if state is a primitive, don't bother proxying at all and just return whatever the producer returns on that value | ||
if ((typeof baseState === "undefined" ? "undefined" : _typeof(baseState)) !== "object" || baseState === null) return producer(baseState); | ||
@@ -470,0 +490,0 @@ if (!isProxyable(baseState)) throw new Error("the first argument to an immer producer should be a primitive, plain object or array, got " + (typeof baseState === "undefined" ? "undefined" : _typeof(baseState)) + ": \"" + baseState + "\""); |
@@ -1,2 +0,2 @@ | ||
var e,r;e=this,r=function(e){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n="undefined"!=typeof Symbol?Symbol("immer-proxy-state"):"__$immer_state",t="An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.";var o=!("undefined"!=typeof process&&"production"===process.env.NODE_ENV||"verifyMinified"!==function(){}.name),i="undefined"!=typeof Proxy;function f(e){return!!e&&!!e[n]}function u(e){if(!e)return!1;if("object"!==(void 0===e?"undefined":r(e)))return!1;if(Array.isArray(e))return!0;var n=Object.getPrototypeOf(e);return null===n||n===Object.prototype}function a(e){return o&&Object.freeze(e),e}function c(e){return Array.isArray(e)?e.slice():void 0===e.__proto__?Object.assign(Object.create(null),e):Object.assign({},e)}function s(e,r){if(Array.isArray(e))for(var n=0;n<e.length;n++)r(n,e[n]);else for(var t in e)r(t,e[t])}function d(e,r){return Object.prototype.hasOwnProperty.call(e,r)}function p(e){if(f(e)){var r=e[n];return!0===r.modified?!0===r.finalized?r.copy:(r.finalized=!0,t=i?r.copy:r.copy=c(e),o=r.base,s(t,function(e,r){r!==o[e]&&(t[e]=p(r))}),a(t)):r.base}var t,o;return function e(r){if(!u(r))return;if(Object.isFrozen(r))return;s(r,function(n,t){f(t)?r[n]=p(t):e(t)});a(r)}(e),e}function y(e,r){return e===r?0!==e||1/e==1/r:e!=e&&r!=r}var l=null,b={get:function(e,r){if(r===n)return e;if(e.modified){var t=e.copy[r];return t===e.base[r]&&u(t)?e.copy[r]=g(e,t):t}if(d(e.proxies,r))return e.proxies[r];var o=e.base[r];return!f(o)&&u(o)?e.proxies[r]=g(e,o):o},has:function(e,r){return r in m(e)},ownKeys:function(e){return Reflect.ownKeys(m(e))},set:function(e,r,n){if(!e.modified){if(r in e.base&&y(e.base[r],n)||d(e.proxies,r)&&e.proxies[r]===n)return!0;h(e)}return e.copy[r]=n,!0},deleteProperty:function(e,r){return h(e),delete e.copy[r],!0},getOwnPropertyDescriptor:function(e,r){var n=e.modified?e.copy:d(e.proxies,r)?e.proxies:e.base,t=Reflect.getOwnPropertyDescriptor(n,r);!t||Array.isArray(n)&&"length"===r||(t.configurable=!0);return t},defineProperty:function(){throw new Error("Immer does currently not support defining properties on draft objects")},setPrototypeOf:function(){throw new Error("Don't even try this...")}},v={};function m(e){return!0===e.modified?e.copy:e.base}function h(e){e.modified||(e.modified=!0,e.copy=c(e.base),Object.assign(e.copy,e.proxies),e.parent&&h(e.parent))}function g(e,r){var n={modified:!1,finalized:!1,parent:e,base:r,copy:void 0,proxies:{}},t=Array.isArray(r)?Proxy.revocable([n],v):Proxy.revocable(n,b);return l.push(t),t.proxy}s(b,function(e,r){v[e]=function(){return arguments[0]=arguments[0][0],r.apply(this,arguments)}});var w={},j=null;function x(e){return e.hasCopy?e.copy:e.base}function O(e){e.modified||(e.modified=!0,e.parent&&O(e.parent))}function P(e){e.hasCopy||(e.hasCopy=!0,e.copy=c(e.base))}function A(e,r){var t=c(r);s(r,function(e){var r;Object.defineProperty(t,""+e,w[r=""+e]||(w[r]={configurable:!0,enumerable:!0,get:function(){return function(e,r){E(e);var n=x(e)[r];return!e.finalizing&&n===e.base[r]&&u(n)?(P(e),e.copy[r]=A(e,n)):n}(this[n],r)},set:function(e){!function(e,r,n){if(E(e),!e.modified){if(y(x(e)[r],n))return;O(e),P(e)}e.copy[r]=n}(this[n],r,e)}}))});var o,i,f,a={modified:!1,hasCopy:!1,parent:e,base:r,proxy:t,copy:void 0,finished:!1,finalizing:!1,finalized:!1};return o=t,i=n,f=a,Object.defineProperty(o,i,{value:f,enumerable:!1,writable:!0}),j.push(a),t}function E(e){if(!0===e.finished)throw new Error("Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process?")}function z(e,o){var i=j;j=[];try{var f=A(void 0,e),u=o.call(f,f);s(j,function(e,r){r.finalizing=!0}),function(){for(var e=j.length-1;e>=0;e--){var n=j[e];!1===n.modified&&(Array.isArray(n.base)?(f=n).proxy.length!==f.base.length&&O(n):(t=n,o=Object.keys(t.base),i=Object.keys(t.proxy),function(e,n){if(y(e,n))return!0;if("object"!==(void 0===e?"undefined":r(e))||null===e||"object"!==(void 0===n?"undefined":r(n))||null===n)return!1;var t=Object.keys(e),o=Object.keys(n);if(t.length!==o.length)return!1;for(var i=0;i<t.length;i++)if(!hasOwnProperty.call(n,t[i])||!y(e[t[i]],n[t[i]]))return!1;return!0}(o,i)||O(n)))}var t,o,i,f}();var a=p(f);if(void 0!==u&&u!==f){if(f[n].modified)throw new Error(t);a=u}return s(j,function(e,r){r.finished=!0}),a}finally{j=i}}e.default=function e(o,f){if(1===arguments.length){var a=o;if("function"!=typeof a)throw new Error("if produce is called with 1 argument, the first argument should be a function");return function(){var r=arguments;return e(r[0],function(e){return r[0]=e,a.apply(e,r)})}}if(2!==arguments.length)throw new Error("produce expects 1 or 2 arguments, got "+arguments.length);if("function"!=typeof f)throw new Error("the second argument to produce should be a function");if("object"!==(void 0===o?"undefined":r(o))||null===o)return f(o);if(!u(o))throw new Error("the first argument to an immer producer should be a primitive, plain object or array, got "+(void 0===o?"undefined":r(o))+': "'+o+'"');return i?function(e,r){var o=l;l=[];try{var i=g(void 0,e),f=r.call(i,i),u=p(i);if(void 0!==f&&f!==i){if(i[n].modified)throw new Error(t);u=f}return s(l,function(e,r){return r.revoke()}),u}finally{l=o}}(o,f):z(o,f)},e.setAutoFreeze=function(e){o=e},e.setUseProxies=function(e){i=e},Object.defineProperty(e,"__esModule",{value:!0})},"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r(e.immer={}); | ||
var e,r;e=this,r=function(e){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n="undefined"!=typeof Symbol?Symbol("immer-proxy-state"):"__$immer_state",t="An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.";var o=!("undefined"!=typeof process&&"production"===process.env.NODE_ENV||"verifyMinified"!==function(){}.name),i="undefined"!=typeof Proxy;function f(e){return!!e&&!!e[n]}function u(e){if(!e)return!1;if("object"!==(void 0===e?"undefined":r(e)))return!1;if(Array.isArray(e))return!0;var n=Object.getPrototypeOf(e);return null===n||n===Object.prototype}function a(e){return o&&Object.freeze(e),e}function c(e){return Array.isArray(e)?e.slice():void 0===e.__proto__?Object.assign(Object.create(null),e):Object.assign({},e)}function s(e,r){if(Array.isArray(e))for(var n=0;n<e.length;n++)r(n,e[n]);else for(var t in e)r(t,e[t])}function d(e,r){return Object.prototype.hasOwnProperty.call(e,r)}function p(e){if(f(e)){var r=e[n];return!0===r.modified?!0===r.finalized?r.copy:(r.finalized=!0,t=i?r.copy:r.copy=c(e),o=r.base,s(t,function(e,r){r!==o[e]&&(t[e]=p(r))}),a(t)):r.base}var t,o;return function e(r){if(!u(r))return;if(Object.isFrozen(r))return;s(r,function(n,t){f(t)?r[n]=p(t):e(t)});a(r)}(e),e}function y(e,r){return e===r?0!==e||1/e==1/r:e!=e&&r!=r}var l=null,b={get:function(e,r){if(r===n)return e;if(e.modified){var t=e.copy[r];return t===e.base[r]&&u(t)?e.copy[r]=g(e,t):t}if(d(e.proxies,r))return e.proxies[r];var o=e.base[r];return!f(o)&&u(o)?e.proxies[r]=g(e,o):o},has:function(e,r){return r in m(e)},ownKeys:function(e){return Reflect.ownKeys(m(e))},set:function(e,r,n){if(!e.modified){if(r in e.base&&y(e.base[r],n)||d(e.proxies,r)&&e.proxies[r]===n)return!0;h(e)}return e.copy[r]=n,!0},deleteProperty:function(e,r){return h(e),delete e.copy[r],!0},getOwnPropertyDescriptor:function(e,r){var n=e.modified?e.copy:d(e.proxies,r)?e.proxies:e.base,t=Reflect.getOwnPropertyDescriptor(n,r);!t||Array.isArray(n)&&"length"===r||(t.configurable=!0);return t},defineProperty:function(){throw new Error("Immer does currently not support defining properties on draft objects")},setPrototypeOf:function(){throw new Error("Don't even try this...")}},v={};function m(e){return!0===e.modified?e.copy:e.base}function h(e){e.modified||(e.modified=!0,e.copy=c(e.base),Object.assign(e.copy,e.proxies),e.parent&&h(e.parent))}function g(e,r){var n={modified:!1,finalized:!1,parent:e,base:r,copy:void 0,proxies:{}},t=Array.isArray(r)?Proxy.revocable([n],v):Proxy.revocable(n,b);return l.push(t),t.proxy}s(b,function(e,r){v[e]=function(){return arguments[0]=arguments[0][0],r.apply(this,arguments)}});var w={},j=null;function O(e){return e.hasCopy?e.copy:e.base}function x(e){e.modified||(e.modified=!0,e.parent&&x(e.parent))}function P(e){e.hasCopy||(e.hasCopy=!0,e.copy=c(e.base))}function A(e,r){var t=c(r);s(r,function(e){var r;Object.defineProperty(t,""+e,w[r=""+e]||(w[r]={configurable:!0,enumerable:!0,get:function(){return function(e,r){E(e);var n=O(e)[r];return!e.finalizing&&n===e.base[r]&&u(n)?(P(e),e.copy[r]=A(e,n)):n}(this[n],r)},set:function(e){!function(e,r,n){if(E(e),!e.modified){if(y(O(e)[r],n))return;x(e),P(e)}e.copy[r]=n}(this[n],r,e)}}))});var o,i,f,a={modified:!1,hasCopy:!1,parent:e,base:r,proxy:t,copy:void 0,finished:!1,finalizing:!1,finalized:!1};return o=t,i=n,f=a,Object.defineProperty(o,i,{value:f,enumerable:!1,writable:!0}),j.push(a),t}function E(e){if(!0===e.finished)throw new Error("Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process?")}function z(e){var r=e.proxy;if(r.length!==e.base.length)return!0;var n=Object.getOwnPropertyDescriptor(r,r.length-1);return!(!n||n.get)}function _(e,o){var i=j;j=[];try{var f=A(void 0,e),u=o.call(f,f);s(j,function(e,r){r.finalizing=!0}),function(){for(var e=j.length-1;e>=0;e--){var n=j[e];!1===n.modified&&(Array.isArray(n.base)?z(n)&&x(n):(t=n,o=Object.keys(t.base),i=Object.keys(t.proxy),function(e,n){if(y(e,n))return!0;if("object"!==(void 0===e?"undefined":r(e))||null===e||"object"!==(void 0===n?"undefined":r(n))||null===n)return!1;var t=Object.keys(e),o=Object.keys(n);if(t.length!==o.length)return!1;for(var i=0;i<t.length;i++)if(!hasOwnProperty.call(n,t[i])||!y(e[t[i]],n[t[i]]))return!1;return!0}(o,i)||x(n)))}var t,o,i}();var a=void 0;if(void 0!==u&&u!==f){if(f[n].modified)throw new Error(t);a=p(u)}else a=p(f);return s(j,function(e,r){r.finished=!0}),a}finally{j=i}}e.default=function e(o,f){if(1===arguments.length){var a=o;if("function"!=typeof a)throw new Error("if produce is called with 1 argument, the first argument should be a function");return function(){var r=arguments;return e(r[0],function(e){return r[0]=e,a.apply(e,r)})}}if(2!==arguments.length)throw new Error("produce expects 1 or 2 arguments, got "+arguments.length);if("function"!=typeof f)throw new Error("the second argument to produce should be a function");if("object"!==(void 0===o?"undefined":r(o))||null===o)return f(o);if(!u(o))throw new Error("the first argument to an immer producer should be a primitive, plain object or array, got "+(void 0===o?"undefined":r(o))+': "'+o+'"');return i?function(e,r){var o=l;l=[];try{var i=g(void 0,e),f=r.call(i,i),u=void 0;if(void 0!==f&&f!==i){if(i[n].modified)throw new Error(t);u=p(f)}else u=p(i);return s(l,function(e,r){return r.revoke()}),u}finally{l=o}}(o,f):_(o,f)},e.setAutoFreeze=function(e){o=e},e.setUseProxies=function(e){i=e},Object.defineProperty(e,"__esModule",{value:!0})},"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r(e.immer={}); | ||
//# sourceMappingURL=immer.umd.js.map |
{ | ||
"name": "immer", | ||
"version": "1.1.1", | ||
"version": "1.1.2", | ||
"description": "Create your next immutable state by mutating the current one", | ||
@@ -18,4 +18,4 @@ "main": "dist/immer.js", | ||
"prettier": "prettier \"*/**/*.js\" --ignore-path ./.prettierignore --write", | ||
"prepublish": "yarn-or-npm run build", | ||
"precommit": "lint-staged" | ||
"precommit": "lint-staged", | ||
"release": "yarn-or-npm run build && np" | ||
}, | ||
@@ -60,2 +60,3 @@ "repository": { | ||
"lodash.clonedeep": "^4.5.0", | ||
"np": "^2.20.1", | ||
"prettier": "^1.9.2", | ||
@@ -62,0 +63,0 @@ "regenerator-runtime": "^0.11.1", |
@@ -6,3 +6,3 @@ # Immer | ||
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) | ||
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://mobx.js.org/donate.html) | ||
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/michelweststrate) | ||
@@ -139,3 +139,3 @@ _Create the next immutable state tree by simply modifying the current tree_ | ||
_Note: it might be tempting after using producers a while, to just put `produce` in your root reducer, and then past the draft along to each reducer and work on that. Don't do that. It kills the point of Redux where each reducer is testable as pure reducer. Immer is best used when applying it to small individual pieces of logic._ | ||
_Note: it might be tempting after using producers for a while, to just place `produce` in your root reducer and then pass the draft to each reducer and work directly over such draft. Don't do that. It kills the point of Redux where each reducer is testable as pure reducer. Immer is best used when applying it to small individual pieces of logic._ | ||
@@ -167,3 +167,3 @@ ## React.setState example | ||
draft.user.age += 1 | ||
}) | ||
})) | ||
} | ||
@@ -312,2 +312,54 @@ ``` | ||
## Example patterns. | ||
_For those who have to go back to thinking in object updates :-)_ | ||
```javscript | ||
import produce from "immer"; | ||
// object mutations | ||
const todosObj = { | ||
id1: { done: false, body: "Take out the trash" }, | ||
id2: { done: false, body: "Check Email" } | ||
}; | ||
// add | ||
const addedTodosObj = produce(todosObj, draft => { | ||
draft["id3"] = { done: false, body: "Buy bananas" }; | ||
}); | ||
// delete | ||
const deletedTodosObj = produce(todosObj, draft => { | ||
delete draft["id1"]; | ||
}); | ||
// update | ||
const updatedTodosObj = produce(todosObj, draft => { | ||
draft["id1"].done = true; | ||
}); | ||
// array mutations | ||
const todosArray = [ | ||
{ id: "id1", done: false, body: "Take out the trash" }, | ||
{ id: "id2", done: false, body: "Check Email" } | ||
]; | ||
// add | ||
const addedTodosArray = produce(todosArray, draft => { | ||
draft.push({ id: "id3", done: false, body: "Buy bananas" }); | ||
}); | ||
// delete | ||
const deletedTodosArray = produce(todosArray, draft => { | ||
draft.splice(draft.findIndex(todo => todo.id === "id1"), 1); | ||
// or (slower): | ||
// return draft.filter(todo => todo.id !== "id1") | ||
}); | ||
// update | ||
const updatedTodosArray = produce(todosArray, draft => { | ||
draft[draft.findIndex(todo => todo.id === "id1")].done = true; | ||
}); | ||
``` | ||
## Performance | ||
@@ -314,0 +366,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
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
155260
931
420
32