├── .gitignore ├── README.md ├── dist ├── update-in.js └── update-in.min.js ├── examples └── cursor │ ├── .gitignore │ ├── karma.conf.js │ ├── package.json │ ├── src │ ├── Cursor.js │ ├── Store.js │ └── __tests__ │ │ └── Cursor.spec.js │ ├── tests.webpack.js │ └── webpack.config.js ├── karma.conf.js ├── package.json ├── src ├── __tests__ │ └── UpdateIn.spec.js └── update-in.js ├── tests.webpack.js ├── webpack.config.js └── webpack.dist.js /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | .DS_STORE 3 | /node_modules 4 | /bower_components 5 | *.iml 6 | .idea 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # update-in 2 | Persistent functional object updates on vanilla js data structures (wraps react-addons-update) 3 | 4 | ## Quick Examples 5 | ```javascript 6 | import {updateIn, merge, push, unshift, splice, assoc, dissoc} from 'update-in'; 7 | 8 | const val = {a: {b: 0, c: 2}, xs: [1, 2]}; 9 | 10 | updateIn(val, ['a', 'b'], v => v+1) // => {a: {b: 1, c: 2}, xs: [1, 2]} 11 | updateIn(val, ['a', 'b'], v => v+10) // => {a: {b: 10, c: 2}, xs: [1, 2]} 12 | 13 | let add = (...args) => args.reduce((a,b)=>a+b, 0); 14 | updateIn(val, ['a', 'b'], add, 1, 2, 3) // => {a: {b: 6, c: 2}, xs: [1, 2]} 15 | 16 | updateIn(val, ['a', 'b'], v => 99) // => {a: {b: 99, c: 2}, xs: [1, 2]} 17 | 18 | merge({x: 1, y: 1}, {y: 2, z: 2}) // => {x: 1, y: 2, z: 2} 19 | updateIn(val, ['a'], merge, {c:99, d: 99}) // => {a: {b: 0, c: 99, d: 99}, xs: [1, 2]} 20 | 21 | updateIn(val, ['xs'], push, [3]) // => {a: {b: 0, c: 2}, xs: [1, 2, 3]} 22 | updateIn(val, ['xs'], push, [99]) // => {a: {b: 0, c: 2}, xs: [1, 2, 99]} 23 | 24 | updateIn(val, ['xs'], unshift, [0]) // => {a: {b: 0, c: 2}, xs: [0, 1, 2]} 25 | 26 | updateIn(val, ['xs'], splice, [[1, 1, 20]]) // => {a: {b: 0, c: 2}, xs: [1, 20]} 27 | updateIn(val, ['xs'], splice, [[0, 1, 6, 5], [4, 0, 99, 99]]) // => {a: {b: 0, c: 99, d: 99}, xs: [6,5,2,99,99]} 28 | 29 | updateIn(val, ['a'], assoc, 'b', 1); // => {b: 1, c: 2} 30 | updateIn(val, ['a'], assoc, 'b', 5, 'c', 6); // => {b: 5, c: 6} 31 | updateIn(val, ['a'], assoc, 'd', 4); // => {b: 0, c: 2, d: 4} 32 | updateIn(val, ['a'], assoc, 'd', 4, 'e', 6); // => {b: 0, c: 2, d: 4, e: 6} 33 | updateIn(val, ['a'], assoc, 'd', 4, 'e') // => Error('assoc expects an even number of arguments') 34 | 35 | updateIn(val, ['xs'], assoc, 0, 3); // => [3, 2] 36 | updateIn(val, ['xs'], assoc, 0, 3, 1, 4); // => [3, 4] 37 | updateIn(val, ['xs'], assoc, 2, 3); // => [1, 2, 3] 38 | updateIn(val, ['xs'], assoc, 1, false, 0) // => Error('assoc expects an even number of arguments') 39 | updateIn(val, ['xs'], assoc, 1.5, 'not an int') // => TypeError('assoc expects only integer keys') 40 | updateIn(val, ['xs'], assoc, -1, 'negative index?') // => RangeError('assoc expects only numeric keys in the range [0, array.length]') 41 | updateIn(val, ['xs'], assoc, 3, 'sparse arrays?') // => RangeError('assoc expects only numeric keys in the range [0, array.length]') 42 | 43 | const collections = { 44 | object: {foo: 1, bar: 2, baz: 3}, 45 | array: [1, 2, 3, 4, 5, 6, 7] 46 | }; 47 | 48 | updateIn(collections, ['object'], dissoc, 'bar') // => {foo: 1, baz: 3} 49 | updateIn(collections, ['object'], dissoc, 'foo', 'baz') // => {bar: 2} 50 | 51 | updateIn(collections, ['array'], dissoc, 1) // => [1, 3, 4, 5, 6, 7] 52 | updateIn(collections, ['array'], dissoc, 2, 3, 4) // => [1, 2, 6, 7] 53 | updateIn(collections, ['array'], dissoc, 1, 3, 5) // => [1, 3, 5, 7] 54 | ``` 55 | 56 | These combinators use structure sharing to preserve `===` for unchanged nodes, structure sharing is provided by [react-addons-update](https://www.npmjs.com/package/react-addons-update). As of React 0.14, react-addons-update requires all of React as a peer dependency. 57 | 58 | 59 | ## Bigger example 60 | 61 | We can implement cursors in very few lines with `updateIn`, see the examples subdirectory. 62 | -------------------------------------------------------------------------------- /dist/update-in.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | /******/ 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | /******/ 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | /******/ 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ exports: {}, 15 | /******/ id: moduleId, 16 | /******/ loaded: false 17 | /******/ }; 18 | /******/ 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | /******/ 22 | /******/ // Flag the module as loaded 23 | /******/ module.loaded = true; 24 | /******/ 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | /******/ 29 | /******/ 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | /******/ 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | /******/ 36 | /******/ // __webpack_public_path__ 37 | /******/ __webpack_require__.p = "/static/"; 38 | /******/ 39 | /******/ // Load entry module and return exports 40 | /******/ return __webpack_require__(0); 41 | /******/ }) 42 | /************************************************************************/ 43 | /******/ ([ 44 | /* 0 */ 45 | /***/ function(module, exports, __webpack_require__) { 46 | 47 | 'use strict'; 48 | 49 | Object.defineProperty(exports, '__esModule', { 50 | value: true 51 | }); 52 | 53 | var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); 54 | 55 | exports.merge = merge; 56 | exports.push = push; 57 | exports.unshift = unshift; 58 | exports.splice = splice; 59 | exports.assoc = assoc; 60 | exports.dissoc = dissoc; 61 | exports.updateIn = updateIn; 62 | 63 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } 64 | 65 | var _reactAddonsUpdate = __webpack_require__(1); 66 | 67 | var _reactAddonsUpdate2 = _interopRequireDefault(_reactAddonsUpdate); 68 | 69 | var _deepEqual = __webpack_require__(7); 70 | 71 | var _deepEqual2 = _interopRequireDefault(_deepEqual); 72 | 73 | function merge(a, b) { 74 | return (0, _reactAddonsUpdate2['default'])(a, { $merge: b }); 75 | } 76 | 77 | function push(as, bs) { 78 | return (0, _reactAddonsUpdate2['default'])(as, { $push: bs }); 79 | } 80 | 81 | function unshift(as, bs) { 82 | return (0, _reactAddonsUpdate2['default'])(as, { $unshift: bs }); 83 | } 84 | 85 | function splice(as, splices) { 86 | // persistentUpdate([12, 17, 15], {$splice: [[1, 1, 13, 14]]}) => [12, 13, 14, 15] 87 | return (0, _reactAddonsUpdate2['default'])(as, { $splice: splices }); 88 | } 89 | 90 | function assoc(coll) { 91 | for (var _len = arguments.length, kvs = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 92 | kvs[_key - 1] = arguments[_key]; 93 | } 94 | 95 | if (kvs.length % 2 !== 0) throw new Error('assoc expects an even number of arguments'); 96 | var ps = pairs(kvs); 97 | 98 | if (Array.isArray(coll)) { 99 | ps.forEach(function (_ref) { 100 | var _ref2 = _slicedToArray(_ref, 2); 101 | 102 | var k = _ref2[0]; 103 | var v = _ref2[1]; 104 | 105 | if (!(typeof k === 'number' && parseInt(k, 10) === k)) throw new TypeError('assoc expects only integer keys'); 106 | if (k < 0 || k > coll.length) throw new RangeError('assoc expects only numeric keys in the range [0, array.length]'); 107 | }); 108 | } 109 | 110 | return (0, _reactAddonsUpdate2['default'])(coll, { $apply: function $apply(o) { 111 | return ps.reduce(function (acc, _ref3) { 112 | var _ref32 = _slicedToArray(_ref3, 2); 113 | 114 | var k = _ref32[0]; 115 | var v = _ref32[1]; 116 | acc[k] = v;return acc; 117 | }, o); 118 | } }); 119 | } 120 | 121 | function dissoc(coll) { 122 | for (var _len2 = arguments.length, keys = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 123 | keys[_key2 - 1] = arguments[_key2]; 124 | } 125 | 126 | if (Array.isArray(coll)) { 127 | return (0, _reactAddonsUpdate2['default'])(coll, { $apply: function $apply(a) { 128 | return a.filter(function (v, i) { 129 | return keys.indexOf(i) === -1; 130 | }); 131 | } }); 132 | } else { 133 | return (0, _reactAddonsUpdate2['default'])(coll, { $apply: function $apply(o) { 134 | keys.forEach(function (k) { 135 | return delete o[k]; 136 | }); 137 | return o; 138 | } }); 139 | } 140 | } 141 | 142 | /** 143 | * Thin wrapper over react-addons-update to apply a function at path 144 | * preserving other references. 145 | */ 146 | 147 | function updateIn(rootVal, paths, f) { 148 | for (var _len3 = arguments.length, args = Array(_len3 > 3 ? _len3 - 3 : 0), _key3 = 3; _key3 < _len3; _key3++) { 149 | args[_key3 - 3] = arguments[_key3]; 150 | } 151 | 152 | var ff = function ff(v) { 153 | return f.apply(null, [v].concat(args)); 154 | }; 155 | 156 | var newRootVal; 157 | if (paths.length > 0) { 158 | var command = rootAt(paths, { $apply: ff }); 159 | newRootVal = (0, _reactAddonsUpdate2['default'])(rootVal, command); 160 | } else if (paths.length === 0) { 161 | newRootVal = ff(rootVal); 162 | } 163 | 164 | // would be better to do this valEq check on just the leaf 165 | return (0, _deepEqual2['default'])(rootVal, newRootVal) ? rootVal // preserve === if same value 166 | : newRootVal; 167 | } 168 | 169 | // Helper methods for forming react-addons-update commands. 170 | 171 | /** 172 | * @param leafVal e.g. {$apply: f} 173 | * @param paths e.g. ['x', 'y', 'z'] 174 | * @returns e.g. {x: {y: {z: {$apply: f}}} 175 | */ 176 | function rootAt(paths, leafVal) { 177 | return paths.reduceRight(unDeref, leafVal); 178 | } 179 | 180 | /** 181 | * @param obj e.g {$apply: f} 182 | * @param key e.g. 'foo' 183 | * @returns e.g. {foo: {$apply: f}} 184 | */ 185 | function unDeref(obj, key) { 186 | // aka un-get 187 | var nextObj = {}; 188 | nextObj[key] = obj; 189 | return nextObj; 190 | } 191 | 192 | // Other helper functions 193 | 194 | /** 195 | * 196 | * @param array e.g. [1, 2, 3, 4, 5, 6] 197 | * @returns {Array} e.g. [[1, 2], [3, 4], [5, 6]] 198 | */ 199 | function pairs(array) { 200 | var index = 0; 201 | var pairs = []; 202 | 203 | while (index < array.length) { 204 | pairs.push([array[index++], array[index++]]); 205 | } 206 | 207 | return pairs; 208 | } 209 | 210 | /***/ }, 211 | /* 1 */ 212 | /***/ function(module, exports, __webpack_require__) { 213 | 214 | module.exports = __webpack_require__(2); 215 | 216 | /***/ }, 217 | /* 2 */ 218 | /***/ function(module, exports, __webpack_require__) { 219 | 220 | /* WEBPACK VAR INJECTION */(function(process) {/** 221 | * Copyright 2013-2015, Facebook, Inc. 222 | * All rights reserved. 223 | * 224 | * This source code is licensed under the BSD-style license found in the 225 | * LICENSE file in the root directory of this source tree. An additional grant 226 | * of patent rights can be found in the PATENTS file in the same directory. 227 | * 228 | * @providesModule update 229 | */ 230 | 231 | /* global hasOwnProperty:true */ 232 | 233 | 'use strict'; 234 | 235 | var assign = __webpack_require__(4); 236 | var keyOf = __webpack_require__(5); 237 | var invariant = __webpack_require__(6); 238 | var hasOwnProperty = ({}).hasOwnProperty; 239 | 240 | function shallowCopy(x) { 241 | if (Array.isArray(x)) { 242 | return x.concat(); 243 | } else if (x && typeof x === 'object') { 244 | return assign(new x.constructor(), x); 245 | } else { 246 | return x; 247 | } 248 | } 249 | 250 | var COMMAND_PUSH = keyOf({ $push: null }); 251 | var COMMAND_UNSHIFT = keyOf({ $unshift: null }); 252 | var COMMAND_SPLICE = keyOf({ $splice: null }); 253 | var COMMAND_SET = keyOf({ $set: null }); 254 | var COMMAND_MERGE = keyOf({ $merge: null }); 255 | var COMMAND_APPLY = keyOf({ $apply: null }); 256 | 257 | var ALL_COMMANDS_LIST = [COMMAND_PUSH, COMMAND_UNSHIFT, COMMAND_SPLICE, COMMAND_SET, COMMAND_MERGE, COMMAND_APPLY]; 258 | 259 | var ALL_COMMANDS_SET = {}; 260 | 261 | ALL_COMMANDS_LIST.forEach(function (command) { 262 | ALL_COMMANDS_SET[command] = true; 263 | }); 264 | 265 | function invariantArrayCase(value, spec, command) { 266 | !Array.isArray(value) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): expected target of %s to be an array; got %s.', command, value) : invariant(false) : undefined; 267 | var specValue = spec[command]; 268 | !Array.isArray(specValue) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): expected spec of %s to be an array; got %s. ' + 'Did you forget to wrap your parameter in an array?', command, specValue) : invariant(false) : undefined; 269 | } 270 | 271 | function update(value, spec) { 272 | !(typeof spec === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): You provided a key path to update() that did not contain one ' + 'of %s. Did you forget to include {%s: ...}?', ALL_COMMANDS_LIST.join(', '), COMMAND_SET) : invariant(false) : undefined; 273 | 274 | if (hasOwnProperty.call(spec, COMMAND_SET)) { 275 | !(Object.keys(spec).length === 1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Cannot have more than one key in an object with %s', COMMAND_SET) : invariant(false) : undefined; 276 | 277 | return spec[COMMAND_SET]; 278 | } 279 | 280 | var nextValue = shallowCopy(value); 281 | 282 | if (hasOwnProperty.call(spec, COMMAND_MERGE)) { 283 | var mergeObj = spec[COMMAND_MERGE]; 284 | !(mergeObj && typeof mergeObj === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): %s expects a spec of type \'object\'; got %s', COMMAND_MERGE, mergeObj) : invariant(false) : undefined; 285 | !(nextValue && typeof nextValue === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): %s expects a target of type \'object\'; got %s', COMMAND_MERGE, nextValue) : invariant(false) : undefined; 286 | assign(nextValue, spec[COMMAND_MERGE]); 287 | } 288 | 289 | if (hasOwnProperty.call(spec, COMMAND_PUSH)) { 290 | invariantArrayCase(value, spec, COMMAND_PUSH); 291 | spec[COMMAND_PUSH].forEach(function (item) { 292 | nextValue.push(item); 293 | }); 294 | } 295 | 296 | if (hasOwnProperty.call(spec, COMMAND_UNSHIFT)) { 297 | invariantArrayCase(value, spec, COMMAND_UNSHIFT); 298 | spec[COMMAND_UNSHIFT].forEach(function (item) { 299 | nextValue.unshift(item); 300 | }); 301 | } 302 | 303 | if (hasOwnProperty.call(spec, COMMAND_SPLICE)) { 304 | !Array.isArray(value) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected %s target to be an array; got %s', COMMAND_SPLICE, value) : invariant(false) : undefined; 305 | !Array.isArray(spec[COMMAND_SPLICE]) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): expected spec of %s to be an array of arrays; got %s. ' + 'Did you forget to wrap your parameters in an array?', COMMAND_SPLICE, spec[COMMAND_SPLICE]) : invariant(false) : undefined; 306 | spec[COMMAND_SPLICE].forEach(function (args) { 307 | !Array.isArray(args) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): expected spec of %s to be an array of arrays; got %s. ' + 'Did you forget to wrap your parameters in an array?', COMMAND_SPLICE, spec[COMMAND_SPLICE]) : invariant(false) : undefined; 308 | nextValue.splice.apply(nextValue, args); 309 | }); 310 | } 311 | 312 | if (hasOwnProperty.call(spec, COMMAND_APPLY)) { 313 | !(typeof spec[COMMAND_APPLY] === 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): expected spec of %s to be a function; got %s.', COMMAND_APPLY, spec[COMMAND_APPLY]) : invariant(false) : undefined; 314 | nextValue = spec[COMMAND_APPLY](nextValue); 315 | } 316 | 317 | for (var k in spec) { 318 | if (!(ALL_COMMANDS_SET.hasOwnProperty(k) && ALL_COMMANDS_SET[k])) { 319 | nextValue[k] = update(value[k], spec[k]); 320 | } 321 | } 322 | 323 | return nextValue; 324 | } 325 | 326 | module.exports = update; 327 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) 328 | 329 | /***/ }, 330 | /* 3 */ 331 | /***/ function(module, exports) { 332 | 333 | // shim for using process in browser 334 | 335 | var process = module.exports = {}; 336 | var queue = []; 337 | var draining = false; 338 | var currentQueue; 339 | var queueIndex = -1; 340 | 341 | function cleanUpNextTick() { 342 | draining = false; 343 | if (currentQueue.length) { 344 | queue = currentQueue.concat(queue); 345 | } else { 346 | queueIndex = -1; 347 | } 348 | if (queue.length) { 349 | drainQueue(); 350 | } 351 | } 352 | 353 | function drainQueue() { 354 | if (draining) { 355 | return; 356 | } 357 | var timeout = setTimeout(cleanUpNextTick); 358 | draining = true; 359 | 360 | var len = queue.length; 361 | while(len) { 362 | currentQueue = queue; 363 | queue = []; 364 | while (++queueIndex < len) { 365 | if (currentQueue) { 366 | currentQueue[queueIndex].run(); 367 | } 368 | } 369 | queueIndex = -1; 370 | len = queue.length; 371 | } 372 | currentQueue = null; 373 | draining = false; 374 | clearTimeout(timeout); 375 | } 376 | 377 | process.nextTick = function (fun) { 378 | var args = new Array(arguments.length - 1); 379 | if (arguments.length > 1) { 380 | for (var i = 1; i < arguments.length; i++) { 381 | args[i - 1] = arguments[i]; 382 | } 383 | } 384 | queue.push(new Item(fun, args)); 385 | if (queue.length === 1 && !draining) { 386 | setTimeout(drainQueue, 0); 387 | } 388 | }; 389 | 390 | // v8 likes predictible objects 391 | function Item(fun, array) { 392 | this.fun = fun; 393 | this.array = array; 394 | } 395 | Item.prototype.run = function () { 396 | this.fun.apply(null, this.array); 397 | }; 398 | process.title = 'browser'; 399 | process.browser = true; 400 | process.env = {}; 401 | process.argv = []; 402 | process.version = ''; // empty string to avoid regexp issues 403 | process.versions = {}; 404 | 405 | function noop() {} 406 | 407 | process.on = noop; 408 | process.addListener = noop; 409 | process.once = noop; 410 | process.off = noop; 411 | process.removeListener = noop; 412 | process.removeAllListeners = noop; 413 | process.emit = noop; 414 | 415 | process.binding = function (name) { 416 | throw new Error('process.binding is not supported'); 417 | }; 418 | 419 | process.cwd = function () { return '/' }; 420 | process.chdir = function (dir) { 421 | throw new Error('process.chdir is not supported'); 422 | }; 423 | process.umask = function() { return 0; }; 424 | 425 | 426 | /***/ }, 427 | /* 4 */ 428 | /***/ function(module, exports) { 429 | 430 | /** 431 | * Copyright 2014-2015, Facebook, Inc. 432 | * All rights reserved. 433 | * 434 | * This source code is licensed under the BSD-style license found in the 435 | * LICENSE file in the root directory of this source tree. An additional grant 436 | * of patent rights can be found in the PATENTS file in the same directory. 437 | * 438 | * @providesModule Object.assign 439 | */ 440 | 441 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign 442 | 443 | 'use strict'; 444 | 445 | function assign(target, sources) { 446 | if (target == null) { 447 | throw new TypeError('Object.assign target cannot be null or undefined'); 448 | } 449 | 450 | var to = Object(target); 451 | var hasOwnProperty = Object.prototype.hasOwnProperty; 452 | 453 | for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) { 454 | var nextSource = arguments[nextIndex]; 455 | if (nextSource == null) { 456 | continue; 457 | } 458 | 459 | var from = Object(nextSource); 460 | 461 | // We don't currently support accessors nor proxies. Therefore this 462 | // copy cannot throw. If we ever supported this then we must handle 463 | // exceptions and side-effects. We don't support symbols so they won't 464 | // be transferred. 465 | 466 | for (var key in from) { 467 | if (hasOwnProperty.call(from, key)) { 468 | to[key] = from[key]; 469 | } 470 | } 471 | } 472 | 473 | return to; 474 | } 475 | 476 | module.exports = assign; 477 | 478 | /***/ }, 479 | /* 5 */ 480 | /***/ function(module, exports) { 481 | 482 | /** 483 | * Copyright 2013-2015, Facebook, Inc. 484 | * All rights reserved. 485 | * 486 | * This source code is licensed under the BSD-style license found in the 487 | * LICENSE file in the root directory of this source tree. An additional grant 488 | * of patent rights can be found in the PATENTS file in the same directory. 489 | * 490 | * @providesModule keyOf 491 | */ 492 | 493 | /** 494 | * Allows extraction of a minified key. Let's the build system minify keys 495 | * without losing the ability to dynamically use key strings as values 496 | * themselves. Pass in an object with a single key/val pair and it will return 497 | * you the string key of that single record. Suppose you want to grab the 498 | * value for a key 'className' inside of an object. Key/val minification may 499 | * have aliased that key to be 'xa12'. keyOf({className: null}) will return 500 | * 'xa12' in that case. Resolve keys you want to use once at startup time, then 501 | * reuse those resolutions. 502 | */ 503 | "use strict"; 504 | 505 | var keyOf = function (oneKeyObj) { 506 | var key; 507 | for (key in oneKeyObj) { 508 | if (!oneKeyObj.hasOwnProperty(key)) { 509 | continue; 510 | } 511 | return key; 512 | } 513 | return null; 514 | }; 515 | 516 | module.exports = keyOf; 517 | 518 | /***/ }, 519 | /* 6 */ 520 | /***/ function(module, exports, __webpack_require__) { 521 | 522 | /* WEBPACK VAR INJECTION */(function(process) {/** 523 | * Copyright 2013-2015, Facebook, Inc. 524 | * All rights reserved. 525 | * 526 | * This source code is licensed under the BSD-style license found in the 527 | * LICENSE file in the root directory of this source tree. An additional grant 528 | * of patent rights can be found in the PATENTS file in the same directory. 529 | * 530 | * @providesModule invariant 531 | */ 532 | 533 | 'use strict'; 534 | 535 | /** 536 | * Use invariant() to assert state which your program assumes to be true. 537 | * 538 | * Provide sprintf-style format (only %s is supported) and arguments 539 | * to provide information about what broke and what you were 540 | * expecting. 541 | * 542 | * The invariant message will be stripped in production, but the invariant 543 | * will remain to ensure logic does not differ in production. 544 | */ 545 | 546 | function invariant(condition, format, a, b, c, d, e, f) { 547 | if (process.env.NODE_ENV !== 'production') { 548 | if (format === undefined) { 549 | throw new Error('invariant requires an error message argument'); 550 | } 551 | } 552 | 553 | if (!condition) { 554 | var error; 555 | if (format === undefined) { 556 | error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); 557 | } else { 558 | var args = [a, b, c, d, e, f]; 559 | var argIndex = 0; 560 | error = new Error(format.replace(/%s/g, function () { 561 | return args[argIndex++]; 562 | })); 563 | error.name = 'Invariant Violation'; 564 | } 565 | 566 | error.framesToPop = 1; // we don't care about invariant's own frame 567 | throw error; 568 | } 569 | } 570 | 571 | module.exports = invariant; 572 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) 573 | 574 | /***/ }, 575 | /* 7 */ 576 | /***/ function(module, exports, __webpack_require__) { 577 | 578 | var pSlice = Array.prototype.slice; 579 | var objectKeys = __webpack_require__(8); 580 | var isArguments = __webpack_require__(9); 581 | 582 | var deepEqual = module.exports = function (actual, expected, opts) { 583 | if (!opts) opts = {}; 584 | // 7.1. All identical values are equivalent, as determined by ===. 585 | if (actual === expected) { 586 | return true; 587 | 588 | } else if (actual instanceof Date && expected instanceof Date) { 589 | return actual.getTime() === expected.getTime(); 590 | 591 | // 7.3. Other pairs that do not both pass typeof value == 'object', 592 | // equivalence is determined by ==. 593 | } else if (typeof actual != 'object' && typeof expected != 'object') { 594 | return opts.strict ? actual === expected : actual == expected; 595 | 596 | // 7.4. For all other Object pairs, including Array objects, equivalence is 597 | // determined by having the same number of owned properties (as verified 598 | // with Object.prototype.hasOwnProperty.call), the same set of keys 599 | // (although not necessarily the same order), equivalent values for every 600 | // corresponding key, and an identical 'prototype' property. Note: this 601 | // accounts for both named and indexed properties on Arrays. 602 | } else { 603 | return objEquiv(actual, expected, opts); 604 | } 605 | } 606 | 607 | function isUndefinedOrNull(value) { 608 | return value === null || value === undefined; 609 | } 610 | 611 | function isBuffer (x) { 612 | if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false; 613 | if (typeof x.copy !== 'function' || typeof x.slice !== 'function') { 614 | return false; 615 | } 616 | if (x.length > 0 && typeof x[0] !== 'number') return false; 617 | return true; 618 | } 619 | 620 | function objEquiv(a, b, opts) { 621 | var i, key; 622 | if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) 623 | return false; 624 | // an identical 'prototype' property. 625 | if (a.prototype !== b.prototype) return false; 626 | //~~~I've managed to break Object.keys through screwy arguments passing. 627 | // Converting to array solves the problem. 628 | if (isArguments(a)) { 629 | if (!isArguments(b)) { 630 | return false; 631 | } 632 | a = pSlice.call(a); 633 | b = pSlice.call(b); 634 | return deepEqual(a, b, opts); 635 | } 636 | if (isBuffer(a)) { 637 | if (!isBuffer(b)) { 638 | return false; 639 | } 640 | if (a.length !== b.length) return false; 641 | for (i = 0; i < a.length; i++) { 642 | if (a[i] !== b[i]) return false; 643 | } 644 | return true; 645 | } 646 | try { 647 | var ka = objectKeys(a), 648 | kb = objectKeys(b); 649 | } catch (e) {//happens when one is a string literal and the other isn't 650 | return false; 651 | } 652 | // having the same number of owned properties (keys incorporates 653 | // hasOwnProperty) 654 | if (ka.length != kb.length) 655 | return false; 656 | //the same set of keys (although not necessarily the same order), 657 | ka.sort(); 658 | kb.sort(); 659 | //~~~cheap key test 660 | for (i = ka.length - 1; i >= 0; i--) { 661 | if (ka[i] != kb[i]) 662 | return false; 663 | } 664 | //equivalent values for every corresponding key, and 665 | //~~~possibly expensive deep test 666 | for (i = ka.length - 1; i >= 0; i--) { 667 | key = ka[i]; 668 | if (!deepEqual(a[key], b[key], opts)) return false; 669 | } 670 | return typeof a === typeof b; 671 | } 672 | 673 | 674 | /***/ }, 675 | /* 8 */ 676 | /***/ function(module, exports) { 677 | 678 | exports = module.exports = typeof Object.keys === 'function' 679 | ? Object.keys : shim; 680 | 681 | exports.shim = shim; 682 | function shim (obj) { 683 | var keys = []; 684 | for (var key in obj) keys.push(key); 685 | return keys; 686 | } 687 | 688 | 689 | /***/ }, 690 | /* 9 */ 691 | /***/ function(module, exports) { 692 | 693 | var supportsArgumentsClass = (function(){ 694 | return Object.prototype.toString.call(arguments) 695 | })() == '[object Arguments]'; 696 | 697 | exports = module.exports = supportsArgumentsClass ? supported : unsupported; 698 | 699 | exports.supported = supported; 700 | function supported(object) { 701 | return Object.prototype.toString.call(object) == '[object Arguments]'; 702 | }; 703 | 704 | exports.unsupported = unsupported; 705 | function unsupported(object){ 706 | return object && 707 | typeof object == 'object' && 708 | typeof object.length == 'number' && 709 | Object.prototype.hasOwnProperty.call(object, 'callee') && 710 | !Object.prototype.propertyIsEnumerable.call(object, 'callee') || 711 | false; 712 | }; 713 | 714 | 715 | /***/ } 716 | /******/ ]); 717 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAgMDdiNzA0ZmNjYmUxZjcwMzUxMTkiLCJ3ZWJwYWNrOi8vLy4vc3JjL3VwZGF0ZS1pbi5qcyIsIndlYnBhY2s6Ly8vLi9+L3JlYWN0LWFkZG9ucy11cGRhdGUvaW5kZXguanMiLCJ3ZWJwYWNrOi8vLy4vfi9yZWFjdC9saWIvdXBkYXRlLmpzIiwid2VicGFjazovLy8uL34vcHJvY2Vzcy9icm93c2VyLmpzIiwid2VicGFjazovLy8uL34vcmVhY3QvbGliL09iamVjdC5hc3NpZ24uanMiLCJ3ZWJwYWNrOi8vLy4vfi9mYmpzL2xpYi9rZXlPZi5qcyIsIndlYnBhY2s6Ly8vLi9+L2ZianMvbGliL2ludmFyaWFudC5qcyIsIndlYnBhY2s6Ly8vLi9+L2RlZXAtZXF1YWwvaW5kZXguanMiLCJ3ZWJwYWNrOi8vLy4vfi9kZWVwLWVxdWFsL2xpYi9rZXlzLmpzIiwid2VicGFjazovLy8uL34vZGVlcC1lcXVhbC9saWIvaXNfYXJndW1lbnRzLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSx1QkFBZTtBQUNmO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzhDQ3RDMEMsQ0FBcUI7Ozs7c0NBQzNDLENBQVk7Ozs7QUFHekIsVUFBUyxLQUFLLENBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtBQUMzQixVQUFPLG9DQUFpQixDQUFDLEVBQUUsRUFBQyxNQUFNLEVBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQztFQUN6Qzs7QUFFTSxVQUFTLElBQUksQ0FBRSxFQUFFLEVBQUUsRUFBRSxFQUFFO0FBQzVCLFVBQU8sb0NBQWlCLEVBQUUsRUFBRSxFQUFDLEtBQUssRUFB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QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFlLGNBQWM7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFHLFlBQVk7QUFDZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUF5QixRQUFRO0FBQ2pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBeUIsUUFBUTtBQUNqQztBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7O0FDN0ZBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7O0FDUkE7QUFDQTtBQUNBLEVBQUM7O0FBRUQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6InVwZGF0ZS1pbi5qcyIsInNvdXJjZXNDb250ZW50IjpbIiBcdC8vIFRoZSBtb2R1bGUgY2FjaGVcbiBcdHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XG5cbiBcdC8vIFRoZSByZXF1aXJlIGZ1bmN0aW9uXG4gXHRmdW5jdGlvbiBfX3dlYnBhY2tfcmVxdWlyZV9fKG1vZHVsZUlkKSB7XG5cbiBcdFx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG4gXHRcdGlmKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKVxuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuXG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRleHBvcnRzOiB7fSxcbiBcdFx0XHRpZDogbW9kdWxlSWQsXG4gXHRcdFx0bG9hZGVkOiBmYWxzZVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sb2FkZWQgPSB0cnVlO1xuXG4gXHRcdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG4gXHRcdHJldHVybiBtb2R1bGUuZXhwb3J0cztcbiBcdH1cblxuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZXMgb2JqZWN0IChfX3dlYnBhY2tfbW9kdWxlc19fKVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5tID0gbW9kdWxlcztcblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcbiBcdF9fd2VicGFja19yZXF1aXJlX18uYyA9IGluc3RhbGxlZE1vZHVsZXM7XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIi9zdGF0aWMvXCI7XG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oMCk7XG5cblxuXG4vKiogV0VCUEFDSyBGT09URVIgKipcbiAqKiB3ZWJwYWNrL2Jvb3RzdHJhcCAwN2I3MDRmY2NiZTFmNzAzNTExOVxuICoqLyIsImltcG9ydCB7ZGVmYXVsdCBhcyBwZXJzaXN0ZW50VXBkYXRlfSBmcm9tICdyZWFjdC1hZGRvbnMtdXBkYXRlJztcbmltcG9ydCBpc0VxdWFsIGZyb20gJ2RlZXAtZXF1YWwnO1xuXG5cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZSAoYSwgYikge1xuICByZXR1cm4gcGVyc2lzdGVudFVwZGF0ZShhLCB7JG1lcmdlOiBifSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwdXNoIChhcywgYnMpIHtcbiAgcmV0dXJuIHBlcnNpc3RlbnRVcGRhdGUoYXMsIHskcHVzaDogYnN9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHVuc2hpZnQgKGFzLCBicykge1xuICByZXR1cm4gcGVyc2lzdGVudFVwZGF0ZShhcywgeyR1bnNoaWZ0OiBic30pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc3BsaWNlIChhcywgc3BsaWNlcykge1xuICAvLyBwZXJzaXN0ZW50VXBkYXRlKFsxMiwgMTcsIDE1XSwgeyRzcGxpY2U6IFtbMSwgMSwgMTMsIDE0XV19KSA9PiBbMTIsIDEzLCAxNCwgMTVdXG4gIHJldHVybiBwZXJzaXN0ZW50VXBkYXRlKGFzLCB7JHNwbGljZTogc3BsaWNlc30pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gYXNzb2MoY29sbCwgLi4ua3ZzKSB7XG4gIGlmIChrdnMubGVuZ3RoICUgMiAhPT0gMCkgdGhyb3cgbmV3IEVycm9yKCdhc3NvYyBleHBlY3RzIGFuIGV2ZW4gbnVtYmVyIG9mIGFyZ3VtZW50cycpO1xuICBjb25zdCBwcyA9IHBhaXJzKGt2cyk7XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkoY29sbCkpIHtcbiAgICBwcy5mb3JFYWNoKChbaywgdl0pID0+IHtcbiAgICAgIGlmICghICh0eXBlb2YgayA9PT0gJ251bWJlcicgJiYgcGFyc2VJbnQoaywgMTApID09PSBrKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignYXNzb2MgZXhwZWN0cyBvbmx5IGludGVnZXIga2V5cycpO1xuICAgICAgaWYgKGsgPCAwIHx8IGsgPiBjb2xsLmxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2Fzc29jIGV4cGVjdHMgb25seSBudW1lcmljIGtleXMgaW4gdGhlIHJhbmdlIFswLCBhcnJheS5sZW5ndGhdJyk7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gcGVyc2lzdGVudFVwZGF0ZShjb2xsLCB7JGFwcGx5OiBvID0+IHBzLnJlZHVjZSgoYWNjLCBbaywgdl0pID0+IHsgYWNjW2tdID0gdjsgcmV0dXJuIGFjYzsgfSwgbyl9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRpc3NvYyAoY29sbCwgLi4ua2V5cykge1xuICBpZiAoQXJyYXkuaXNBcnJheShjb2xsKSkge1xuICAgIHJldHVybiBwZXJzaXN0ZW50VXBkYXRlKGNvbGwsIHskYXBwbHk6IGEgPT4gYS5maWx0ZXIoKHYsaSkgPT4ga2V5cy5pbmRleE9mKGkpID09PSAtMSl9KTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gcGVyc2lzdGVudFVwZGF0ZShjb2xsLCB7JGFwcGx5OiBvID0+IHtcbiAgICAgIGtleXMuZm9yRWFjaChrID0+IGRlbGV0ZSBvW2tdKTtcbiAgICAgIHJldHVybiBvO1xuICAgIH19KTtcbiAgfVxufVxuXG4vKipcbiAqIFRoaW4gd3JhcHBlciBvdmVyIHJlYWN0LWFkZG9ucy11cGRhdGUgdG8gYXBwbHkgYSBmdW5jdGlvbiBhdCBwYXRoXG4gKiBwcmVzZXJ2aW5nIG90aGVyIHJlZmVyZW5jZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVJbiAocm9vdFZhbCwgcGF0aHMsIGYsIC4uLmFyZ3MpIHtcbiAgbGV0IGZmID0gKHYpID0+IGYuYXBwbHkobnVsbCwgW3ZdLmNvbmNhdChhcmdzKSk7XG5cbiAgdmFyIG5ld1Jvb3RWYWw7XG4gIGlmIChwYXRocy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3QgY29tbWFuZCA9IHJvb3RBdChwYXRocywgeyRhcHBseTogZmZ9KTtcbiAgICBuZXdSb290VmFsID0gcGVyc2lzdGVudFVwZGF0ZShyb290VmFsLCBjb21tYW5kKTtcbiAgfVxuICBlbHNlIGlmIChwYXRocy5sZW5ndGggPT09IDApIHtcbiAgICBuZXdSb290VmFsID0gZmYocm9vdFZhbCk7XG4gIH1cblxuICAvLyB3b3VsZCBiZSBiZXR0ZXIgdG8gZG8gdGhpcyB2YWxFcSBjaGVjayBvbiBqdXN0IHRoZSBsZWFmXG4gIHJldHVybiBpc0VxdWFsKHJvb3RWYWwsIG5ld1Jvb3RWYWwpXG4gICAgICA/IHJvb3RWYWwgLy8gcHJlc2VydmUgPT09IGlmIHNhbWUgdmFsdWVcbiAgICAgIDogbmV3Um9vdFZhbDtcbn1cblxuXG5cbi8vIEhlbHBlciBtZXRob2RzIGZvciBmb3JtaW5nIHJlYWN0LWFkZG9ucy11cGRhdGUgY29tbWFuZHMuXG5cbi8qKlxuICogQHBhcmFtIGxlYWZWYWwgZS5nLiB7JGFwcGx5OiBmfVxuICogQHBhcmFtIHBhdGhzIGUuZy4gWyd4JywgJ3knLCAneiddXG4gKiBAcmV0dXJucyBlLmcuIHt4OiB7eToge3o6IHskYXBwbHk6IGZ9fX1cbiAqL1xuZnVuY3Rpb24gcm9vdEF0IChwYXRocywgbGVhZlZhbCkge1xuICByZXR1cm4gcGF0aHMucmVkdWNlUmlnaHQodW5EZXJlZiwgbGVhZlZhbClcbn1cblxuXG4vKipcbiAqIEBwYXJhbSBvYmogZS5nIHskYXBwbHk6IGZ9XG4gKiBAcGFyYW0ga2V5IGUuZy4gJ2ZvbydcbiAqIEByZXR1cm5zIGUuZy4ge2ZvbzogeyRhcHBseTogZn19XG4gKi9cbmZ1bmN0aW9uIHVuRGVyZWYob2JqLCBrZXkpIHsgLy8gYWthIHVuLWdldFxuICB2YXIgbmV4dE9iaiA9IHt9O1xuICBuZXh0T2JqW2tleV0gPSBvYmo7XG4gIHJldHVybiBuZXh0T2JqO1xufVxuXG4vLyBPdGhlciBoZWxwZXIgZnVuY3Rpb25zXG5cbi8qKlxuICpcbiAqIEBwYXJhbSBhcnJheSBlLmcuIFsxLCAyLCAzLCA0LCA1LCA2XVxuICogQHJldHVybnMge0FycmF5fSBlLmcuIFtbMSwgMl0sIFszLCA0XSwgWzUsIDZdXVxuICovXG5mdW5jdGlvbiBwYWlycyAoYXJyYXkpIHtcbiAgbGV0IGluZGV4ID0gMDtcbiAgbGV0IHBhaXJzID0gW107XG5cbiAgd2hpbGUgKGluZGV4IDwgYXJyYXkubGVuZ3RoKSB7XG4gICAgcGFpcnMucHVzaChbYXJyYXlbaW5kZXgrK10sIGFycmF5W2luZGV4KytdXSk7XG4gIH1cblxuICByZXR1cm4gIHBhaXJzO1xufVxuXG5cblxuLyoqIFdFQlBBQ0sgRk9PVEVSICoqXG4gKiogLi9zcmMvdXBkYXRlLWluLmpzXG4gKiovIiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCdyZWFjdC9saWIvdXBkYXRlJyk7XG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiAuL34vcmVhY3QtYWRkb25zLXVwZGF0ZS9pbmRleC5qc1xuICoqIG1vZHVsZSBpZCA9IDFcbiAqKiBtb2R1bGUgY2h1bmtzID0gMFxuICoqLyIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNSwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSB1cGRhdGVcbiAqL1xuXG4vKiBnbG9iYWwgaGFzT3duUHJvcGVydHk6dHJ1ZSAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKCcuL09iamVjdC5hc3NpZ24nKTtcbnZhciBrZXlPZiA9IHJlcXVpcmUoJ2ZianMvbGliL2tleU9mJyk7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZSgnZmJqcy9saWIvaW52YXJpYW50Jyk7XG52YXIgaGFzT3duUHJvcGVydHkgPSAoe30pLmhhc093blByb3BlcnR5O1xuXG5mdW5jdGlvbiBzaGFsbG93Q29weSh4KSB7XG4gIGlmIChBcnJheS5pc0FycmF5KHgpKSB7XG4gICAgcmV0dXJuIHguY29uY2F0KCk7XG4gIH0gZWxzZSBpZiAoeCAmJiB0eXBlb2YgeCA9PT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gYXNzaWduKG5ldyB4LmNvbnN0cnVjdG9yKCksIHgpO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiB4O1xuICB9XG59XG5cbnZhciBDT01NQU5EX1BVU0ggPSBrZXlPZih7ICRwdXNoOiBudWxsIH0pO1xudmFyIENPTU1BTkRfVU5TSElGVCA9IGtleU9mKHsgJHVuc2hpZnQ6IG51bGwgfSk7XG52YXIgQ09NTUFORF9TUExJQ0UgPSBrZXlPZih7ICRzcGxpY2U6IG51bGwgfSk7XG52YXIgQ09NTUFORF9TRVQgPSBrZXlPZih7ICRzZXQ6IG51bGwgfSk7XG52YXIgQ09NTUFORF9NRVJHRSA9IGtleU9mKHsgJG1lcmdlOiBudWxsIH0pO1xudmFyIENPTU1BTkRfQVBQTFkgPSBrZXlPZih7ICRhcHBseTogbnVsbCB9KTtcblxudmFyIEFMTF9DT01NQU5EU19MSVNUID0gW0NPTU1BTkRfUFVTSCwgQ09NTUFORF9VTlNISUZULCBDT01NQU5EX1NQTElDRSwgQ09NTUFORF9TRVQsIENPTU1BTkRfTUVSR0UsIENPTU1BTkRfQVBQTFldO1xuXG52YXIgQUxMX0NPTU1BTkRTX1NFVCA9IHt9O1xuXG5BTExfQ09NTUFORFNfTElTVC5mb3JFYWNoKGZ1bmN0aW9uIChjb21tYW5kKSB7XG4gIEFMTF9DT01NQU5EU19TRVRbY29tbWFuZF0gPSB0cnVlO1xufSk7XG5cbmZ1bmN0aW9uIGludmFyaWFudEFycmF5Q2FzZSh2YWx1ZSwgc3BlYywgY29tbWFuZCkge1xuICAhQXJyYXkuaXNBcnJheSh2YWx1ZSkgPyBwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nID8gaW52YXJpYW50KGZhbHNlLCAndXBkYXRlKCk6IGV4cGVjdGVkIHRhcmdldCBvZiAlcyB0byBiZSBhbiBhcnJheTsgZ290ICVzLicsIGNvbW1hbmQsIHZhbHVlKSA6IGludmFyaWFudChmYWxzZSkgOiB1bmRlZmluZWQ7XG4gIHZhciBzcGVjVmFsdWUgPSBzcGVjW2NvbW1hbmRdO1xuICAhQXJyYXkuaXNBcnJheShzcGVjVmFsdWUpID8gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJyA/IGludmFyaWFudChmYWxzZSwgJ3VwZGF0ZSgpOiBleHBlY3RlZCBzcGVjIG9mICVzIHRvIGJlIGFuIGFycmF5OyBnb3QgJXMuICcgKyAnRGlkIHlvdSBmb3JnZXQgdG8gd3JhcCB5b3VyIHBhcmFtZXRlciBpbiBhbiBhcnJheT8nLCBjb21tYW5kLCBzcGVjVmFsdWUpIDogaW52YXJpYW50KGZhbHNlKSA6IHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gdXBkYXRlKHZhbHVlLCBzcGVjKSB7XG4gICEodHlwZW9mIHNwZWMgPT09ICdvYmplY3QnKSA/IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicgPyBpbnZhcmlhbnQoZmFsc2UsICd1cGRhdGUoKTogWW91IHByb3ZpZGVkIGEga2V5IHBhdGggdG8gdXBkYXRlKCkgdGhhdCBkaWQgbm90IGNvbnRhaW4gb25lICcgKyAnb2YgJXMuIERpZCB5b3UgZm9yZ2V0IHRvIGluY2x1ZGUgeyVzOiAuLi59PycsIEFMTF9DT01NQU5EU19MSVNULmpvaW4oJywgJyksIENPTU1BTkRfU0VUKSA6IGludmFyaWFudChmYWxzZSkgOiB1bmRlZmluZWQ7XG5cbiAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoc3BlYywgQ09NTUFORF9TRVQpKSB7XG4gICAgIShPYmplY3Qua2V5cyhzcGVjKS5sZW5ndGggPT09IDEpID8gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJyA/IGludmFyaWFudChmYWxzZSwgJ0Nhbm5vdCBoYXZlIG1vcmUgdGhhbiBvbmUga2V5IGluIGFuIG9iamVjdCB3aXRoICVzJywgQ09NTUFORF9TRVQpIDogaW52YXJpYW50KGZhbHNlKSA6IHVuZGVmaW5lZDtcblxuICAgIHJldHVybiBzcGVjW0NPTU1BTkRfU0VUXTtcbiAgfVxuXG4gIHZhciBuZXh0VmFsdWUgPSBzaGFsbG93Q29weSh2YWx1ZSk7XG5cbiAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoc3BlYywgQ09NTUFORF9NRVJHRSkpIHtcbiAgICB2YXIgbWVyZ2VPYmogPSBzcGVjW0NPTU1BTkRfTUVSR0VdO1xuICAgICEobWVyZ2VPYmogJiYgdHlwZW9mIG1lcmdlT2JqID09PSAnb2JqZWN0JykgPyBwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nID8gaW52YXJpYW50KGZhbHNlLCAndXBkYXRlKCk6ICVzIGV4cGVjdHMgYSBzcGVjIG9mIHR5cGUgXFwnb2JqZWN0XFwnOyBnb3QgJXMnLCBDT01NQU5EX01FUkdFLCBtZXJnZU9iaikgOiBpbnZhcmlhbnQoZmFsc2UpIDogdW5kZWZpbmVkO1xuICAgICEobmV4dFZhbHVlICYmIHR5cGVvZiBuZXh0VmFsdWUgPT09ICdvYmplY3QnKSA/IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicgPyBpbnZhcmlhbnQoZmFsc2UsICd1cGRhdGUoKTogJXMgZXhwZWN0cyBhIHRhcmdldCBvZiB0eXBlIFxcJ29iamVjdFxcJzsgZ290ICVzJywgQ09NTUFORF9NRVJHRSwgbmV4dFZhbHVlKSA6IGludmFyaWFudChmYWxzZSkgOiB1bmRlZmluZWQ7XG4gICAgYXNzaWduKG5leHRWYWx1ZSwgc3BlY1tDT01NQU5EX01FUkdFXSk7XG4gIH1cblxuICBpZiAoaGFzT3duUHJvcGVydHkuY2FsbChzcGVjLCBDT01NQU5EX1BVU0gpKSB7XG4gICAgaW52YXJpYW50QXJyYXlDYXNlKHZhbHVlLCBzcGVjLCBDT01NQU5EX1BVU0gpO1xuICAgIHNwZWNbQ09NTUFORF9QVVNIXS5mb3JFYWNoKGZ1bmN0aW9uIChpdGVtKSB7XG4gICAgICBuZXh0VmFsdWUucHVzaChpdGVtKTtcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChoYXNPd25Qcm9wZXJ0eS5jYWxsKHNwZWMsIENPTU1BTkRfVU5TSElGVCkpIHtcbiAgICBpbnZhcmlhbnRBcnJheUNhc2UodmFsdWUsIHNwZWMsIENPTU1BTkRfVU5TSElGVCk7XG4gICAgc3BlY1tDT01NQU5EX1VOU0hJRlRdLmZvckVhY2goZnVuY3Rpb24gKGl0ZW0pIHtcbiAgICAgIG5leHRWYWx1ZS51bnNoaWZ0KGl0ZW0pO1xuICAgIH0pO1xuICB9XG5cbiAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoc3BlYywgQ09NTUFORF9TUExJQ0UpKSB7XG4gICAgIUFycmF5LmlzQXJyYXkodmFsdWUpID8gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJyA/IGludmFyaWFudChmYWxzZSwgJ0V4cGVjdGVkICVzIHRhcmdldCB0byBiZSBhbiBhcnJheTsgZ290ICVzJywgQ09NTUFORF9TUExJQ0UsIHZhbHVlKSA6IGludmFyaWFudChmYWxzZSkgOiB1bmRlZmluZWQ7XG4gICAgIUFycmF5LmlzQXJyYXkoc3BlY1tDT01NQU5EX1NQTElDRV0pID8gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJyA/IGludmFyaWFudChmYWxzZSwgJ3VwZGF0ZSgpOiBleHBlY3RlZCBzcGVjIG9mICVzIHRvIGJlIGFuIGFycmF5IG9mIGFycmF5czsgZ290ICVzLiAnICsgJ0RpZCB5b3UgZm9yZ2V0IHRvIHdyYXAgeW91ciBwYXJhbWV0ZXJzIGluIGFuIGFycmF5PycsIENPTU1BTkRfU1BMSUNFLCBzcGVjW0NPTU1BTkRfU1BMSUNFXSkgOiBpbnZhcmlhbnQoZmFsc2UpIDogdW5kZWZpbmVkO1xuICAgIHNwZWNbQ09NTUFORF9TUExJQ0VdLmZvckVhY2goZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICAgICFBcnJheS5pc0FycmF5KGFyZ3MpID8gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJyA/IGludmFyaWFudChmYWxzZSwgJ3VwZGF0ZSgpOiBleHBlY3RlZCBzcGVjIG9mICVzIHRvIGJlIGFuIGFycmF5IG9mIGFycmF5czsgZ290ICVzLiAnICsgJ0RpZCB5b3UgZm9yZ2V0IHRvIHdyYXAgeW91ciBwYXJhbWV0ZXJzIGluIGFuIGFycmF5PycsIENPTU1BTkRfU1BMSUNFLCBzcGVjW0NPTU1BTkRfU1BMSUNFXSkgOiBpbnZhcmlhbnQoZmFsc2UpIDogdW5kZWZpbmVkO1xuICAgICAgbmV4dFZhbHVlLnNwbGljZS5hcHBseShuZXh0VmFsdWUsIGFyZ3MpO1xuICAgIH0pO1xuICB9XG5cbiAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoc3BlYywgQ09NTUFORF9BUFBMWSkpIHtcbiAgICAhKHR5cGVvZiBzcGVjW0NPTU1BTkRfQVBQTFldID09PSAnZnVuY3Rpb24nKSA/IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicgPyBpbnZhcmlhbnQoZmFsc2UsICd1cGRhdGUoKTogZXhwZWN0ZWQgc3BlYyBvZiAlcyB0byBiZSBhIGZ1bmN0aW9uOyBnb3QgJXMuJywgQ09NTUFORF9BUFBMWSwgc3BlY1tDT01NQU5EX0FQUExZXSkgOiBpbnZhcmlhbnQoZmFsc2UpIDogdW5kZWZpbmVkO1xuICAgIG5leHRWYWx1ZSA9IHNwZWNbQ09NTUFORF9BUFBMWV0obmV4dFZhbHVlKTtcbiAgfVxuXG4gIGZvciAodmFyIGsgaW4gc3BlYykge1xuICAgIGlmICghKEFMTF9DT01NQU5EU19TRVQuaGFzT3duUHJvcGVydHkoaykgJiYgQUxMX0NPTU1BTkRTX1NFVFtrXSkpIHtcbiAgICAgIG5leHRWYWx1ZVtrXSA9IHVwZGF0ZSh2YWx1ZVtrXSwgc3BlY1trXSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG5leHRWYWx1ZTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB1cGRhdGU7XG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiAuL34vcmVhY3QvbGliL3VwZGF0ZS5qc1xuICoqIG1vZHVsZSBpZCA9IDJcbiAqKiBtb2R1bGUgY2h1bmtzID0gMFxuICoqLyIsIi8vIHNoaW0gZm9yIHVzaW5nIHByb2Nlc3MgaW4gYnJvd3NlclxuXG52YXIgcHJvY2VzcyA9IG1vZHVsZS5leHBvcnRzID0ge307XG52YXIgcXVldWUgPSBbXTtcbnZhciBkcmFpbmluZyA9IGZhbHNlO1xudmFyIGN1cnJlbnRRdWV1ZTtcbnZhciBxdWV1ZUluZGV4ID0gLTE7XG5cbmZ1bmN0aW9uIGNsZWFuVXBOZXh0VGljaygpIHtcbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIGlmIChjdXJyZW50UXVldWUubGVuZ3RoKSB7XG4gICAgICAgIHF1ZXVlID0gY3VycmVudFF1ZXVlLmNvbmNhdChxdWV1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgIH1cbiAgICBpZiAocXVldWUubGVuZ3RoKSB7XG4gICAgICAgIGRyYWluUXVldWUoKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGRyYWluUXVldWUoKSB7XG4gICAgaWYgKGRyYWluaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGNsZWFuVXBOZXh0VGljayk7XG4gICAgZHJhaW5pbmcgPSB0cnVlO1xuXG4gICAgdmFyIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB3aGlsZShsZW4pIHtcbiAgICAgICAgY3VycmVudFF1ZXVlID0gcXVldWU7XG4gICAgICAgIHF1ZXVlID0gW107XG4gICAgICAgIHdoaWxlICgrK3F1ZXVlSW5kZXggPCBsZW4pIHtcbiAgICAgICAgICAgIGlmIChjdXJyZW50UXVldWUpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50UXVldWVbcXVldWVJbmRleF0ucnVuKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgICAgICBsZW4gPSBxdWV1ZS5sZW5ndGg7XG4gICAgfVxuICAgIGN1cnJlbnRRdWV1ZSA9IG51bGw7XG4gICAgZHJhaW5pbmcgPSBmYWxzZTtcbiAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG59XG5cbnByb2Nlc3MubmV4dFRpY2sgPSBmdW5jdGlvbiAoZnVuKSB7XG4gICAgdmFyIGFyZ3MgPSBuZXcgQXJyYXkoYXJndW1lbnRzLmxlbmd0aCAtIDEpO1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgYXJnc1tpIC0gMV0gPSBhcmd1bWVudHNbaV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcXVldWUucHVzaChuZXcgSXRlbShmdW4sIGFyZ3MpKTtcbiAgICBpZiAocXVldWUubGVuZ3RoID09PSAxICYmICFkcmFpbmluZykge1xuICAgICAgICBzZXRUaW1lb3V0KGRyYWluUXVldWUsIDApO1xuICAgIH1cbn07XG5cbi8vIHY4IGxpa2VzIHByZWRpY3RpYmxlIG9iamVjdHNcbmZ1bmN0aW9uIEl0ZW0oZnVuLCBhcnJheSkge1xuICAgIHRoaXMuZnVuID0gZnVuO1xuICAgIHRoaXMuYXJyYXkgPSBhcnJheTtcbn1cbkl0ZW0ucHJvdG90eXBlLnJ1biA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZ1bi5hcHBseShudWxsLCB0aGlzLmFycmF5KTtcbn07XG5wcm9jZXNzLnRpdGxlID0gJ2Jyb3dzZXInO1xucHJvY2Vzcy5icm93c2VyID0gdHJ1ZTtcbnByb2Nlc3MuZW52ID0ge307XG5wcm9jZXNzLmFyZ3YgPSBbXTtcbnByb2Nlc3MudmVyc2lvbiA9ICcnOyAvLyBlbXB0eSBzdHJpbmcgdG8gYXZvaWQgcmVnZXhwIGlzc3Vlc1xucHJvY2Vzcy52ZXJzaW9ucyA9IHt9O1xuXG5mdW5jdGlvbiBub29wKCkge31cblxucHJvY2Vzcy5vbiA9IG5vb3A7XG5wcm9jZXNzLmFkZExpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3Mub25jZSA9IG5vb3A7XG5wcm9jZXNzLm9mZiA9IG5vb3A7XG5wcm9jZXNzLnJlbW92ZUxpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlQWxsTGlzdGVuZXJzID0gbm9vcDtcbnByb2Nlc3MuZW1pdCA9IG5vb3A7XG5cbnByb2Nlc3MuYmluZGluZyA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmJpbmRpbmcgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcblxucHJvY2Vzcy5jd2QgPSBmdW5jdGlvbiAoKSB7IHJldHVybiAnLycgfTtcbnByb2Nlc3MuY2hkaXIgPSBmdW5jdGlvbiAoZGlyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmNoZGlyIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG5wcm9jZXNzLnVtYXNrID0gZnVuY3Rpb24oKSB7IHJldHVybiAwOyB9O1xuXG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiAuL34vcHJvY2Vzcy9icm93c2VyLmpzXG4gKiogbW9kdWxlIGlkID0gM1xuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxNC0yMDE1LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIE9iamVjdC5hc3NpZ25cbiAqL1xuXG4vLyBodHRwczovL3Blb3BsZS5tb3ppbGxhLm9yZy9+am9yZW5kb3JmZi9lczYtZHJhZnQuaHRtbCNzZWMtb2JqZWN0LmFzc2lnblxuXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGFzc2lnbih0YXJnZXQsIHNvdXJjZXMpIHtcbiAgaWYgKHRhcmdldCA9PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignT2JqZWN0LmFzc2lnbiB0YXJnZXQgY2Fubm90IGJlIG51bGwgb3IgdW5kZWZpbmVkJyk7XG4gIH1cblxuICB2YXIgdG8gPSBPYmplY3QodGFyZ2V0KTtcbiAgdmFyIGhhc093blByb3BlcnR5ID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtcblxuICBmb3IgKHZhciBuZXh0SW5kZXggPSAxOyBuZXh0SW5kZXggPCBhcmd1bWVudHMubGVuZ3RoOyBuZXh0SW5kZXgrKykge1xuICAgIHZhciBuZXh0U291cmNlID0gYXJndW1lbnRzW25leHRJbmRleF07XG4gICAgaWYgKG5leHRTb3VyY2UgPT0gbnVsbCkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgdmFyIGZyb20gPSBPYmplY3QobmV4dFNvdXJjZSk7XG5cbiAgICAvLyBXZSBkb24ndCBjdXJyZW50bHkgc3VwcG9ydCBhY2Nlc3NvcnMgbm9yIHByb3hpZXMuIFRoZXJlZm9yZSB0aGlzXG4gICAgLy8gY29weSBjYW5ub3QgdGhyb3cuIElmIHdlIGV2ZXIgc3VwcG9ydGVkIHRoaXMgdGhlbiB3ZSBtdXN0IGhhbmRsZVxuICAgIC8vIGV4Y2VwdGlvbnMgYW5kIHNpZGUtZWZmZWN0cy4gV2UgZG9uJ3Qgc3VwcG9ydCBzeW1ib2xzIHNvIHRoZXkgd29uJ3RcbiAgICAvLyBiZSB0cmFuc2ZlcnJlZC5cblxuICAgIGZvciAodmFyIGtleSBpbiBmcm9tKSB7XG4gICAgICBpZiAoaGFzT3duUHJvcGVydHkuY2FsbChmcm9tLCBrZXkpKSB7XG4gICAgICAgIHRvW2tleV0gPSBmcm9tW2tleV07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRvO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGFzc2lnbjtcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIC4vfi9yZWFjdC9saWIvT2JqZWN0LmFzc2lnbi5qc1xuICoqIG1vZHVsZSBpZCA9IDRcbiAqKiBtb2R1bGUgY2h1bmtzID0gMFxuICoqLyIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNSwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBrZXlPZlxuICovXG5cbi8qKlxuICogQWxsb3dzIGV4dHJhY3Rpb24gb2YgYSBtaW5pZmllZCBrZXkuIExldCdzIHRoZSBidWlsZCBzeXN0ZW0gbWluaWZ5IGtleXNcbiAqIHdpdGhvdXQgbG9zaW5nIHRoZSBhYmlsaXR5IHRvIGR5bmFtaWNhbGx5IHVzZSBrZXkgc3RyaW5ncyBhcyB2YWx1ZXNcbiAqIHRoZW1zZWx2ZXMuIFBhc3MgaW4gYW4gb2JqZWN0IHdpdGggYSBzaW5nbGUga2V5L3ZhbCBwYWlyIGFuZCBpdCB3aWxsIHJldHVyblxuICogeW91IHRoZSBzdHJpbmcga2V5IG9mIHRoYXQgc2luZ2xlIHJlY29yZC4gU3VwcG9zZSB5b3Ugd2FudCB0byBncmFiIHRoZVxuICogdmFsdWUgZm9yIGEga2V5ICdjbGFzc05hbWUnIGluc2lkZSBvZiBhbiBvYmplY3QuIEtleS92YWwgbWluaWZpY2F0aW9uIG1heVxuICogaGF2ZSBhbGlhc2VkIHRoYXQga2V5IHRvIGJlICd4YTEyJy4ga2V5T2Yoe2NsYXNzTmFtZTogbnVsbH0pIHdpbGwgcmV0dXJuXG4gKiAneGExMicgaW4gdGhhdCBjYXNlLiBSZXNvbHZlIGtleXMgeW91IHdhbnQgdG8gdXNlIG9uY2UgYXQgc3RhcnR1cCB0aW1lLCB0aGVuXG4gKiByZXVzZSB0aG9zZSByZXNvbHV0aW9ucy5cbiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBrZXlPZiA9IGZ1bmN0aW9uIChvbmVLZXlPYmopIHtcbiAgdmFyIGtleTtcbiAgZm9yIChrZXkgaW4gb25lS2V5T2JqKSB7XG4gICAgaWYgKCFvbmVLZXlPYmouaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHJldHVybiBrZXk7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGtleU9mO1xuXG5cbi8qKioqKioqKioqKioqKioqKlxuICoqIFdFQlBBQ0sgRk9PVEVSXG4gKiogLi9+L2ZianMvbGliL2tleU9mLmpzXG4gKiogbW9kdWxlIGlkID0gNVxuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE1LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGludmFyaWFudFxuICovXG5cbid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiBVc2UgaW52YXJpYW50KCkgdG8gYXNzZXJ0IHN0YXRlIHdoaWNoIHlvdXIgcHJvZ3JhbSBhc3N1bWVzIHRvIGJlIHRydWUuXG4gKlxuICogUHJvdmlkZSBzcHJpbnRmLXN0eWxlIGZvcm1hdCAob25seSAlcyBpcyBzdXBwb3J0ZWQpIGFuZCBhcmd1bWVudHNcbiAqIHRvIHByb3ZpZGUgaW5mb3JtYXRpb24gYWJvdXQgd2hhdCBicm9rZSBhbmQgd2hhdCB5b3Ugd2VyZVxuICogZXhwZWN0aW5nLlxuICpcbiAqIFRoZSBpbnZhcmlhbnQgbWVzc2FnZSB3aWxsIGJlIHN0cmlwcGVkIGluIHByb2R1Y3Rpb24sIGJ1dCB0aGUgaW52YXJpYW50XG4gKiB3aWxsIHJlbWFpbiB0byBlbnN1cmUgbG9naWMgZG9lcyBub3QgZGlmZmVyIGluIHByb2R1Y3Rpb24uXG4gKi9cblxuZnVuY3Rpb24gaW52YXJpYW50KGNvbmRpdGlvbiwgZm9ybWF0LCBhLCBiLCBjLCBkLCBlLCBmKSB7XG4gIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gICAgaWYgKGZvcm1hdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFyaWFudCByZXF1aXJlcyBhbiBlcnJvciBtZXNzYWdlIGFyZ3VtZW50Jyk7XG4gICAgfVxuICB9XG5cbiAgaWYgKCFjb25kaXRpb24pIHtcbiAgICB2YXIgZXJyb3I7XG4gICAgaWYgKGZvcm1hdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBlcnJvciA9IG5ldyBFcnJvcignTWluaWZpZWQgZXhjZXB0aW9uIG9jY3VycmVkOyB1c2UgdGhlIG5vbi1taW5pZmllZCBkZXYgZW52aXJvbm1lbnQgJyArICdmb3IgdGhlIGZ1bGwgZXJyb3IgbWVzc2FnZSBhbmQgYWRkaXRpb25hbCBoZWxwZnVsIHdhcm5pbmdzLicpO1xuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgYXJncyA9IFthLCBiLCBjLCBkLCBlLCBmXTtcbiAgICAgIHZhciBhcmdJbmRleCA9IDA7XG4gICAgICBlcnJvciA9IG5ldyBFcnJvcihmb3JtYXQucmVwbGFjZSgvJXMvZywgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYXJnc1thcmdJbmRleCsrXTtcbiAgICAgIH0pKTtcbiAgICAgIGVycm9yLm5hbWUgPSAnSW52YXJpYW50IFZpb2xhdGlvbic7XG4gICAgfVxuXG4gICAgZXJyb3IuZnJhbWVzVG9Qb3AgPSAxOyAvLyB3ZSBkb24ndCBjYXJlIGFib3V0IGludmFyaWFudCdzIG93biBmcmFtZVxuICAgIHRocm93IGVycm9yO1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaW52YXJpYW50O1xuXG5cbi8qKioqKioqKioqKioqKioqKlxuICoqIFdFQlBBQ0sgRk9PVEVSXG4gKiogLi9+L2ZianMvbGliL2ludmFyaWFudC5qc1xuICoqIG1vZHVsZSBpZCA9IDZcbiAqKiBtb2R1bGUgY2h1bmtzID0gMFxuICoqLyIsInZhciBwU2xpY2UgPSBBcnJheS5wcm90b3R5cGUuc2xpY2U7XG52YXIgb2JqZWN0S2V5cyA9IHJlcXVpcmUoJy4vbGliL2tleXMuanMnKTtcbnZhciBpc0FyZ3VtZW50cyA9IHJlcXVpcmUoJy4vbGliL2lzX2FyZ3VtZW50cy5qcycpO1xuXG52YXIgZGVlcEVxdWFsID0gbW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYWN0dWFsLCBleHBlY3RlZCwgb3B0cykge1xuICBpZiAoIW9wdHMpIG9wdHMgPSB7fTtcbiAgLy8gNy4xLiBBbGwgaWRlbnRpY2FsIHZhbHVlcyBhcmUgZXF1aXZhbGVudCwgYXMgZGV0ZXJtaW5lZCBieSA9PT0uXG4gIGlmIChhY3R1YWwgPT09IGV4cGVjdGVkKSB7XG4gICAgcmV0dXJuIHRydWU7XG5cbiAgfSBlbHNlIGlmIChhY3R1YWwgaW5zdGFuY2VvZiBEYXRlICYmIGV4cGVjdGVkIGluc3RhbmNlb2YgRGF0ZSkge1xuICAgIHJldHVybiBhY3R1YWwuZ2V0VGltZSgpID09PSBleHBlY3RlZC5nZXRUaW1lKCk7XG5cbiAgLy8gNy4zLiBPdGhlciBwYWlycyB0aGF0IGRvIG5vdCBib3RoIHBhc3MgdHlwZW9mIHZhbHVlID09ICdvYmplY3QnLFxuICAvLyBlcXVpdmFsZW5jZSBpcyBkZXRlcm1pbmVkIGJ5ID09LlxuICB9IGVsc2UgaWYgKHR5cGVvZiBhY3R1YWwgIT0gJ29iamVjdCcgJiYgdHlwZW9mIGV4cGVjdGVkICE9ICdvYmplY3QnKSB7XG4gICAgcmV0dXJuIG9wdHMuc3RyaWN0ID8gYWN0dWFsID09PSBleHBlY3RlZCA6IGFjdHVhbCA9PSBleHBlY3RlZDtcblxuICAvLyA3LjQuIEZvciBhbGwgb3RoZXIgT2JqZWN0IHBhaXJzLCBpbmNsdWRpbmcgQXJyYXkgb2JqZWN0cywgZXF1aXZhbGVuY2UgaXNcbiAgLy8gZGV0ZXJtaW5lZCBieSBoYXZpbmcgdGhlIHNhbWUgbnVtYmVyIG9mIG93bmVkIHByb3BlcnRpZXMgKGFzIHZlcmlmaWVkXG4gIC8vIHdpdGggT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKSwgdGhlIHNhbWUgc2V0IG9mIGtleXNcbiAgLy8gKGFsdGhvdWdoIG5vdCBuZWNlc3NhcmlseSB0aGUgc2FtZSBvcmRlciksIGVxdWl2YWxlbnQgdmFsdWVzIGZvciBldmVyeVxuICAvLyBjb3JyZXNwb25kaW5nIGtleSwgYW5kIGFuIGlkZW50aWNhbCAncHJvdG90eXBlJyBwcm9wZXJ0eS4gTm90ZTogdGhpc1xuICAvLyBhY2NvdW50cyBmb3IgYm90aCBuYW1lZCBhbmQgaW5kZXhlZCBwcm9wZXJ0aWVzIG9uIEFycmF5cy5cbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gb2JqRXF1aXYoYWN0dWFsLCBleHBlY3RlZCwgb3B0cyk7XG4gIH1cbn1cblxuZnVuY3Rpb24gaXNVbmRlZmluZWRPck51bGwodmFsdWUpIHtcbiAgcmV0dXJuIHZhbHVlID09PSBudWxsIHx8IHZhbHVlID09PSB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIGlzQnVmZmVyICh4KSB7XG4gIGlmICgheCB8fCB0eXBlb2YgeCAhPT0gJ29iamVjdCcgfHwgdHlwZW9mIHgubGVuZ3RoICE9PSAnbnVtYmVyJykgcmV0dXJuIGZhbHNlO1xuICBpZiAodHlwZW9mIHguY29weSAhPT0gJ2Z1bmN0aW9uJyB8fCB0eXBlb2YgeC5zbGljZSAhPT0gJ2Z1bmN0aW9uJykge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBpZiAoeC5sZW5ndGggPiAwICYmIHR5cGVvZiB4WzBdICE9PSAnbnVtYmVyJykgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gdHJ1ZTtcbn1cblxuZnVuY3Rpb24gb2JqRXF1aXYoYSwgYiwgb3B0cykge1xuICB2YXIgaSwga2V5O1xuICBpZiAoaXNVbmRlZmluZWRPck51bGwoYSkgfHwgaXNVbmRlZmluZWRPck51bGwoYikpXG4gICAgcmV0dXJuIGZhbHNlO1xuICAvLyBhbiBpZGVudGljYWwgJ3Byb3RvdHlwZScgcHJvcGVydHkuXG4gIGlmIChhLnByb3RvdHlwZSAhPT0gYi5wcm90b3R5cGUpIHJldHVybiBmYWxzZTtcbiAgLy9+fn5JJ3ZlIG1hbmFnZWQgdG8gYnJlYWsgT2JqZWN0LmtleXMgdGhyb3VnaCBzY3Jld3kgYXJndW1lbnRzIHBhc3NpbmcuXG4gIC8vICAgQ29udmVydGluZyB0byBhcnJheSBzb2x2ZXMgdGhlIHByb2JsZW0uXG4gIGlmIChpc0FyZ3VtZW50cyhhKSkge1xuICAgIGlmICghaXNBcmd1bWVudHMoYikpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgYSA9IHBTbGljZS5jYWxsKGEpO1xuICAgIGIgPSBwU2xpY2UuY2FsbChiKTtcbiAgICByZXR1cm4gZGVlcEVxdWFsKGEsIGIsIG9wdHMpO1xuICB9XG4gIGlmIChpc0J1ZmZlcihhKSkge1xuICAgIGlmICghaXNCdWZmZXIoYikpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKGEubGVuZ3RoICE9PSBiLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuICAgIGZvciAoaSA9IDA7IGkgPCBhLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoYVtpXSAhPT0gYltpXSkgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICB0cnkge1xuICAgIHZhciBrYSA9IG9iamVjdEtleXMoYSksXG4gICAgICAgIGtiID0gb2JqZWN0S2V5cyhiKTtcbiAgfSBjYXRjaCAoZSkgey8vaGFwcGVucyB3aGVuIG9uZSBpcyBhIHN0cmluZyBsaXRlcmFsIGFuZCB0aGUgb3RoZXIgaXNuJ3RcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgLy8gaGF2aW5nIHRoZSBzYW1lIG51bWJlciBvZiBvd25lZCBwcm9wZXJ0aWVzIChrZXlzIGluY29ycG9yYXRlc1xuICAvLyBoYXNPd25Qcm9wZXJ0eSlcbiAgaWYgKGthLmxlbmd0aCAhPSBrYi5sZW5ndGgpXG4gICAgcmV0dXJuIGZhbHNlO1xuICAvL3RoZSBzYW1lIHNldCBvZiBrZXlzIChhbHRob3VnaCBub3QgbmVjZXNzYXJpbHkgdGhlIHNhbWUgb3JkZXIpLFxuICBrYS5zb3J0KCk7XG4gIGtiLnNvcnQoKTtcbiAgLy9+fn5jaGVhcCBrZXkgdGVzdFxuICBmb3IgKGkgPSBrYS5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgIGlmIChrYVtpXSAhPSBrYltpXSlcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICAvL2VxdWl2YWxlbnQgdmFsdWVzIGZvciBldmVyeSBjb3JyZXNwb25kaW5nIGtleSwgYW5kXG4gIC8vfn5+cG9zc2libHkgZXhwZW5zaXZlIGRlZXAgdGVzdFxuICBmb3IgKGkgPSBrYS5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgIGtleSA9IGthW2ldO1xuICAgIGlmICghZGVlcEVxdWFsKGFba2V5XSwgYltrZXldLCBvcHRzKSkgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiB0eXBlb2YgYSA9PT0gdHlwZW9mIGI7XG59XG5cblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIC4vfi9kZWVwLWVxdWFsL2luZGV4LmpzXG4gKiogbW9kdWxlIGlkID0gN1xuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIiwiZXhwb3J0cyA9IG1vZHVsZS5leHBvcnRzID0gdHlwZW9mIE9iamVjdC5rZXlzID09PSAnZnVuY3Rpb24nXG4gID8gT2JqZWN0LmtleXMgOiBzaGltO1xuXG5leHBvcnRzLnNoaW0gPSBzaGltO1xuZnVuY3Rpb24gc2hpbSAob2JqKSB7XG4gIHZhciBrZXlzID0gW107XG4gIGZvciAodmFyIGtleSBpbiBvYmopIGtleXMucHVzaChrZXkpO1xuICByZXR1cm4ga2V5cztcbn1cblxuXG5cbi8qKioqKioqKioqKioqKioqKlxuICoqIFdFQlBBQ0sgRk9PVEVSXG4gKiogLi9+L2RlZXAtZXF1YWwvbGliL2tleXMuanNcbiAqKiBtb2R1bGUgaWQgPSA4XG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJ2YXIgc3VwcG9ydHNBcmd1bWVudHNDbGFzcyA9IChmdW5jdGlvbigpe1xuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGFyZ3VtZW50cylcbn0pKCkgPT0gJ1tvYmplY3QgQXJndW1lbnRzXSc7XG5cbmV4cG9ydHMgPSBtb2R1bGUuZXhwb3J0cyA9IHN1cHBvcnRzQXJndW1lbnRzQ2xhc3MgPyBzdXBwb3J0ZWQgOiB1bnN1cHBvcnRlZDtcblxuZXhwb3J0cy5zdXBwb3J0ZWQgPSBzdXBwb3J0ZWQ7XG5mdW5jdGlvbiBzdXBwb3J0ZWQob2JqZWN0KSB7XG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwob2JqZWN0KSA9PSAnW29iamVjdCBBcmd1bWVudHNdJztcbn07XG5cbmV4cG9ydHMudW5zdXBwb3J0ZWQgPSB1bnN1cHBvcnRlZDtcbmZ1bmN0aW9uIHVuc3VwcG9ydGVkKG9iamVjdCl7XG4gIHJldHVybiBvYmplY3QgJiZcbiAgICB0eXBlb2Ygb2JqZWN0ID09ICdvYmplY3QnICYmXG4gICAgdHlwZW9mIG9iamVjdC5sZW5ndGggPT0gJ251bWJlcicgJiZcbiAgICBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCAnY2FsbGVlJykgJiZcbiAgICAhT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKG9iamVjdCwgJ2NhbGxlZScpIHx8XG4gICAgZmFsc2U7XG59O1xuXG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiAuL34vZGVlcC1lcXVhbC9saWIvaXNfYXJndW1lbnRzLmpzXG4gKiogbW9kdWxlIGlkID0gOVxuICoqIG1vZHVsZSBjaHVua3MgPSAwXG4gKiovIl0sInNvdXJjZVJvb3QiOiIifQ== -------------------------------------------------------------------------------- /dist/update-in.min.js: -------------------------------------------------------------------------------- 1 | !function(r,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.UpdateIn=t():r.UpdateIn=t()}(this,function(){return function(r){function t(n){if(e[n])return e[n].exports;var o=e[n]={exports:{},id:n,loaded:!1};return r[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var e={};return t.m=r,t.c=e,t.p="",t(0)}([function(r,t,e){"use strict";function n(r){return r&&r.__esModule?r:{"default":r}}function o(r,t){return(0,v["default"])(r,{$merge:t})}function u(r,t){return(0,v["default"])(r,{$push:t})}function i(r,t){return(0,v["default"])(r,{$unshift:t})}function a(r,t){return(0,v["default"])(r,{$splice:t})}function f(r){for(var t=arguments.length,e=Array(t>1?t-1:0),n=1;t>n;n++)e[n-1]=arguments[n];if(e.length%2!==0)throw new Error("assoc expects an even number of arguments");var o=y(e);return Array.isArray(r)&&o.forEach(function(t){var e=h(t,2),n=e[0];e[1];if("number"!=typeof n||parseInt(n,10)!==n)throw new TypeError("assoc expects only integer keys");if(0>n||n>r.length)throw new RangeError("assoc expects only numeric keys in the range [0, array.length]")}),(0,v["default"])(r,{$apply:function(r){return o.reduce(function(r,t){var e=h(t,2),n=e[0],o=e[1];return r[n]=o,r},r)}})}function c(r){for(var t=arguments.length,e=Array(t>1?t-1:0),n=1;t>n;n++)e[n-1]=arguments[n];return Array.isArray(r)?(0,v["default"])(r,{$apply:function(r){return r.filter(function(r,t){return-1===e.indexOf(t)})}}):(0,v["default"])(r,{$apply:function(r){return e.forEach(function(t){return delete r[t]}),r}})}function l(r,t,e){for(var n=arguments.length,o=Array(n>3?n-3:0),u=3;n>u;u++)o[u-3]=arguments[u];var i,a=function(r){return e.apply(null,[r].concat(o))};if(t.length>0){var f=s(t,{$apply:a});i=(0,v["default"])(r,f)}else 0===t.length&&(i=a(r));return(0,m["default"])(r,i)?r:i}function s(r,t){return r.reduceRight(p,t)}function p(r,t){var e={};return e[t]=r,e}function y(r){for(var t=0,e=[];t0&&"number"!=typeof r[0]?!1:!0:!1}function u(r,t,e){var u,l;if(n(r)||n(t))return!1;if(r.prototype!==t.prototype)return!1;if(f(r))return f(t)?(r=i.call(r),t=i.call(t),c(r,t,e)):!1;if(o(r)){if(!o(t))return!1;if(r.length!==t.length)return!1;for(u=0;u=0;u--)if(s[u]!=p[u])return!1;for(u=s.length-1;u>=0;u--)if(l=s[u],!c(r[l],t[l],e))return!1;return typeof r==typeof t}var i=Array.prototype.slice,a=e(7),f=e(8),c=r.exports=function(r,t,e){return e||(e={}),r===t?!0:r instanceof Date&&t instanceof Date?r.getTime()===t.getTime():"object"!=typeof r&&"object"!=typeof t?e.strict?r===t:r==t:u(r,t,e)}},function(r,t){function e(r){var t=[];for(var e in r)t.push(e);return t}t=r.exports="function"==typeof Object.keys?Object.keys:e,t.shim=e},function(r,t){function e(r){return"[object Arguments]"==Object.prototype.toString.call(r)}function n(r){return r&&"object"==typeof r&&"number"==typeof r.length&&Object.prototype.hasOwnProperty.call(r,"callee")&&!Object.prototype.propertyIsEnumerable.call(r,"callee")||!1}var o="[object Arguments]"==function(){return Object.prototype.toString.call(arguments)}();t=r.exports=o?e:n,t.supported=e,t.unsupported=n}])}); -------------------------------------------------------------------------------- /examples/cursor/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | static/ 5 | -------------------------------------------------------------------------------- /examples/cursor/karma.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = function (config) { 4 | var configuration = { 5 | browsers: [ 'Chrome' ], 6 | frameworks: [ 'mocha', 'sinon-chai' ], 7 | reporters: [ 'mocha' ], 8 | 9 | customLaunchers: { 10 | Chrome_travis_ci: { 11 | base: 'Chrome', 12 | flags: ['--no-sandbox'] 13 | } 14 | }, 15 | 16 | files: [ 17 | 'tests.webpack.js' 18 | ], 19 | 20 | preprocessors: { 21 | 'tests.webpack.js': [ 'webpack', 'sourcemap' ] 22 | }, 23 | 24 | webpack: { 25 | devtool: 'inline-source-map', 26 | module: { 27 | loaders: [ 28 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel' }, 29 | { test: /node_modules\/update-in/, loader: 'babel' } 30 | ] 31 | }, 32 | resolve: { 33 | alias: { 34 | 'update-in': path.join(__dirname, '../../src/update-in') 35 | } 36 | } 37 | }, 38 | 39 | webpackServer: { 40 | noInfo: true 41 | } 42 | }; 43 | 44 | if(process.env.TRAVIS) { 45 | configuration.browsers = [ 'Chrome_travis_ci' ]; 46 | } 47 | 48 | config.set(configuration); 49 | }; 50 | -------------------------------------------------------------------------------- /examples/cursor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.1", 3 | "scripts": { 4 | "test": "karma start", 5 | "build": "webpack" 6 | }, 7 | "main": "./cursor.js", 8 | "devDependencies": { 9 | "babel-core": "^5.8.22", 10 | "babel-loader": "^5.3.2", 11 | "babelify": "^6.1.3", 12 | "chai": "^1.9.2", 13 | "clone": "^1.0.2", 14 | "es5-shim": "^4.0.3", 15 | "karma": "0.12.37", 16 | "karma-chai": "^0.1.0", 17 | "karma-chrome-launcher": "^0.2.0", 18 | "karma-firefox-launcher": "^0.1.6", 19 | "karma-mocha": "^0.2.0", 20 | "karma-mocha-reporter": "^1.1.1", 21 | "karma-sinon-chai": "^1.1.0", 22 | "karma-sourcemap-loader": "^0.3.5", 23 | "karma-webpack": "1.6.0", 24 | "mocha": "^2.0.1", 25 | "react": "^0.14.2", 26 | "uglifyify": "~2.6.0", 27 | "webpack": "^1.11.0" 28 | }, 29 | "dependencies": { 30 | "lodash": "^3.10.1", 31 | "array-union": "^1.0.0", 32 | "deep-equal": "^0.2.1", 33 | "lodash.isobject": "^3.0.2", 34 | "omit-keys": "^0.1.0", 35 | "react-addons-update": "^0.14.2" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/cursor/src/Cursor.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import {updateIn} from 'update-in'; 3 | 4 | 5 | let get = (o, k) => o[k]; 6 | let getIn = (o, ks) => _.reduce(ks, get, o); 7 | 8 | class Cursor { 9 | constructor(store, paths, value) { 10 | this.value = () => getIn(value, paths); 11 | this.swap = (f, ...args) => store.swap(v => updateIn(v, paths, f, args)); 12 | this.refine = (...morePaths) => new Cursor(store, paths.concat(morePaths), value); 13 | } 14 | } 15 | 16 | export let cursor = (store) => new Cursor(store, [], store.value()); 17 | -------------------------------------------------------------------------------- /examples/cursor/src/Store.js: -------------------------------------------------------------------------------- 1 | export default class Store { 2 | constructor (initialVal) { 3 | this._ref = initialVal; 4 | 5 | // auto-bind store methods 6 | this.value = () => this._ref; 7 | this.swap = (f) => { this._ref = f(this._ref); } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/cursor/src/__tests__/Cursor.spec.js: -------------------------------------------------------------------------------- 1 | import {cursor} from '../Cursor'; 2 | import Store from '../Store' 3 | 4 | 5 | describe('Cursor', () => { 6 | var cur, store; 7 | var initialState = {a: {b: 42}, c: [1, 2, 3]}; 8 | 9 | beforeEach(() => { 10 | store = new Store(initialState); 11 | cur = cursor(store); 12 | }); 13 | 14 | afterEach(() => { 15 | cur = null; 16 | store = null; 17 | }); 18 | 19 | it('get value from refined cursor', () => { 20 | expect(cur.refine('a', 'b').value()).to.equal(42); 21 | }); 22 | 23 | it('swap at refined cursor reflected in store', () => { 24 | cur.refine('a', 'b').swap(v => v+1); 25 | expect(store.value().a.b).to.equal(43); 26 | }); 27 | 28 | it('cursor value semantics', () => { 29 | cur.refine('a', 'b').swap(v => v+1); 30 | expect(cur.refine('a','b').value()).to.equal(42); 31 | }); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /examples/cursor/tests.webpack.js: -------------------------------------------------------------------------------- 1 | var context = require.context('./src', true, /.spec\.js$/); 2 | context.keys().forEach(context); 3 | -------------------------------------------------------------------------------- /examples/cursor/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | devtool: 'inline-source-map', 6 | entry: [ 7 | './src/index' 8 | ], 9 | output: { 10 | path: path.join(__dirname, 'static'), 11 | filename: 'bundle.js', 12 | publicPath: '/static/' 13 | }, 14 | plugins: [ 15 | new webpack.NoErrorsPlugin() 16 | ], 17 | resolve: { 18 | extensions: ['', '.js', '.less'], 19 | root: [ 20 | path.resolve('./src') 21 | ], 22 | alias: { 23 | 'update-in': path.join(__dirname, '../../src/update-in') 24 | } 25 | }, 26 | module: { 27 | loaders: [ 28 | { test: /\.js$/, loaders: ['babel'], include: [path.join(__dirname, 'src')] }, 29 | { test: /node_modules\/update-in/, loader: 'babel' } 30 | ] 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function (config) { 3 | var configuration = { 4 | browsers: [ 'Chrome' ], 5 | frameworks: [ 'mocha', 'sinon-chai' ], 6 | reporters: [ 'mocha' ], 7 | 8 | customLaunchers: { 9 | Chrome_travis_ci: { 10 | base: 'Chrome', 11 | flags: ['--no-sandbox'] 12 | } 13 | }, 14 | 15 | files: [ 16 | 'tests.webpack.js' 17 | ], 18 | 19 | preprocessors: { 20 | 'tests.webpack.js': [ 'webpack', 'sourcemap' ] 21 | }, 22 | 23 | webpack: { 24 | devtool: 'inline-source-map', 25 | module: { 26 | loaders: [ 27 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel' } 28 | ] 29 | } 30 | }, 31 | 32 | webpackServer: { 33 | noInfo: true 34 | } 35 | }; 36 | 37 | if(process.env.TRAVIS) { 38 | configuration.browsers = [ 'Chrome_travis_ci' ]; 39 | } 40 | 41 | config.set(configuration); 42 | }; 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "update-in", 3 | "version": "0.0.1-alpha.5", 4 | "description": "Persistent functional object updates on vanilla js data structures (wraps react-addons-update)", 5 | "keywords": [ 6 | "react", 7 | "persistent", 8 | "immutable", 9 | "update" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/dustingetz/update-in.git" 14 | }, 15 | "license": "MIT", 16 | "scripts": { 17 | "test": "karma start", 18 | "start": "node server.js", 19 | "build": "webpack", 20 | "dist": "webpack --config webpack.dist.js" 21 | }, 22 | "main": "./src/update-in.js", 23 | "devDependencies": { 24 | "babel-core": "^5.8.22", 25 | "babel-loader": "^5.3.2", 26 | "babelify": "^6.1.3", 27 | "chai": "^1.9.2", 28 | "clone": "^1.0.2", 29 | "es5-shim": "^4.0.3", 30 | "karma": "0.12.37", 31 | "karma-chai": "^0.1.0", 32 | "karma-chrome-launcher": "^0.2.0", 33 | "karma-firefox-launcher": "^0.1.6", 34 | "karma-mocha": "^0.2.0", 35 | "karma-mocha-reporter": "^1.1.1", 36 | "karma-sinon-chai": "^1.1.0", 37 | "karma-sourcemap-loader": "^0.3.5", 38 | "karma-webpack": "1.6.0", 39 | "lodash": "^3.10.1", 40 | "mocha": "^2.0.1", 41 | "react": "^0.14.2", 42 | "uglifyify": "~2.6.0", 43 | "webpack": "^1.11.0" 44 | }, 45 | "dependencies": { 46 | "array-union": "^1.0.0", 47 | "deep-equal": "^0.2.1", 48 | "lodash.isobject": "^3.0.2", 49 | "omit-keys": "^0.1.0", 50 | "react-addons-update": "^0.14.2" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/__tests__/UpdateIn.spec.js: -------------------------------------------------------------------------------- 1 | /* global describe, it, expect */ 2 | import _ from 'lodash'; 3 | import {updateIn, merge, push, unshift, splice, assoc, dissoc} from '../update-in'; 4 | 5 | 6 | const val = {a: {b: 0, c: 2}, xs: [1, 2]}; 7 | 8 | describe('updateIn applies a fn at a path', () => { 9 | 10 | it('apply', () => { 11 | const v = updateIn(val, ['a', 'b'], v => v+1); 12 | expect(v.a.b).to.equal(1); 13 | const v2 = updateIn(val, ['a', 'b'], v => v+10); 14 | expect(v2.a.b).to.equal(10); 15 | }); 16 | 17 | it('apply with extra args', () => { 18 | let add = (...args) => args.reduce((a,b)=>a+b, 0); 19 | const v = updateIn(val, ['a', 'b'], add, 1, 2, 3); 20 | expect(v.a.b).to.equal(6); 21 | }); 22 | 23 | }); 24 | 25 | 26 | describe('updateIn with persistent update combinators', () => { 27 | 28 | it('set', () => { 29 | const v = updateIn(val, ['a', 'b'], v => 10); 30 | expect(v.a.b).to.equal(10); 31 | }); 32 | 33 | it('push', () => { 34 | const v1 = updateIn(val, ['xs'], push, [3]); 35 | expect(v1.xs).to.deep.equal([1,2,3]); 36 | const v2 = updateIn(val, ['xs'], push, [99]); 37 | expect(v2.xs).to.deep.equal([1,2,99]); 38 | }); 39 | 40 | it('unshift', () => { 41 | const v1 = updateIn(val, ['xs'], unshift, [0]); 42 | expect(v1.xs).to.deep.equal([0,1,2]); 43 | }); 44 | 45 | it('splice', () => { 46 | const v1 = updateIn(val, ['xs'], splice, [[1, 1, 20]]); 47 | expect(v1.xs).to.deep.equal([1,20]); 48 | 49 | const v2 = updateIn(val, ['xs'], splice, [[0, 1, 6, 5], [4, 0, 99, 99]]); 50 | expect(v2.xs).to.deep.equal([6,5,2,99,99]); 51 | }); 52 | 53 | it('merge', () => { 54 | const v1 = updateIn(val, ['a'], merge, {c:99, d: 99}); 55 | expect(v1.a).to.deep.equal({b: 0, c: 99, d: 99}); 56 | }); 57 | 58 | }); 59 | 60 | describe('assoc', () => { 61 | describe('in objects', () => { 62 | it('can assoc a single existing key', () => { 63 | const updated = updateIn(val, ['a'], assoc, 'b', 1); 64 | expect(updated.a).to.deep.equal({b: 1, c: 2}); 65 | }); 66 | 67 | it('can assoc multiple existing keys', () => { 68 | const updated = updateIn(val, ['a'], assoc, 'b', 5, 'c', 6); 69 | expect(updated.a).to.deep.equal({b: 5, c: 6}); 70 | }); 71 | 72 | it('can assoc a single new key', () => { 73 | const updated = updateIn(val, ['a'], assoc, 'd', 4); 74 | expect(updated.a).to.deep.equal({b: 0, c: 2, d: 4}); 75 | }); 76 | 77 | it('can assoc multiple new keys', () => { 78 | const updated = updateIn(val, ['a'], assoc, 'd', 4, 'e', 6); 79 | expect(updated.a).to.deep.equal({b: 0, c: 2, d: 4, e: 6}); 80 | }); 81 | 82 | it('expects an even number of varargs', () => { 83 | expect(() => updateIn(val, ['a'], assoc, 'd', 4, 'e')).to.throw(Error, 'assoc expects an even number of arguments'); 84 | }); 85 | }); 86 | 87 | describe('in arrays', () => { 88 | it('can assoc a single existing key', () => { 89 | const updated = updateIn(val, ['xs'], assoc, 0, 3); 90 | expect(updated.xs).to.deep.equal([3, 2]); 91 | }); 92 | 93 | it('can assoc multiple existing keys', () => { 94 | const updated = updateIn(val, ['xs'], assoc, 0, 3, 1, 4); 95 | expect(updated.xs).to.deep.equal([3, 4]); 96 | }); 97 | 98 | it('can assoc a single new key', () => { 99 | const updated = updateIn(val, ['xs'], assoc, 2, 3); 100 | expect(updated.xs).to.deep.equal([1, 2, 3]); 101 | }); 102 | 103 | it('expects an even number of varargs', () => { 104 | expect(() => updateIn(val, ['xs'], assoc, 1, false, 0)).to.throw(Error, 'assoc expects an even number of arguments'); 105 | }); 106 | 107 | it('rejects non-integer keys', () => { 108 | expect(() => updateIn(val, ['xs'], assoc, 1.5, 'not an int')).to.throw(TypeError, 'assoc expects only integer keys'); 109 | }); 110 | 111 | it('expects keys to be between [0, array.length]', () => { 112 | expect(() => updateIn(val, ['xs'], assoc, -1, 'negative index?')).to.throw(RangeError, 'assoc expects only numeric keys in the range [0, array.length]'); 113 | expect(() => updateIn(val, ['xs'], assoc, 3, 'sparse arrays?')).to.throw(RangeError, 'assoc expects only numeric keys in the range [0, array.length]'); 114 | }); 115 | }); 116 | }); 117 | 118 | describe('dissoc', () => { 119 | const collections = { 120 | array: [1, 2, 3, 4, 5, 6, 7], 121 | object: {foo: 1, bar: 2, baz: 3} 122 | }; 123 | 124 | describe('from objects', () => { 125 | it('can dissoc a single key', () => { 126 | const updated = updateIn(collections, ['object'], dissoc, 'bar'); 127 | expect(updated.object).to.deep.equal({foo: 1, baz: 3}); 128 | }); 129 | 130 | it('can dissoc multiple keys', () => { 131 | const updated = updateIn(collections, ['object'], dissoc, 'foo', 'baz'); 132 | expect(updated.object).to.deep.equal({bar: 2}); 133 | }); 134 | }); 135 | 136 | describe('from arrays', () => { 137 | it('can dissoc a single element', () => { 138 | const updated = updateIn(collections, ['array'], dissoc, 1); 139 | expect(updated.array).to.deep.equal([1, 3, 4, 5, 6, 7]); 140 | }); 141 | 142 | it('can dissoc multiple elements', () => { 143 | const updated = updateIn(collections, ['array'], dissoc, 2, 3, 4); 144 | expect(updated.array).to.deep.equal([1, 2, 6, 7]); 145 | }); 146 | 147 | it('can dissoc non-adjacent elements', () => { 148 | const updated = updateIn(collections, ['array'], dissoc, 1, 3, 5); 149 | expect(updated.array).to.deep.equal([1, 3, 5, 7]); 150 | }); 151 | }); 152 | }); 153 | -------------------------------------------------------------------------------- /src/update-in.js: -------------------------------------------------------------------------------- 1 | import {default as persistentUpdate} from 'react-addons-update'; 2 | import isEqual from 'deep-equal'; 3 | 4 | 5 | export function merge (a, b) { 6 | return persistentUpdate(a, {$merge: b}); 7 | } 8 | 9 | export function push (as, bs) { 10 | return persistentUpdate(as, {$push: bs}); 11 | } 12 | 13 | export function unshift (as, bs) { 14 | return persistentUpdate(as, {$unshift: bs}); 15 | } 16 | 17 | export function splice (as, splices) { 18 | // persistentUpdate([12, 17, 15], {$splice: [[1, 1, 13, 14]]}) => [12, 13, 14, 15] 19 | return persistentUpdate(as, {$splice: splices}); 20 | } 21 | 22 | export function assoc(coll, ...kvs) { 23 | if (kvs.length % 2 !== 0) throw new Error('assoc expects an even number of arguments'); 24 | const ps = pairs(kvs); 25 | 26 | if (Array.isArray(coll)) { 27 | ps.forEach(([k, v]) => { 28 | if (! (typeof k === 'number' && parseInt(k, 10) === k)) throw new TypeError('assoc expects only integer keys'); 29 | if (k < 0 || k > coll.length) throw new RangeError('assoc expects only numeric keys in the range [0, array.length]'); 30 | }); 31 | } 32 | 33 | return persistentUpdate(coll, {$apply: o => ps.reduce((acc, [k, v]) => { acc[k] = v; return acc; }, o)}); 34 | } 35 | 36 | export function dissoc (coll, ...keys) { 37 | if (Array.isArray(coll)) { 38 | return persistentUpdate(coll, {$apply: a => a.filter((v,i) => keys.indexOf(i) === -1)}); 39 | } else { 40 | return persistentUpdate(coll, {$apply: o => { 41 | keys.forEach(k => delete o[k]); 42 | return o; 43 | }}); 44 | } 45 | } 46 | 47 | /** 48 | * Thin wrapper over react-addons-update to apply a function at path 49 | * preserving other references. 50 | */ 51 | export function updateIn (rootVal, paths, f, ...args) { 52 | let ff = (v) => f.apply(null, [v].concat(args)); 53 | 54 | var newRootVal; 55 | if (paths.length > 0) { 56 | const command = rootAt(paths, {$apply: ff}); 57 | newRootVal = persistentUpdate(rootVal, command); 58 | } 59 | else if (paths.length === 0) { 60 | newRootVal = ff(rootVal); 61 | } 62 | 63 | // would be better to do this valEq check on just the leaf 64 | return isEqual(rootVal, newRootVal) 65 | ? rootVal // preserve === if same value 66 | : newRootVal; 67 | } 68 | 69 | 70 | 71 | // Helper methods for forming react-addons-update commands. 72 | 73 | /** 74 | * @param leafVal e.g. {$apply: f} 75 | * @param paths e.g. ['x', 'y', 'z'] 76 | * @returns e.g. {x: {y: {z: {$apply: f}}} 77 | */ 78 | function rootAt (paths, leafVal) { 79 | return paths.reduceRight(unDeref, leafVal) 80 | } 81 | 82 | 83 | /** 84 | * @param obj e.g {$apply: f} 85 | * @param key e.g. 'foo' 86 | * @returns e.g. {foo: {$apply: f}} 87 | */ 88 | function unDeref(obj, key) { // aka un-get 89 | var nextObj = {}; 90 | nextObj[key] = obj; 91 | return nextObj; 92 | } 93 | 94 | // Other helper functions 95 | 96 | /** 97 | * 98 | * @param array e.g. [1, 2, 3, 4, 5, 6] 99 | * @returns {Array} e.g. [[1, 2], [3, 4], [5, 6]] 100 | */ 101 | function pairs (array) { 102 | let index = 0; 103 | let pairs = []; 104 | 105 | while (index < array.length) { 106 | pairs.push([array[index++], array[index++]]); 107 | } 108 | 109 | return pairs; 110 | } 111 | -------------------------------------------------------------------------------- /tests.webpack.js: -------------------------------------------------------------------------------- 1 | var context = require.context('./src', true, /.spec\.js$/); 2 | context.keys().forEach(context); 3 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | devtool: 'inline-source-map', 5 | entry: './src/update-in', 6 | 7 | output: { 8 | path: path.resolve('./dist'), 9 | filename: 'update-in.js', 10 | publicPath: '/static/' 11 | }, 12 | 13 | resolve: { 14 | extensions: ['', '.js'], 15 | root: [ 16 | path.resolve('./src') 17 | ], 18 | modulesDirectories: ['node_modules'] 19 | }, 20 | 21 | module: { 22 | loaders: [ 23 | {test: /\.js$/, loaders: ['babel'], include: path.resolve('./src')} 24 | ] 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /webpack.dist.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var config = require('./webpack.config'); 4 | 5 | config.devtool = false; 6 | 7 | config.output = { 8 | path: path.resolve('./dist'), 9 | filename: 'update-in.min.js', 10 | libraryTarget: 'umd', 11 | library: 'UpdateIn' 12 | }; 13 | 14 | config.plugins = [ 15 | new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production') } }), 16 | new webpack.optimize.UglifyJsPlugin({ minimize: true }) 17 | ]; 18 | 19 | module.exports = config; 20 | --------------------------------------------------------------------------------