UNPKG

rext-image-editor

Version:

REXT is a client side image editor that uses GPU.

1,033 lines (973 loc) 103 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["RextEditor"] = factory(); else root["RextEditor"] = factory(); })(this, function() { return /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./node_modules/raw-loader/dist/cjs.js!./src/shaders/fragment_shader.frag": /*!********************************************************************************!*\ !*** ./node_modules/raw-loader/dist/cjs.js!./src/shaders/fragment_shader.frag ***! \********************************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("/** * David Iglesias. All rights reserved */\nprecision mediump float;\nuniform sampler2D u_image;\nuniform vec2 u_textureSize;\nuniform float u_kernel[25];\nuniform float u_kernelWeight;\nuniform sampler2D u_lut;\nuniform float u_saturation;\nuniform float u_brightness;\nuniform float u_exposure;\nuniform float u_contrast;\nuniform float u_dehaze;\nuniform float u_atmosferic_light;\nuniform float u_masking;\nuniform vec3 u_temptint[3]; // RGB temptint, RGB lightFill, RGB darkFill\nuniform float u_bAndW;\nuniform float u_hdr;\nvarying vec2 v_texCoord;\nvoid main() {\n \n\tvec2 pixel_size = vec2(1.0, 1.0) / u_textureSize;\n \n\tvec3 center = texture2D(u_image, v_texCoord).rgb;\n\n /* 5x5 kernel filter */\n vec4 colorSum = texture2D(u_image, v_texCoord + pixel_size * vec2(-2, -2)) * u_kernel[0]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(-1, -2)) * u_kernel[1]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(0, -2)) * u_kernel[2]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(1, -2)) * u_kernel[3]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(2, -2)) * u_kernel[4]\n\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(-2, -1)) * u_kernel[5]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(-1, -1)) * u_kernel[6]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(0, -1)) * u_kernel[7]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(1, -1)) * u_kernel[8]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(2, -1)) * u_kernel[9]\n\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(-2, 0)) * u_kernel[10]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(-1, 0)) * u_kernel[11]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(0, 0)) * u_kernel[12]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(1, 0)) * u_kernel[13]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(2, 0)) * u_kernel[14]\n\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(-2, 1)) * u_kernel[15]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(-1, 1)) * u_kernel[16]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(0, 1)) * u_kernel[17]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(1, 1)) * u_kernel[18]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(2, 1)) * u_kernel[19]\n\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(-2, 2)) * u_kernel[20]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(-1, 2)) * u_kernel[21]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(0, 2)) * u_kernel[22]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(1, 2)) * u_kernel[23]\n\t\t + texture2D(u_image, v_texCoord + pixel_size * vec2(2, 2)) * u_kernel[24];\n\n\t/* Kernel filter mask */\n vec3 rgb_pix = mix(center, (colorSum.rgb / u_kernelWeight), u_masking);\n\t\n\t/**\n\t * RGB to saturation/value conversion, in order to keep hue constant \n\t * sv_pixel = (saturation, value)\n\t */\n float _max = max(rgb_pix.r, max(rgb_pix.g, rgb_pix.b));\n float _min = min(rgb_pix.r, min(rgb_pix.g, rgb_pix.b));\n vec2 sv_pixel = vec2(1.0 - _min / _max, _max);\n\n sv_pixel.y = clamp(texture2D(u_lut, vec2(sv_pixel.y, 0.0)).a, 0.0, 1.0);\n\n\t/* Add saturation */\n if (u_saturation != 0.0) {\n sv_pixel.x *= (1.0 + u_saturation);\n }\n\n sv_pixel.x = clamp(sv_pixel.x, 0.0, 1.0);\n\n\t/* Brightness */\n if (u_brightness != 0.0) {\n sv_pixel.y = pow(sv_pixel.y, 1.0 - u_brightness * 0.6);\n }\n\n\t/* HDR 'like' filter */\n if (u_hdr != 0.0) {\n sv_pixel.y = mix(sv_pixel.y, clamp(1.0 - pow(1.0 - pow(sv_pixel.y, 0.3), 0.42), 0.0, 1.0), u_hdr);\n }\n\n sv_pixel = clamp(sv_pixel, 0.0, 1.0);\n\t/* Return to RGB */\n if (sv_pixel.x > 0.0) {\n float k = -sv_pixel.x / (1.0 - _min / _max);\n rgb_pix = (_max - rgb_pix) * k + _max;\n rgb_pix *= sv_pixel.y / _max;\n } else {\n rgb_pix.r = rgb_pix.g = rgb_pix.b = sv_pixel.y;\n }\n\n\t/* Dehaze */\n if (u_dehaze != 0.0) {\n float t = 1.0 / 25.0;\n vec4 center = texture2D(u_image, v_texCoord);\n vec2 pixel_size = vec2(1.0, 1.0) / u_textureSize;\n float dark = 1.0;\n const int radius = 1;\n for (int ii = -radius; ii <= radius; ii++) {\n for (int jj = -radius; jj <= radius; jj++) {\n vec4 pix = texture2D(u_image, v_texCoord + pixel_size * vec2(ii, jj));\n float _min = min(pix.r, min(pix.g, pix.b));\n if (dark > _min) {\n dark = _min;\n }\n }\n }\n float darkPix = min(center.r, min(center.g, center.b));\n float diff = abs(darkPix - dark);\n float mask = pow(diff, 3.0);\n dark = mix(darkPix, dark, mask);\n float mm = max(1.0 - dark, 0.2);\n rgb_pix = mix(rgb_pix, ((rgb_pix - u_atmosferic_light) / mm + u_atmosferic_light), u_dehaze);\n }\n\n\t/* Exposure */\n rgb_pix += u_exposure;\n rgb_pix = clamp(rgb_pix, 0.0, 1.0);\n\n\t/* Contrast */\n float contrast = u_contrast + 1.0;\n rgb_pix = contrast * (rgb_pix - 0.5) + 0.5;\n\t\n\t/* Apply tint filter */\n rgb_pix *= u_temptint[0];\n float mono = dot(rgb_pix, vec3(0.2126, 0.7152, 0.0722));\n rgb_pix += mix(u_temptint[2], u_temptint[1], mono);\n\n\t/* Black&White filter */\n if (u_bAndW != 0.0) {\n rgb_pix = mix(rgb_pix, vec3(mono, mono, mono), u_bAndW);\n }\n\n gl_FragColor = vec4(rgb_pix, 1.0);\n\n}\n"); /***/ }), /***/ "./node_modules/raw-loader/dist/cjs.js!./src/shaders/vertex_shader.vert": /*!******************************************************************************!*\ !*** ./node_modules/raw-loader/dist/cjs.js!./src/shaders/vertex_shader.vert ***! \******************************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("attribute vec2 a_position;\nattribute vec2 a_texCoord;\nuniform vec2 u_resolution;\nvarying vec2 v_texCoord;\nuniform vec2 u_rotation;\nuniform vec2 u_rotation_center;\nuniform vec2 u_scale;\nuniform vec2 u_translate; \n\nvoid main() {\n\n vec2 scaled = a_position * vec2(u_scale);\n vec2 pos_r_t = scaled - u_rotation_center;\n vec2 pos_rotated = vec2(\n pos_r_t.x * u_rotation.y + pos_r_t.y * u_rotation.x,\n pos_r_t.y * u_rotation.y - pos_r_t.x * u_rotation.x);\n \n vec2 dist = (pos_rotated + u_rotation_center) / u_resolution;\n\n vec2 pos = vec2((dist + u_translate) * 2.0 - 1.0) * vec2(1, -1);\n gl_Position = vec4(pos, 0, 1);\n v_texCoord = a_texCoord;\n}\n"); /***/ }), /***/ "./src/editor.ts": /*!***********************!*\ !*** ./src/editor.ts ***! \***********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "RextEditor": () => (/* binding */ RextEditor) /* harmony export */ }); /* harmony import */ var _lib_color__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib/color */ "./src/lib/color.ts"); /* harmony import */ var _lib_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/constants */ "./src/lib/constants.ts"); /* harmony import */ var _shaders_index__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/index */ "./src/shaders/index.ts"); /* harmony import */ var _log_LogFacade__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./log/LogFacade */ "./src/log/LogFacade.ts"); /* harmony import */ var _lib_image_transforms__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lib/image-transforms */ "./src/lib/image-transforms.ts"); /* harmony import */ var _shaders__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./shaders */ "./src/shaders.ts"); /* harmony import */ var _lib_context__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./lib/context */ "./src/lib/context.ts"); const clone = (obj) => JSON.parse(JSON.stringify(obj)); const CANVAS_OPTIONS = { alpha: false, antialias: false, }; /* BEGIN WEBGL PART */ class RextEditor { constructor(canvas) { this.params = clone(_lib_constants__WEBPACK_IMPORTED_MODULE_1__.defaultParams); this.program = null; this.realImage = null; this.currentImage = null; this.context = null; this.config = _lib_constants__WEBPACK_IMPORTED_MODULE_1__.defaultConfig; this.onParamsChangeCallbacks = []; this.WIDTH = 0; this.HEIGHT = 0; this.log = new _log_LogFacade__WEBPACK_IMPORTED_MODULE_3__.LogFacade(); this.uniforms = { kernel: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], temptint: [1, 1, 1] }; this.LIGHT_MATCH = new Array(256).fill(0).map((v, i) => i); if (canvas) { this.setCanvas(canvas); } } setCanvas(canvas) { this.config.width = canvas.width; this.config.height = canvas.height; this.canvas = canvas; this.gl = canvas.getContext("webgl", CANVAS_OPTIONS) || canvas.getContext("experimental-webgl", CANVAS_OPTIONS); } runCallback(callbackName) { switch (callbackName) { case "generateLightning": this.generateLightning(); case "kernel_update": this.uniforms.kernel = (0,_lib_image_transforms__WEBPACK_IMPORTED_MODULE_4__.computeKernel)(this.params); case "updateTemptint": this.updateTemptint(); return; } this.log.warn(`No callback ${callbackName} exists`); } onParamsChange(callback) { this.onParamsChangeCallbacks.push(callback); } updateParams(params) { /* Calculate difference */ const updateKeys = Object.keys(this.params).filter(paramKey => { return this.params[paramKey] !== params[paramKey]; }); updateKeys.forEach(paramKey => { this._updateParam(paramKey, params[paramKey]); }); const updates = this.getCallbacks(updateKeys); /* Update with callbacks */ updates.forEach(callbackName => { this.runCallback(callbackName); }); this.update(); this.onParamsChangeCallbacks.forEach(callback => { if (callback) { try { callback(this.params); } catch (err) { // Ignored } } }); } getCallbacks(updatedParams) { const callbacks = new Set(updatedParams.filter(key => _lib_constants__WEBPACK_IMPORTED_MODULE_1__.paramsCallbacks[key] !== undefined && _lib_constants__WEBPACK_IMPORTED_MODULE_1__.paramsCallbacks[key] !== null) .map(key => _lib_constants__WEBPACK_IMPORTED_MODULE_1__.paramsCallbacks[key]) .reduce((acc, v) => acc.concat(v), [])); return Array.from(callbacks); } // Do not call this method from any other function than updateParams _updateParam(param, value) { const keys = Object.keys(this.params); if (keys.includes(param)) { // @ts-ignore this.params[param] = value; } else { this.log.error(`Param ${param} does not exists`); } } autoZoom() { const widthX = this.config.width / this.WIDTH; const heightX = this.config.height / this.HEIGHT; const maxX = Math.max(widthX, heightX); this.setZoom(maxX); } setZoom(zoom) { this.updateParams({ ...this.params, zoom: zoom }); this.update(); } getWidth() { return this.WIDTH; } getHeight() { return this.HEIGHT; } setWidth(width) { this.WIDTH = width; } setHeight(height) { this.HEIGHT = height; } getCanvas() { return this.gl.canvas; } // FIXME: To Math class get2dRotation() { return [ Math.sin(this.params.rotation), Math.cos(this.params.rotation) ]; } get2dRotationCenter() { const x = (this.params.rotation_center.x + 1) * this.WIDTH / 2.0; const y = (this.params.rotation_center.y + 1) * this.HEIGHT / 2.0; return [x, y]; } loadImage(url) { return new Promise((resolve, reject) => { const image = new Image(); image.onload = () => { if (this.currentImage == null) { this.log.warn('Load Image called without image.'); return; } this.WIDTH = image.width; this.HEIGHT = image.height; this.fitCanvas(image.width, image.height); this.create(this.currentImage); resolve(); }; image.onerror = (err) => { this.log.error("Error while loading the image."); reject(err); }; this.currentImage = image; image.src = url; this.realImage = image; }); } async load(url, config) { this.log.log("Version 1.4.0"); // Save real image as a copy if (config !== undefined) { this.config = config; } await this.loadImage(url); return this; } setLog(log) { this.log = log; } // Temp and Tint updateTemptint() { this.uniforms.temptint = (0,_lib_image_transforms__WEBPACK_IMPORTED_MODULE_4__.tempTint)(this.params); } /** * Lightning generation: * Map brightness values depending on Brightness, Contrast... etc */ generateLightning() { this.LIGHT_MATCH = (0,_lib_image_transforms__WEBPACK_IMPORTED_MODULE_4__.lightning)(this.params); } blob(type, quality) { return new Promise((resolve, reject) => { if (this.realImage === null) { this.log.warn('Called to blob without loaded image'); return reject(); } this.create(this.realImage); this.getCanvas().toBlob((blob) => { if (blob === null) { this.log.error('Unable to generate the blob file'); return reject(); } resolve(blob); }, type || "image/jpeg", quality || 1); }); } /** * create * Prepare the environment to edit the image * image: Image element to edit (Image object) * context: webgl context. Default: __window.gl * SET_FULL_RES: no resize the image to edit. Default: false (resize the image) */ create(image, preventRenderImage) { // Load GSLS programs try { const VERTEX_SHADER_CODE = (0,_shaders__WEBPACK_IMPORTED_MODULE_5__.createShader)(this.gl, this.gl.VERTEX_SHADER, _shaders_index__WEBPACK_IMPORTED_MODULE_2__.VERTEX_SHADER); const FRAGMENT_SHADER_CODE = (0,_shaders__WEBPACK_IMPORTED_MODULE_5__.createShader)(this.gl, this.gl.FRAGMENT_SHADER, _shaders_index__WEBPACK_IMPORTED_MODULE_2__.FRAGMENT_SHADER); this.program = (0,_shaders__WEBPACK_IMPORTED_MODULE_5__.createProgram)(this.gl, VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE); } catch (err) { return this.log.error(err); } this.context = new _lib_context__WEBPACK_IMPORTED_MODULE_6__.Context(this.gl, this.program); this.log.log("[IMAGE] width = " + this.WIDTH + ", height = " + this.HEIGHT); this.log.log("[CANVAS] width = " + this.canvas.width + ", height = " + this.canvas.height); this.setRectangle(this.context.createBuffer("ARRAY_BUFFER"), 0.0, 0.0, this.WIDTH, this.HEIGHT); this.setRectangle(this.context.createBuffer("TEXCOORD_BUFFER"), 0, 0, 1.0, 1.0); this.gl.activeTexture(this.gl.TEXTURE0); // Upload the image into the texture. (0,_shaders__WEBPACK_IMPORTED_MODULE_5__.createTexture)(this.gl); try { this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image); } catch (err) { return this.log.error(err); } // Upload the LUT (contrast, brightness...) this.gl.activeTexture(this.gl.TEXTURE1); (0,_shaders__WEBPACK_IMPORTED_MODULE_5__.createTexture)(this.gl); this.gl.viewport(0, 0, this.WIDTH, this.HEIGHT); this.gl.clearColor(0, 0, 0, 0); this.gl.clear(this.gl.COLOR_BUFFER_BIT); if (!preventRenderImage) { this.update(); } } fitCanvas(width, height) { this.canvas.width = width; this.canvas.height = height; } update() { this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.ALPHA, 256, 1, 0, this.gl.ALPHA, this.gl.UNSIGNED_BYTE, new Uint8Array(this.LIGHT_MATCH)); this.gl.useProgram(this.program); this.gl.enableVertexAttribArray(this.context.getAttribute("a_position")); this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.context.getBuffer("ARRAY_BUFFER")); this.gl.vertexAttribPointer(this.context.getAttribute("a_position"), 2, this.gl.FLOAT, false, 0, 0); this.gl.enableVertexAttribArray(this.context.getAttribute("a_texCoord")); this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.context.getBuffer("TEXCOORD_BUFFER")); this.gl.vertexAttribPointer(this.context.getAttribute("a_texCoord"), 2, this.gl.FLOAT, false, 0, 0); this.gl.uniform2f(this.context.getUniform("u_resolution"), this.WIDTH, this.HEIGHT); this.gl.uniform2f(this.context.getUniform("u_textureSize"), this.WIDTH, this.HEIGHT); this.gl.uniform1f(this.context.getUniform("u_brightness"), this.params.brightness); this.gl.uniform1f(this.context.getUniform("u_contrast"), this.params.contrast); this.gl.uniform1f(this.context.getUniform("u_exposure"), this.params.exposure); this.gl.uniform1f(this.context.getUniform("u_contrast"), this.params.contrast); this.gl.uniform1f(this.context.getUniform("u_saturation"), this.params.saturation); this.gl.uniform1f(this.context.getUniform("u_masking"), this.params.masking); this.gl.uniform1f(this.context.getUniform("u_dehaze"), this.params.dehaze); this.gl.uniform1f(this.context.getUniform("u_atmosferic_light"), this.params.atmosferic_light); this.gl.uniform3fv(this.context.getUniform("u_temptint[0]"), this.uniforms.temptint .concat((0,_lib_color__WEBPACK_IMPORTED_MODULE_0__.asArray)((0,_lib_color__WEBPACK_IMPORTED_MODULE_0__.hsv2rgb)({ x: this.params.lightColor * 360, y: this.params.lightSat, z: this.params.lightFill }))) .concat((0,_lib_color__WEBPACK_IMPORTED_MODULE_0__.asArray)((0,_lib_color__WEBPACK_IMPORTED_MODULE_0__.hsv2rgb)({ x: this.params.darkColor * 360, y: this.params.darkSat, z: this.params.darkFill })))); // vec3 x3 this.gl.uniform1f(this.context.getUniform("u_bAndW"), this.params.bAndW); this.gl.uniform1f(this.context.getUniform("u_hdr"), this.params.hdr); this.gl.uniform2fv(this.context.getUniform("u_rotation"), this.get2dRotation()); this.gl.uniform2fv(this.context.getUniform("u_rotation_center"), this.get2dRotationCenter()); this.gl.uniform2f(this.context.getUniform("u_scale"), this.params.scale.x, this.params.scale.y); this.gl.uniform2f(this.context.getUniform("u_translate"), this.params.translate.x, this.params.translate.y); // Show image this.gl.uniform1i(this.context.getUniform("u_lut"), 1); // TEXTURE 1 // set the kernel and it's weight this.gl.uniform1fv(this.context.getUniform("u_kernel[0]"), this.uniforms.kernel); this.gl.uniform1f(this.context.getUniform("u_kernelWeight"), (0,_lib_image_transforms__WEBPACK_IMPORTED_MODULE_4__.sumArray)(this.uniforms.kernel)); /* Adjust canvas size: Cropping */ this.applyCrop(); this.gl.drawArrays(this.gl.TRIANGLES, 0, 6); } applyCrop() { const x2 = this.WIDTH * this.params.size.x; const y2 = this.HEIGHT * this.params.size.y; const cw = (this.params.zoom * x2); const ch = (this.params.zoom * y2); this.getCanvas().style.width = cw + "px"; this.getCanvas().style.height = ch + "px"; this.getCanvas().width = x2; this.getCanvas().height = y2; } setRectangle(buffer, x, y, width, height) { this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer); var x1 = x; var x2 = x + width; var y1 = y; var y2 = y + height; this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([ x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2, ]), this.gl.STATIC_DRAW); } } /***/ }), /***/ "./src/lib/color.ts": /*!**************************!*\ !*** ./src/lib/color.ts ***! \**************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "getLuma": () => (/* binding */ getLuma), /* harmony export */ "hsv2rgb": () => (/* binding */ hsv2rgb), /* harmony export */ "asArray": () => (/* binding */ asArray) /* harmony export */ }); /* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./math */ "./src/lib/math.ts"); /** * Color space functions */ const getLuma = (rgb_pix) => { return 0.2126 * rgb_pix.x + 0.7152 * rgb_pix.y + 0.0722 * rgb_pix.z; }; const hsv2rgb = (pixel_hsv) => { let a, d, c; let r, g, b; a = pixel_hsv.z * pixel_hsv.y; d = a * (1.0 - Math.abs((pixel_hsv.x / 60.0) % 2.0 - 1.0)); c = pixel_hsv.z - a; if (pixel_hsv.x < 180.0) { if (pixel_hsv.x < 60.0) { r = pixel_hsv.z; g = d + c; b = c; } else if (pixel_hsv.x < 120.0) { r = d + c; g = pixel_hsv.z; b = c; } else { r = c; g = pixel_hsv.z; b = d + c; } } else { if (pixel_hsv.x < 240.0) { r = c; g = d + c; b = pixel_hsv.z; } else if (pixel_hsv.x < 300.0) { r = d + c; g = c; b = a + c; } else { r = a + c; g = c; b = d + c; } } r = (0,_math__WEBPACK_IMPORTED_MODULE_0__.clamp)(r, 0.0, 1.0); g = (0,_math__WEBPACK_IMPORTED_MODULE_0__.clamp)(g, 0.0, 1.0); b = (0,_math__WEBPACK_IMPORTED_MODULE_0__.clamp)(b, 0.0, 1.0); return { x: r, y: g, z: b }; }; const asArray = (vec) => [vec.x, vec.y, vec.z]; /***/ }), /***/ "./src/lib/constants.ts": /*!******************************!*\ !*** ./src/lib/constants.ts ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "defaultConfig": () => (/* binding */ defaultConfig), /* harmony export */ "defaultParams": () => (/* binding */ defaultParams), /* harmony export */ "paramsCallbacks": () => (/* binding */ paramsCallbacks), /* harmony export */ "TEMP_DATA": () => (/* binding */ TEMP_DATA) /* harmony export */ }); const defaultConfig = { resolutionLimit: -1, editionResolutionLimit: -1, }; const defaultParams = { hdr: 0, exposure: 0, temperature: 0, tint: 0, brightness: 0, saturation: 0, contrast: 0, sharpen: 0, masking: 0, sharpen_radius: 0, radiance: 0, highlights: 0, shadows: 0, whites: 0, blacks: 0, dehaze: 0, bAndW: 0, atmosferic_light: 0, lightFill: 0, lightColor: 0, lightSat: 1, darkFill: 0, darkColor: 0, darkSat: 1, rotation: 0, rotation_center: { x: 0, y: 0, }, scale: { x: 1, y: 1, }, translate: { x: 0, y: 0, }, size: { x: 1, y: 1, }, zoom: 1, }; /** * Callbacks needed to be recalculated when changing parameters */ const paramsCallbacks = { contrast: ["generateLightning"], whites: ["generateLightning"], highlights: ["generateLightning"], shadows: ["generateLightning"], blacks: ["generateLightning"], radiance: ["generateLightning", "kernel_update"], hdr: ["kernel_update"], temperature: ["updateTemptint"], tint: ["updateTemptint"], sharpen: ["kernel_update"], sharpen_radius: ["kernel_update"], }; /** * Temperature map */ const TEMP_DATA = [ [0.6167426069865002, 0.017657981710823077], [0.5838624982041293, 0.06447754787874993], [0.5666570157784903, 0.1010769359975838], [0.5600215017846518, 0.13012054359808795], [0.5603460901328465, 0.15370282338343416], [0.5651414015638195, 0.1734071109259789], [0.5727157905223393, 0.19040417876076665], [0.5819305919306469, 0.20554787970182647], [0.5920253173976543, 0.219454396860673], [0.6024964973113273, 0.23256361077001078], [0.613014923688415, 0.2451851574423344], [0.6233694681448863, 0.2575325541865392], [0.633428991849502, 0.2697484189519574], [0.6431164873163056, 0.2819231700046263], [0.6523914777767198, 0.29410898225476145], [0.6612380004437802, 0.30633028466830314], [0.6696563786680246, 0.31859171532935343], [0.6776575761390952, 0.330884185957384], [0.6852593188363603, 0.34318952105568623], [0.6924834326806721, 0.3554840067292358], [0.6993540206164168, 0.36774109382812364], [0.705896221219359, 0.37993343721079975], [0.712135371070854, 0.3920344089104195], [0.7180964477199883, 0.4040191918024166], [0.7238037074478182, 0.41586553788423575], [0.7292804578150028, 0.42755425869079605], [0.7345489228275083, 0.43906950280216533], [0.7396301709912545, 0.4503988656030025], [0.7445440852278651, 0.4615333686006381], [0.7493093597375261, 0.47246733915721345], [0.7539435132044948, 0.4831982160881075], [0.7584629107855697, 0.4937263019887011], [0.7628827894765442, 0.5040544792219176], [0.7672172829757861, 0.5141879031216875], [0.7756812566990368, 0.5339005596070674], [0.7756812566990368, 0.5339005596070674], [0.7798336535847834, 0.5434985836882681], [0.7839465092903851, 0.552938802301879], [0.7880286368234596, 0.5622329533372938], [0.7920877696863722, 0.5713931712543325], [0.796130534601134, 0.5804317041849897], [0.8001624136045166, 0.5893606423074715], [0.8041876951180534, 0.5981916567442426], [0.8082094136732589, 0.6069357478075997], [0.8122292780585781, 0.6156030011340633], [0.8162475877574743, 0.624202350096731], [0.8202631376804659, 0.6327413428542148], [0.8242731113661302, 0.6412259124772712], [0.8282729630469863, 0.6496601487868902], [0.8322562892583072, 0.6580460708395705], [0.8362146910181553, 0.6663833994084263], [0.8401376280395388, 0.6746693293369075], [0.8440122669563406, 0.6828983022904387], [0.8478233261635671, 0.691061781205187], [0.8515529205921868, 0.6991480286361483], [0.8578515274860328, 0.7143328511178657], [0.8630349166004683, 0.7236145588845], [0.8630349166004683, 0.7236145588845], [0.8678866519883774, 0.7326305266929798], [0.8724265417351438, 0.7413920824039555], [0.8766746938112879, 0.7499106260961086], [0.8806514255414362, 0.7581975699581189], [0.8843771730729832, 0.7662642858505886], [0.8878724008449614, 0.7741220599147951], [0.8911575110568668, 0.7817820536219475], [0.8942527531374216, 0.7892552706795768], [0.8971781332133792, 0.7965525292390034], [0.9025975721615955, 0.8106613818669473], [0.9051296119968262, 0.8174934982533621], [0.9051296119968262, 0.8174934982533621], [0.9075675706910422, 0.8241906743465228], [0.9099288798932852, 0.8307625342003426], [0.912230184763394, 0.8372184337382709], [0.914487253441016, 0.8435674571884941], [0.9167148865142485, 0.8498184155292972], [0.9189268264883301, 0.8559798466723794], [0.9211356672547586, 0.862060017138353], [0.9233527635598611, 0.8680669250033681], [0.9278504028585166, 0.8798916280267886], [0.9301466448383797, 0.8857241176152066], [0.9324823592671754, 0.8915127453709542], [0.9348613471976668, 0.8972642431099969], [0.9348613471976668, 0.8972642431099969], [0.9372856273504615, 0.9029851088748369], [0.9397553455825536, 0.9086816143048344], [0.9422686843563701, 0.9143598121965675], [0.9448217722084058, 0.9200255441824128], [0.947408593218177, 0.925684448465339], [0.9500208964767429, 0.931341967556689], [0.9552772279767501, 0.9426736878435626], [0.9578927646784257, 0.9483578644262163], [0.9604766194871308, 0.954060621455171], [0.9630080085847714, 0.9597865363484674], [0.965463369977889, 0.9655400352277332], [0.965463369977889, 0.9655400352277332], [0.9678162729662736, 0.9713253997462401], [0.9700373276119754, 0.9771467737131783], [0.9720940942080452, 0.9830081695063213], [0.9739509927471266, 0.9889134742677088], [0.97556921239073, 0.9948664558790756], [0.9782396416593983, 1] ]; /***/ }), /***/ "./src/lib/context.ts": /*!****************************!*\ !*** ./src/lib/context.ts ***! \****************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Context": () => (/* binding */ Context) /* harmony export */ }); class Context { constructor(gl, program) { this.gl = gl; this.program = program; this.pointers = {}; this.atributes = {}; this.buffers = {}; } ; getUniform(uniform) { if (!this.pointers[uniform]) { this.pointers[uniform] = this.gl.getUniformLocation(this.program, uniform); } return this.pointers[uniform]; } getAttribute(atribute) { if (!this.atributes[atribute]) { this.atributes[atribute] = this.gl.getAttribLocation(this.program, atribute); } return this.atributes[atribute]; } createBuffer(bufferName) { this.buffers[bufferName] = this.gl.createBuffer(); return this.buffers[bufferName]; } getBuffer(bufferName) { return this.buffers[bufferName]; } } /***/ }), /***/ "./src/lib/image-transforms.ts": /*!*************************************!*\ !*** ./src/lib/image-transforms.ts ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "computeKernel": () => (/* binding */ computeKernel), /* harmony export */ "tempTint": () => (/* binding */ tempTint), /* harmony export */ "lightning": () => (/* binding */ lightning), /* harmony export */ "sumArray": () => (/* binding */ sumArray) /* harmony export */ }); /* harmony import */ var _color__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./color */ "./src/lib/color.ts"); /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants */ "./src/lib/constants.ts"); /* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./math */ "./src/lib/math.ts"); /** * Computes an 3x3 kernel for image processing */ const computeKernel = (params) => { let sharpness = -params.sharpen; let radius = params.sharpen_radius; const radiance = params.radiance; const hdr = params.hdr; if (radiance != 0) { sharpness -= 0.5 * radiance; radius += 0.5 * radiance; } if (hdr != 0) { sharpness -= 0.5 * hdr; radius += 0.5 * hdr; } const A = sharpness * Math.exp(-Math.pow(1 / radius, 2)); const B = sharpness * Math.exp(-Math.pow(1.41 / radius, 2)); const C = sharpness * Math.exp(-Math.pow(2 / radius, 2)); const D = sharpness * Math.exp(-Math.pow(2.24 / radius, 2)); const E = sharpness * Math.exp(-Math.pow(2.83 / radius, 2)); let X = 1; if (sharpness < 0) { X += 4 * Math.abs(E) + 8 * Math.abs(D) + 4 * Math.abs(C) + 4 * Math.abs(B) + 4 * Math.abs(A); } return [E, D, C, D, E, D, B, A, B, D, C, A, X, A, C, D, B, A, B, D, E, D, C, D, E]; }; const tempTint = (params) => { let T = params.temperature; let tint = params.tint; let R, G, B; if (T < 0) { R = 1; const i = _constants__WEBPACK_IMPORTED_MODULE_1__.TEMP_DATA[Math.floor((T + 1) * 100)]; // Tab values, algorithm is hard G = i[0]; B = i[1]; } else { R = 0.0438785 / (Math.pow(T + 0.150127, 1.23675)) + 0.543991; G = 0.0305003 / (Math.pow(T + 0.163976, 1.23965)) + 0.69136; B = 1; } if (tint == -1) { // HACK tint = -0.99; } G += tint; // Luma correction var curr_luma = (0,_color__WEBPACK_IMPORTED_MODULE_0__.getLuma)({ x: R, y: G, z: B }); var mult_K = 1 / curr_luma; return [R * mult_K, G * mult_K, B * mult_K]; }; const lightning = (params) => { const func = (0,_math__WEBPACK_IMPORTED_MODULE_2__.getCuadraticFunction)(params.blacks, params.shadows + 0.33, params.highlights + 0.66, params.whites + 1, 0, 0.33, 0.66, 1); let f_radiance = null; if (params.radiance != 0) { f_radiance = (0,_math__WEBPACK_IMPORTED_MODULE_2__.getCuadraticFunction)(0, 0.33 - params.radiance * 0.11, 0.66 + params.radiance * 0.11, 1, 0, 0.33, 0.66, 1); } const LIGHT_MATCH = []; for (let i = 0; i <= 255; i++) { let pixel_value = i / 255; // Radiance part if (params.radiance != 0) { pixel_value = f_radiance(pixel_value); } pixel_value = func(pixel_value); if (pixel_value > 1) { pixel_value = 1; } if (pixel_value < 0) { pixel_value = 0; } LIGHT_MATCH[i] = pixel_value * 255; } return LIGHT_MATCH; }; /** * kernelNormalization * Compute the total weight of the kernel in order to normalize it */ const sumArray = (kernel) => kernel.reduce((a, b) => a + b); /***/ }), /***/ "./src/lib/math.ts": /*!*************************!*\ !*** ./src/lib/math.ts ***! \*************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "clamp": () => (/* binding */ clamp), /* harmony export */ "resTreatment": () => (/* binding */ resTreatment), /* harmony export */ "getCuadraticFunction": () => (/* binding */ getCuadraticFunction) /* harmony export */ }); const clamp = (a, b, c) => { return (a < b) ? b : (a > c) ? c : a; }; const resTreatment = (arr) => arr.map(v => Math.round(v * 1000) / 1000); const getCuadraticFunction = (a, b, c, d, aa = 0, bb = 0.33, cc = 0.66, dd = 1) => { const aaS = Math.pow(aa, 2); const bbS = Math.pow(bb, 2); const ccS = Math.pow(cc, 2); const ddS = Math.pow(dd, 2); const aaT = aaS * aa; const bbT = bbS * bb; const ccT = ccS * cc; const ddT = ddS * dd; const res = resTreatment(solve4x4([aaT, bbT, ccT, ddT], [aaS, bbS, ccS, ddS], [aa, bb, cc, dd], [a, b, c, d])); return function (x) { let _r = res[3]; let xx = x; _r += res[2] * xx; xx *= x; _r += res[1] * xx; xx *= x; _r += res[0] * xx; return _r; }; }; function solve4x4(w, x, y, s) { let S, W, X, Y, Z; let _S, _W, _X, _Y, _Z; const Aa = y[2] - y[3]; const Ad = w[2] - w[3]; const Ab = x[2] - x[3]; const Ah = s[2] - s[3]; const Ac = x[2] * y[3] - y[2] * x[3]; const Af = w[2] * y[3] - y[2] * w[3]; const Ag = w[2] * x[3] - x[2] * w[3]; const Ai = s[2] * y[3] - y[2] * s[3]; const Aj = s[2] * x[3] - x[2] * s[3]; const Ak = w[2] * s[3] - s[2] * w[3]; const Al = x[2] * s[3] - s[2] * x[3]; const Am = y[2] * s[3] - s[2] * y[3]; W = x[1] * Aa - y[1] * Ab + Ac; X = w[1] * Aa - y[1] * Ad + Af; Y = w[1] * Ab - x[1] * Ad + Ag; Z = w[1] * Ac - x[1] * Af + y[1] * Ag; _S = w[0] * W - x[0] * X + y[0] * Y - Z; S = x[1] * Aa - y[1] * Ab + Ac; X = s[1] * Aa - y[1] * Ah + Ai; Y = s[1] * Ab - x[1] * Ah + Aj; Z = s[1] * Ac - x[1] * Ai + y[1] * Aj; _W = s[0] * S - x[0] * X + y[0] * Y - Z; W = s[1] * Aa - y[1] * Ah + Ai; S = w[1] * Aa - y[1] * Ad + Af; Y = w[1] * Ah - s[1] * Ad + Ak; Z = w[1] * Ai - s[1] * Af + y[1] * Ak; _X = w[0] * W - s[0] * S + y[0] * Y - Z; W = x[1] * Ah - s[1] * Ab + Al; X = w[1] * Ah - s[1] * Ad + Ak; S = w[1] * Ab - x[1] * Ad + Ag; Z = w[1] * Al - x[1] * Ak + s[1] * Ag; _Y = w[0] * W - x[0] * X + s[0] * S - Z; W = x[1] * Am - y[1] * Al + s[1] * Ac; X = w[1] * Am - y[1] * Ak + s[1] * Af; Y = w[1] * Al - x[1] * Ak + s[1] * Ag; S = w[1] * Ac - x[1] * Af + y[1] * Ag; _Z = w[0] * W - x[0] * X + y[0] * Y - s[0] * S; return [_W / _S, _X / _S, _Y / _S, _Z / _S]; } /***/ }), /***/ "./src/log/LogFacade.ts": /*!******************************!*\ !*** ./src/log/LogFacade.ts ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "LogFacade": () => (/* binding */ LogFacade) /* harmony export */ }); class LogFacade { log(msg) { console.log(msg); } warn(msg) { console.warn(msg); } error(msg) { console.error(msg); } } /***/ }), /***/ "./src/shaders.ts": /*!************************!*\ !*** ./src/shaders.ts ***! \************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "createShader": () => (/* binding */ createShader), /* harmony export */ "createProgram": () => (/* binding */ createProgram), /* harmony export */ "createTexture": () => (/* binding */ createTexture) /* harmony export */ }); const createShader = (gl, type, source) => { var shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (success) { return shader; } console.warn(gl.getError()); gl.deleteShader(shader); throw new Error("Unable to create a WebGL shader."); }; const createProgram = (gl, vertexShader, fragmentShader) => { const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); const success = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { return program; } console.warn(gl.getError()); gl.deleteProgram(program); throw new Error("Unable to create a WebGL Program."); }; const createTexture = (gl) => { const texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); return texture; }; /***/ }), /***/ "./src/shaders/index.ts": /*!******************************!*\ !*** ./src/shaders/index.ts ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FRAGMENT_SHADER": () => (/* reexport safe */ _raw_loader_fragment_shader_frag__WEBPACK_IMPORTED_MODULE_0__.default), /* harmony export */ "VERTEX_SHADER": () => (/* reexport safe */ _raw_loader_vertex_shader_vert__WEBPACK_IMPORTED_MODULE_1__.default) /* harmony export */ }); /* harmony import */ var _raw_loader_fragment_shader_frag__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !!raw-loader!./fragment_shader.frag */ "./node_modules/raw-loader/dist/cjs.js!./src/shaders/fragment_shader.frag"); /* harmony import */ var _raw_loader_vertex_shader_vert__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !!raw-loader!./vertex_shader.vert */ "./node_modules/raw-loader/dist/cjs.js!./src/shaders/vertex_shader.vert"); /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(__webpack_module_cache__[moduleId]) { /******/ return __webpack_module_cache__[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports /******/ __webpack_require__.r = (exports) => { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. (() => { /*!**********************!*\ !*** ./src/index.ts ***! \**********************/ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "RextEditor": () => (/* reexport safe */ _editor__WEBPACK_IMPORTED_MODULE_0__.RextEditor) /* harmony export */ }); /* harmony import */ var _editor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./editor */ "./src/editor.ts"); })(); /******/ return __webpack_exports__; /******/ })() ; }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9SZXh0RWRpdG9yL3dlYnBhY2svdW5pdmVyc2FsTW9kdWxlRGVmaW5pdGlvbiIsIndlYnBhY2s6Ly9SZXh0RWRpdG9yLy4vc3JjL3NoYWRlcnMvZnJhZ21lbnRfc2hhZGVyLmZyYWciLCJ3ZWJwYWNrOi8vUmV4dEVkaXRvci8uL3NyYy9zaGFkZXJzL3ZlcnRleF9zaGFkZXIudmVydCIsIndlYnBhY2s6Ly9SZXh0RWRpdG9yLy4vc3JjL2VkaXRvci50cyIsIndlYnBhY2s6Ly9SZXh0RWRpdG9yLy4vc3JjL2xpYi9jb2xvci50cyIsIndlYnBhY2s6Ly9SZXh0RWRpdG9yLy4vc3JjL2xpYi9jb25zdGFudHMudHMiLCJ3ZWJwYWNrOi8vUmV4dEVkaXRvci8uL3NyYy9saWIvY29udGV4dC50cyIsIndlYnBhY2s6Ly9SZXh0RWRpdG9yLy4vc3JjL2xpYi9pbWFnZS10cmFuc2Zvcm1zLnRzIiwid2VicGFjazovL1JleHRFZGl0b3IvLi9zcmMvbGliL21hdGgudHMiLCJ3ZWJwYWNrOi8vUmV4dEVkaXRvci8uL3NyYy9sb2cvTG9nRmFjYWRlLnRzIiwid2VicGFjazovL1JleHRFZGl0b3IvLi9zcmMvc2hhZGVycy50cyIsIndlYnBhY2s6Ly9SZXh0RWRpdG9yLy4vc3JjL3NoYWRlcnMvaW5kZXgudHMiLCJ3ZWJwYWNrOi8vUmV4dEVkaXRvci93ZWJwYWNrL2Jvb3RzdHJhcCIsIndlYnBhY2s6Ly9SZXh0RWRpdG9yL3dlYnBhY2svcnVudGltZS9kZWZpbmUgcHJvcGVydHkgZ2V0dGVycyIsIndlYnBhY2s6Ly9SZXh0RWRpdG9yL3dlYnBhY2svcnVudGltZS9oYXNPd25Qcm9wZXJ0eSBzaG9ydGhhbmQiLCJ3ZWJwYWNrOi8vUmV4dEVkaXRvci93ZWJwYWNrL3J1bnRpbWUvbWFrZSBuYW1lc3BhY2Ugb2JqZWN0Iiwid2VicGFjazovL1JleHRFZGl0b3IvLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FB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