foop
Version:
interfaces that describe their intentions.
203 lines (185 loc) • 16.2 kB
JavaScript
var toarr = require('../deps/to-arr')
var traverse = require('../deps/traverse')
var match = require('../deps/matcher')
var getPathSegments = require('../deps/dot/segments')
var dotSet = require('../deps/dot/set')
var newMap = require('../deps/construct/map')
var OBSERVERS_KEY = require('../deps/meta/OBSERVERS_KEY')
var ENV_DEBUG = require('../deps/env/debug')
// @TODO export better, this adds extra size
var eq = traverse.eq;
var clone = traverse.clone;
/**
* @TODO auto-clear when near full, have cache-class with pooling
* @desc scoped clones
* @private
* @type {Map}
*/
var objs = new Map()
/**
* @desc > subscribe to changes
* ❗ called only on **change**
* observers are only called when data they subscribe to changes
*
* @since 3.0.1
* @class Observe
* @member Observe
* @extends {ChainedMap}
* @extends {DotProp}
* @memberOf compose
* @category Chainable
*
* @param {Class | Composable} Target composable class
* @return {Observe} class
*
* @tests Observe
* @types Observe
*
* @see ChainedMap
* @see DotProp
* @see deps/matcher
* @see deps/traversers/eq
* @see deps/traverse
* @see DotProp
*
* {@link https://msdn.microsoft.com/en-us/library/dd456845(v=vs.110).aspx microsoft}
* {@link https://github.com/Hypercubed/ hypercubed}
* {@link http://eliperelman.com/fn.js/ fn-is}
* {@link https://github.com/knockout/knockout/blob/master/src/subscribables/observable.js knockoutjs-observable}
* {@link https://www.npmjs.com/package/simple-observable simple-observable}
* {@link https://github.com/canjs/can-observation can-js-observation}
* [ minimal OR simple OR microjs OR tiny observable ]
*
* {@link https://github.com/iluwatar/java-design-patterns/tree/master/observer observer-pattern}
* {@link https://github.com/ReactiveX/rxjs/blob/master/src/Subscriber.ts reactivex}
* {@link https://github.com/sindresorhus/awesome-observables awesome-observables}
* {@link https://medium.com/@benlesh/learning-observable-by-building-observable-d5da57405d87 building-observables}
* {@link https://github.com/addyosmani/essential-js-design-patterns/blob/master/diagrams/observer.png js-observer-png}
* {@link https://github.com/addyosmani/essential-js-design-patterns/blob/master/diagrams/publishsubscribe.png pubsub-png}
* {@link https://github.com/tusharmath/observable-air observable-air}
*
* @see {@link reactivex}
* @see {@link awesome-observables}
* @see {@link building-observables}
* @see {@link observer-pattern}
* @see {@link observable-air}
*
* @example
*
* const {compose} = require('chain-able')
* const {DotProp} = compose
* new DotProp()
* //=> DotProp
*
*/
module.exports = function (Target) {
// return class Observe extends Target {
/**
* @desc observe properties when they change
*
* @method
* @memberOf Observe
* @since 4.0.0 <- refactored with dot-prop
* @since 1.0.0
*
* @param {Matchable} properties Matchable properties to observe
* @param {Function} fn onChanged
* @return {Target} @chainable
*
* @see traversers/eq
* @see toarr
* @see matcher
*
* {@link https://jsfiddle.net/wqxuags2/28/ for a Demo Clock with observable}
*
* @see {@link for a Demo Clock with observable}
* @see examples/playground/TodoStore
*
* @TODO gotta update `data` if `deleting` too...
* @TODO un-observe
* @TODO should hash these callback properties
* @TODO just throttle the `.set` to allow easier version of .commit
*
* @example
*
* const Target = require('chain-able')
*
* const chain = new Target()
* const log = arg => console.log(arg)
*
* chain
* .extend(['eh'])
* .observe('eh', data => log(data))
* .eh(true)
* //=> {eh: true}
*
* @example
*
* chain
* .extend(['canada', 'timbuck'])
* .observe(['canad*'], data => console.log(data.canada))
* .canada(true)
* .canada(true)
* .timbuck(false)
*
* //=> true
* //=> false
*
* // only called when changed,
* // otherwise it would be 2 `true` & 1 `false`
*
*/
Target.prototype.observe = function chainObserve(properties, fn) {
var this$1 = this;
if (ENV_DEBUG) {
console.log('observe', {properties: properties, fn: fn})
}
var props = toarr(properties)
var hashKey = props.join('_')
if (ENV_DEBUG) {
console.log('observe', {[hashKey]: props})
}
var data = {}
/* prettier-ignore */
return this.meta(OBSERVERS_KEY, function (changed) {
/**
* match the keys, make the data out of it
*/
var m = match(changed.key, props)
// @@debugger
if (ENV_DEBUG) {
console.log({m: m, key: changed.key, objs: objs, data: data, hashKey: hashKey})
}
// @NOTE faster
if (m.length === 0) { return }
// update data
for (var i = 0; i < m.length; i++) {
var segments = getPathSegments(m[i])
// console.log({segments, m, i, v: m[i]})
dotSet(data, segments, this$1.get(segments))
}
/**
* if we have called it at least once...
* and it has not changed, leave it
* else
* clone it
* call the observer
*/
if (objs.has(hashKey) && eq(objs.get(hashKey), data)) {
// @@debugger
return
}
// @@debugger
/**
* it did change - clone it for next deepEquals check
*/
objs.set(hashKey, clone(data))
/**
* call the observer - it matched & data changed
*/
fn.call(this$1, data, this$1)
})
}
return Target
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT2JzZXJ2ZS5qcyIsInNvdXJjZXMiOlsiT2JzZXJ2ZS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCB0b2FyciA9IHJlcXVpcmUoJy4uL2RlcHMvdG8tYXJyJylcbmNvbnN0IHRyYXZlcnNlID0gcmVxdWlyZSgnLi4vZGVwcy90cmF2ZXJzZScpXG5jb25zdCBtYXRjaCA9IHJlcXVpcmUoJy4uL2RlcHMvbWF0Y2hlcicpXG5jb25zdCBnZXRQYXRoU2VnbWVudHMgPSByZXF1aXJlKCcuLi9kZXBzL2RvdC9zZWdtZW50cycpXG5jb25zdCBkb3RTZXQgPSByZXF1aXJlKCcuLi9kZXBzL2RvdC9zZXQnKVxuY29uc3QgbmV3TWFwID0gcmVxdWlyZSgnLi4vZGVwcy9jb25zdHJ1Y3QvbWFwJylcbmNvbnN0IE9CU0VSVkVSU19LRVkgPSByZXF1aXJlKCcuLi9kZXBzL21ldGEvT0JTRVJWRVJTX0tFWScpXG5jb25zdCBFTlZfREVCVUcgPSByZXF1aXJlKCcuLi9kZXBzL2Vudi9kZWJ1ZycpXG5cbi8vIEBUT0RPIGV4cG9ydCBiZXR0ZXIsIHRoaXMgYWRkcyBleHRyYSBzaXplXG5jb25zdCB7ZXEsIGNsb25lfSA9IHRyYXZlcnNlXG5cbi8qKlxuICogQFRPRE8gYXV0by1jbGVhciB3aGVuIG5lYXIgZnVsbCwgaGF2ZSBjYWNoZS1jbGFzcyB3aXRoIHBvb2xpbmdcbiAqIEBkZXNjIHNjb3BlZCBjbG9uZXNcbiAqIEBwcml2YXRlXG4gKiBAdHlwZSB7TWFwfVxuICovXG5sZXQgb2JqcyA9IG5ldyBNYXAoKVxuXG4vKipcbiAqIEBkZXNjID4gc3Vic2NyaWJlIHRvIGNoYW5nZXNcbiAqICAgICAgIOKdlyBjYWxsZWQgb25seSBvbiAqKmNoYW5nZSoqXG4gKiAgICAgICBvYnNlcnZlcnMgYXJlIG9ubHkgY2FsbGVkIHdoZW4gZGF0YSB0aGV5IHN1YnNjcmliZSB0byBjaGFuZ2VzXG4gKlxuICogQHNpbmNlIDMuMC4xXG4gKiBAY2xhc3MgT2JzZXJ2ZVxuICogQG1lbWJlciBPYnNlcnZlXG4gKiBAZXh0ZW5kcyB7Q2hhaW5lZE1hcH1cbiAqIEBleHRlbmRzIHtEb3RQcm9wfVxuICogQG1lbWJlck9mIGNvbXBvc2VcbiAqIEBjYXRlZ29yeSBDaGFpbmFibGVcbiAqXG4gKiBAcGFyYW0gIHtDbGFzcyB8IENvbXBvc2FibGV9IFRhcmdldCBjb21wb3NhYmxlIGNsYXNzXG4gKiBAcmV0dXJuIHtPYnNlcnZlfSBjbGFzc1xuICpcbiAqIEB0ZXN0cyBPYnNlcnZlXG4gKiBAdHlwZXMgT2JzZXJ2ZVxuICpcbiAqIEBzZWUgQ2hhaW5lZE1hcFxuICogQHNlZSBEb3RQcm9wXG4gKiBAc2VlIGRlcHMvbWF0Y2hlclxuICogQHNlZSBkZXBzL3RyYXZlcnNlcnMvZXFcbiAqIEBzZWUgZGVwcy90cmF2ZXJzZVxuICogQHNlZSBEb3RQcm9wXG4gKlxuICoge0BsaW5rIGh0dHBzOi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvZGQ0NTY4NDUodj12cy4xMTApLmFzcHggbWljcm9zb2Z0fVxuICoge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9IeXBlcmN1YmVkLyBoeXBlcmN1YmVkfVxuICoge0BsaW5rIGh0dHA6Ly9lbGlwZXJlbG1hbi5jb20vZm4uanMvIGZuLWlzfVxuICoge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9rbm9ja291dC9rbm9ja291dC9ibG9iL21hc3Rlci9zcmMvc3Vic2NyaWJhYmxlcy9vYnNlcnZhYmxlLmpzIGtub2Nrb3V0anMtb2JzZXJ2YWJsZX1cbiAqIHtAbGluayBodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9zaW1wbGUtb2JzZXJ2YWJsZSBzaW1wbGUtb2JzZXJ2YWJsZX1cbiAqIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vY2FuanMvY2FuLW9ic2VydmF0aW9uIGNhbi1qcy1vYnNlcnZhdGlvbn1cbiAqIFsgbWluaW1hbCBPUiBzaW1wbGUgT1IgbWljcm9qcyBPUiB0aW55IG9ic2VydmFibGUgXVxuICpcbiAqIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vaWx1d2F0YXIvamF2YS1kZXNpZ24tcGF0dGVybnMvdHJlZS9tYXN0ZXIvb2JzZXJ2ZXIgb2JzZXJ2ZXItcGF0dGVybn1cbiAqIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vUmVhY3RpdmVYL3J4anMvYmxvYi9tYXN0ZXIvc3JjL1N1YnNjcmliZXIudHMgcmVhY3RpdmV4fVxuICoge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9zaW5kcmVzb3JodXMvYXdlc29tZS1vYnNlcnZhYmxlcyBhd2Vzb21lLW9ic2VydmFibGVzfVxuICoge0BsaW5rIGh0dHBzOi8vbWVkaXVtLmNvbS9AYmVubGVzaC9sZWFybmluZy1vYnNlcnZhYmxlLWJ5LWJ1aWxkaW5nLW9ic2VydmFibGUtZDVkYTU3NDA1ZDg3IGJ1aWxkaW5nLW9ic2VydmFibGVzfVxuICoge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9hZGR5b3NtYW5pL2Vzc2VudGlhbC1qcy1kZXNpZ24tcGF0dGVybnMvYmxvYi9tYXN0ZXIvZGlhZ3JhbXMvb2JzZXJ2ZXIucG5nIGpzLW9ic2VydmVyLXBuZ31cbiAqIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vYWRkeW9zbWFuaS9lc3NlbnRpYWwtanMtZGVzaWduLXBhdHRlcm5zL2Jsb2IvbWFzdGVyL2RpYWdyYW1zL3B1Ymxpc2hzdWJzY3JpYmUucG5nIHB1YnN1Yi1wbmd9XG4gKiB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL3R1c2hhcm1hdGgvb2JzZXJ2YWJsZS1haXIgb2JzZXJ2YWJsZS1haXJ9XG4gKlxuICogQHNlZSB7QGxpbmsgcmVhY3RpdmV4fVxuICogQHNlZSB7QGxpbmsgYXdlc29tZS1vYnNlcnZhYmxlc31cbiAqIEBzZWUge0BsaW5rIGJ1aWxkaW5nLW9ic2VydmFibGVzfVxuICogQHNlZSB7QGxpbmsgb2JzZXJ2ZXItcGF0dGVybn1cbiAqIEBzZWUge0BsaW5rIG9ic2VydmFibGUtYWlyfVxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogICAgY29uc3Qge2NvbXBvc2V9ID0gcmVxdWlyZSgnY2hhaW4tYWJsZScpXG4gKiAgICBjb25zdCB7RG90UHJvcH0gPSBjb21wb3NlXG4gKiAgICBuZXcgRG90UHJvcCgpXG4gKiAgICAvLz0+IERvdFByb3BcbiAqXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gVGFyZ2V0ID0+IHtcbiAgLy8gcmV0dXJuIGNsYXNzIE9ic2VydmUgZXh0ZW5kcyBUYXJnZXQge1xuICAvKipcbiAgICogQGRlc2Mgb2JzZXJ2ZSBwcm9wZXJ0aWVzIHdoZW4gdGhleSBjaGFuZ2VcbiAgICpcbiAgICogQG1ldGhvZFxuICAgKiBAbWVtYmVyT2YgT2JzZXJ2ZVxuICAgKiBAc2luY2UgNC4wLjAgPC0gcmVmYWN0b3JlZCB3aXRoIGRvdC1wcm9wXG4gICAqIEBzaW5jZSAxLjAuMFxuICAgKlxuICAgKiBAcGFyYW0gIHtNYXRjaGFibGV9IHByb3BlcnRpZXMgTWF0Y2hhYmxlIHByb3BlcnRpZXMgdG8gb2JzZXJ2ZVxuICAgKiBAcGFyYW0gIHtGdW5jdGlvbn0gZm4gb25DaGFuZ2VkXG4gICAqIEByZXR1cm4ge1RhcmdldH0gQGNoYWluYWJsZVxuICAgKlxuICAgKiBAc2VlIHRyYXZlcnNlcnMvZXFcbiAgICogQHNlZSB0b2FyclxuICAgKiBAc2VlIG1hdGNoZXJcbiAgICpcbiAgICoge0BsaW5rIGh0dHBzOi8vanNmaWRkbGUubmV0L3dxeHVhZ3MyLzI4LyBmb3IgYSBEZW1vIENsb2NrIHdpdGggb2JzZXJ2YWJsZX1cbiAgICpcbiAgICogQHNlZSB7QGxpbmsgZm9yIGEgRGVtbyBDbG9jayB3aXRoIG9ic2VydmFibGV9XG4gICAqIEBzZWUgZXhhbXBsZXMvcGxheWdyb3VuZC9Ub2RvU3RvcmVcbiAgICpcbiAgICogQFRPRE8gZ290dGEgdXBkYXRlIGBkYXRhYCBpZiBgZGVsZXRpbmdgIHRvby4uLlxuICAgKiBAVE9ETyB1bi1vYnNlcnZlXG4gICAqIEBUT0RPIHNob3VsZCBoYXNoIHRoZXNlIGNhbGxiYWNrIHByb3BlcnRpZXNcbiAgICogQFRPRE8ganVzdCB0aHJvdHRsZSB0aGUgYC5zZXRgIHRvIGFsbG93IGVhc2llciB2ZXJzaW9uIG9mIC5jb21taXRcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICBjb25zdCBUYXJnZXQgPSByZXF1aXJlKCdjaGFpbi1hYmxlJylcbiAgICpcbiAgICogICBjb25zdCBjaGFpbiA9IG5ldyBUYXJnZXQoKVxuICAgKiAgIGNvbnN0IGxvZyA9IGFyZyA9PiBjb25zb2xlLmxvZyhhcmcpXG4gICAqXG4gICAqICAgY2hhaW5cbiAgICogICAgIC5leHRlbmQoWydlaCddKVxuICAgKiAgICAgLm9ic2VydmUoJ2VoJywgZGF0YSA9PiBsb2coZGF0YSkpXG4gICAqICAgICAuZWgodHJ1ZSlcbiAgICogICAvLz0+IHtlaDogdHJ1ZX1cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogICAgY2hhaW5cbiAgICogICAgICAuZXh0ZW5kKFsnY2FuYWRhJywgJ3RpbWJ1Y2snXSlcbiAgICogICAgICAub2JzZXJ2ZShbJ2NhbmFkKiddLCBkYXRhID0+IGNvbnNvbGUubG9nKGRhdGEuY2FuYWRhKSlcbiAgICogICAgICAuY2FuYWRhKHRydWUpXG4gICAqICAgICAgLmNhbmFkYSh0cnVlKVxuICAgKiAgICAgIC50aW1idWNrKGZhbHNlKVxuICAgKlxuICAgKiAgICAvLz0+IHRydWVcbiAgICogICAgLy89PiBmYWxzZVxuICAgKlxuICAgKiAgICAvLyBvbmx5IGNhbGxlZCB3aGVuIGNoYW5nZWQsXG4gICAqICAgIC8vIG90aGVyd2lzZSBpdCB3b3VsZCBiZSAyIGB0cnVlYCAmIDEgYGZhbHNlYFxuICAgKlxuICAgKi9cbiAgVGFyZ2V0LnByb3RvdHlwZS5vYnNlcnZlID0gZnVuY3Rpb24gY2hhaW5PYnNlcnZlKHByb3BlcnRpZXMsIGZuKSB7XG4gICAgaWYgKEVOVl9ERUJVRykge1xuICAgICAgY29uc29sZS5sb2coJ29ic2VydmUnLCB7cHJvcGVydGllcywgZm59KVxuICAgIH1cblxuICAgIGNvbnN0IHByb3BzID0gdG9hcnIocHJvcGVydGllcylcbiAgICBjb25zdCBoYXNoS2V5ID0gcHJvcHMuam9pbignXycpXG5cbiAgICBpZiAoRU5WX0RFQlVHKSB7XG4gICAgICBjb25zb2xlLmxvZygnb2JzZXJ2ZScsIHtbaGFzaEtleV06IHByb3BzfSlcbiAgICB9XG5cbiAgICBsZXQgZGF0YSA9IHt9XG5cbiAgICAvKiBwcmV0dGllci1pZ25vcmUgKi9cbiAgICByZXR1cm4gdGhpcy5tZXRhKE9CU0VSVkVSU19LRVksIGNoYW5nZWQgPT4ge1xuICAgICAgLyoqXG4gICAgICAgKiBtYXRjaCB0aGUga2V5cywgbWFrZSB0aGUgZGF0YSBvdXQgb2YgaXRcbiAgICAgICAqL1xuICAgICAgY29uc3QgbSA9IG1hdGNoKGNoYW5nZWQua2V5LCBwcm9wcylcblxuICAgICAgLy8gQEBkZWJ1Z2dlclxuXG4gICAgICBpZiAoRU5WX0RFQlVHKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKHttLCBrZXk6IGNoYW5nZWQua2V5LCBvYmpzLCBkYXRhLCBoYXNoS2V5fSlcbiAgICAgIH1cblxuICAgICAgLy8gQE5PVEUgZmFzdGVyXG4gICAgICBpZiAobS5sZW5ndGggPT09IDApIHJldHVyblxuXG4gICAgICAvLyB1cGRhdGUgZGF0YVxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IHNlZ21lbnRzID0gZ2V0UGF0aFNlZ21lbnRzKG1baV0pXG4gICAgICAgIC8vIGNvbnNvbGUubG9nKHtzZWdtZW50cywgbSwgaSwgdjogbVtpXX0pXG4gICAgICAgIGRvdFNldChkYXRhLCBzZWdtZW50cywgdGhpcy5nZXQoc2VnbWVudHMpKVxuICAgICAgfVxuXG4gICAgICAvKipcbiAgICAgICAqIGlmIHdlIGhhdmUgY2FsbGVkIGl0IGF0IGxlYXN0IG9uY2UuLi5cbiAgICAgICAqICAgIGFuZCBpdCBoYXMgbm90IGNoYW5nZWQsIGxlYXZlIGl0XG4gICAgICAgKiBlbHNlXG4gICAgICAgKiAgICBjbG9uZSBpdFxuICAgICAgICogICAgY2FsbCB0aGUgb2JzZXJ2ZXJcbiAgICAgICAqL1xuICAgICAgaWYgKG9ianMuaGFzKGhhc2hLZXkpICYmIGVxKG9ianMuZ2V0KGhhc2hLZXkpLCBkYXRhKSkge1xuICAgICAgICAvLyBAQGRlYnVnZ2VyXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICAvLyBAQGRlYnVnZ2VyXG5cbiAgICAgIC8qKlxuICAgICAgICogaXQgZGlkIGNoYW5nZSAtIGNsb25lIGl0IGZvciBuZXh0IGRlZXBFcXVhbHMgY2hlY2tcbiAgICAgICAqL1xuICAgICAgb2Jqcy5zZXQoaGFzaEtleSwgY2xvbmUoZGF0YSkpXG5cbiAgICAgIC8qKlxuICAgICAgICogY2FsbCB0aGUgb2JzZXJ2ZXIgLSBpdCBtYXRjaGVkICYgZGF0YSBjaGFuZ2VkXG4gICAgICAgKi9cbiAgICAgIGZuLmNhbGwodGhpcywgZGF0YSwgdGhpcylcbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIFRhcmdldFxufVxuIl0sIm5hbWVzIjpbImNvbnN0IiwibGV0IiwidGhpcyJdLCJtYXBwaW5ncyI6IkFBQUFBLEdBQUssQ0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLGdCQUFnQixDQUFDO0FBQ3ZDQSxHQUFLLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQztBQUM1Q0EsR0FBSyxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQUM7QUFDeENBLEdBQUssQ0FBQyxlQUFlLEdBQUcsT0FBTyxDQUFDLHNCQUFzQixDQUFDO0FBQ3ZEQSxHQUFLLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztBQUN6Q0EsR0FBSyxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsdUJBQXVCLENBQUM7QUFDL0NBLEdBQUssQ0FBQyxhQUFhLEdBQUcsT0FBTyxDQUFDLDRCQUE0QixDQUFDO0FBQzNEQSxHQUFLLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQzs7O0FBRzlDLEFBQUssQUFB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