UNPKG

27.5 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.Shader = undefined;
7
8var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
9
10var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
11
12var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
13
14var _core = require('../core');
15
16var _utils = require('../utils');
17
18var _scope = require('../scope');
19
20var _defines = require('./defines');
21
22function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
23
24function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
25
26function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
27
28var Shader = exports.Shader = function (_Component) {
29 _inherits(Shader, _Component);
30
31 _createClass(Shader, null, [{
32 key: 'defaults',
33 value: function defaults() {
34 return _extends({}, _core.ShaderLib.defaults(), { defines: {} });
35 }
36 }]);
37
38 function Shader(ctx) {
39 var initialState = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
40
41 _classCallCheck(this, Shader);
42
43 (0, _utils.assignDefaults)(initialState, Shader.defaults());
44 var shaderName = initialState.shaderName;
45
46 var contextCache = {};
47 var shaderCache = {};
48 var shaderLib = new _core.ShaderLib(_extends({}, initialState));
49
50 var injectShaderDefines = _core.Component.compose(new _defines.ShaderDefines(ctx, _extends({}, initialState.defines)));
51
52 var didDefinesChange = false;
53
54 var injectContext = null;
55
56 var fragmentShaderUncompiled = null;
57 var vertexShaderUncompiled = null;
58 var fragmentShader = null;
59 var vertexShader = null;
60
61 var hashMap = {};
62
63 var _this = _possibleConstructorReturn(this, (Shader.__proto__ || Object.getPrototypeOf(Shader)).call(this, ctx, initialState, update));
64
65 function update(state, block, previousState) {
66 injectShaderDefines(function (reglContext) {
67 var _state$forceCompile = state.forceCompile,
68 forceCompile = _state$forceCompile === undefined ? false : _state$forceCompile;
69 var defines = reglContext.defines;
70
71
72 if (Object.keys(defines).length) {
73 if (shaderLib.preprocessor.define(defines)) {
74 didDefinesChange = true;
75 forceCompile = true;
76 }
77 }
78
79 if (forceCompile || shouldCompile(reglContext, state)) {
80 compile(reglContext, state);
81 }
82
83 setInjectContext(reglContext, state);
84
85 didDefinesChange = false;
86 if ('function' == typeof injectContext) {
87 injectContext(state, block);
88 } else {
89 block(state);
90 }
91 });
92 }
93
94 function hash(str) {
95 if (hashMap[str]) {
96 return hashMap[str];
97 }
98 return hashMap[str] = shaderLib.hash(str);
99 }
100
101 function getShaderFromCache(reglContext, currentState, shader) {
102 shader = getViableShader(reglContext, currentState, shader);
103 return shaderCache[hash(shader)];
104 }
105
106 function setInjectContext(reglContext, currentState) {
107 var opts = {
108 context: {
109 fragmentShader: function (_fragmentShader) {
110 function fragmentShader(_x2) {
111 return _fragmentShader.apply(this, arguments);
112 }
113
114 fragmentShader.toString = function () {
115 return _fragmentShader.toString();
116 };
117
118 return fragmentShader;
119 }(function (_ref) {
120 var fs = _ref.fragmentShader;
121 return fragmentShader || fs;
122 }),
123 vertexShader: function (_vertexShader) {
124 function vertexShader(_x3) {
125 return _vertexShader.apply(this, arguments);
126 }
127
128 vertexShader.toString = function () {
129 return _vertexShader.toString();
130 };
131
132 return vertexShader;
133 }(function (_ref2) {
134 var vs = _ref2.vertexShader;
135 return vertexShader || vs;
136 })
137 }
138 };
139
140 if (!currentState.fragmentShader && !currentState.vertexShader) {
141 return;
142 }
143
144 var requestedFragmentShader = getShaderFromCache(reglContext, currentState, currentState.fragmentShader);
145
146 var requestedVertexShader = getShaderFromCache(reglContext, currentState, currentState.vertexShader);
147
148 if (!requestedVertexShader && !requestedFragmentShader) {
149 return;
150 }
151
152 if (requestedFragmentShader && requestedFragmentShader != fragmentShader) {
153 fragmentShader = requestedFragmentShader;
154 }
155
156 if (requestedVertexShader && requestedVertexShader != vertexShader) {
157 vertexShader = requestedVertexShader;
158 }
159
160 if ('string' == typeof fragmentShader) {
161 opts.frag = fragmentShader;
162 }
163
164 if ('string' == typeof vertexShader) {
165 opts.vert = vertexShader;
166 }
167
168 if ('string' == typeof opts.vert || 'string' == typeof opts.frag) {
169 if (injectContext) {
170 if (injectContext.opts.vert == opts.vert) {
171 if (injectContext.opts.frag == opts.frag) {
172 return;
173 }
174 }
175 }
176 var id = function (o) {
177 return [o.vert || '', o.frag || ''].map(hash).join('');
178 }(opts);
179 if (null == contextCache[id]) {
180 injectContext = ctx.regl(opts);
181 contextCache[id] = injectContext;
182 injectContext.opts = opts;
183 } else if (contextCache[id] != injectContext) {
184 injectContext = contextCache[id];
185 }
186 }
187 }
188
189 function compile(reglContext, currentState) {
190 if (didDefinesChange || !isShaderCached(currentState.vertexShader)) {
191 compileVertexShader();
192 }
193
194 if (didDefinesChange || !isShaderCached(currentState.fragmentShader)) {
195 compileFragmentShader();
196 }
197
198 function compileShader(type, shader) {
199 var compiled = null;
200 var uncompiled = null;
201 if (isViableShader(shader)) {
202 uncompiled = getViableShader(reglContext, currentState, shader);
203 compiled = shaderLib.compile(shaderName + ' (' + type + ')', uncompiled);
204 compiled = shaderLib.preprocess(compiled);
205 return { compiled: compiled, uncompiled: uncompiled };
206 }
207 return null;
208 }
209
210 function isShaderCached(shader) {
211 return Boolean(getShaderFromCache(reglContext, currentState, shader));
212 }
213
214 function compileVertexShader() {
215 var result = compileShader('vertex', currentState.vertexShader);
216 if (result) {
217 vertexShader = result.compiled;
218 vertexShaderUncompiled = result.uncompiled;
219 shaderCache[hash(vertexShaderUncompiled)] = vertexShader;
220 }
221 }
222
223 function compileFragmentShader() {
224 var result = compileShader('fragment', currentState.fragmentShader);
225 if (result) {
226 fragmentShader = result.compiled;
227 fragmentShaderUncompiled = result.uncompiled;
228 shaderCache[hash(fragmentShaderUncompiled)] = fragmentShader;
229 }
230 }
231 }
232
233 function getViableShader(reglContext, currentState, shader) {
234 var defines = shaderLib.defines;
235
236 var source = null;
237 if ('string' == typeof shader) {
238 source = shader;
239 } else if ('function' == typeof shader) {
240 source = shader(reglContext, currentState);
241 }
242 return source;
243 }
244
245 function isViableShader(shader) {
246 return ['string', 'function'].indexOf(typeof shader === 'undefined' ? 'undefined' : _typeof(shader)) > -1;
247 }
248
249 function shouldCompile(reglContext, currentState) {
250 var needsCompile = false;
251 check('function' != typeof injectContext);
252 checkShader(vertexShaderUncompiled, currentState.vertexShader);
253 checkShader(fragmentShaderUncompiled, currentState.fragmentShader);
254 return needsCompile;
255
256 function check(cond) {
257 if (cond) {
258 needsCompile = true;
259 }
260 }
261
262 function checkShader(current, next) {
263 next = getViableShader(reglContext, currentState, next);
264 if (shaderCache[hash(next)]) {
265 return check(false);
266 } else if ('string' != typeof current && 'string' == typeof next) {
267 return check(true);
268 } else if ('string' == typeof next && current != next) {
269 return check(true);
270 }
271 }
272 }
273 return _this;
274 }
275
276 return Shader;
277}(_core.Component);
278//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zaGFkZXIvc2hhZGVyLmpzIl0sIm5hbWVzIjpbIlNoYWRlciIsImRlZmF1bHRzIiwiZGVmaW5lcyIsImN0eCIsImluaXRpYWxTdGF0ZSIsInNoYWRlck5hbWUiLCJjb250ZXh0Q2FjaGUiLCJzaGFkZXJDYWNoZSIsInNoYWRlckxpYiIsImluamVjdFNoYWRlckRlZmluZXMiLCJjb21wb3NlIiwiZGlkRGVmaW5lc0NoYW5nZSIsImluamVjdENvbnRleHQiLCJmcmFnbWVudFNoYWRlclVuY29tcGlsZWQiLCJ2ZXJ0ZXhTaGFkZXJVbmNvbXBpbGVkIiwiZnJhZ21lbnRTaGFkZXIiLCJ2ZXJ0ZXhTaGFkZXIiLCJoYXNoTWFwIiwidXBkYXRlIiwic3RhdGUiLCJibG9jayIsInByZXZpb3VzU3RhdGUiLCJyZWdsQ29udGV4dCIsImZvcmNlQ29tcGlsZSIsIk9iamVjdCIsImtleXMiLCJsZW5ndGgiLCJwcmVwcm9jZXNzb3IiLCJkZWZpbmUiLCJzaG91bGRDb21waWxlIiwiY29tcGlsZSIsInNldEluamVjdENvbnRleHQiLCJoYXNoIiwic3RyIiwiZ2V0U2hhZGVyRnJvbUNhY2hlIiwiY3VycmVudFN0YXRlIiwic2hhZGVyIiwiZ2V0VmlhYmxlU2hhZGVyIiwib3B0cyIsImNvbnRleHQiLCJmcyIsInZzIiwicmVxdWVzdGVkRnJhZ21lbnRTaGFkZXIiLCJyZXF1ZXN0ZWRWZXJ0ZXhTaGFkZXIiLCJmcmFnIiwidmVydCIsImlkIiwibyIsIm1hcCIsImpvaW4iLCJyZWdsIiwiaXNTaGFkZXJDYWNoZWQiLCJjb21waWxlVmVydGV4U2hhZGVyIiwiY29tcGlsZUZyYWdtZW50U2hhZGVyIiwiY29tcGlsZVNoYWRlciIsInR5cGUiLCJjb21waWxlZCIsInVuY29tcGlsZWQiLCJpc1ZpYWJsZVNoYWRlciIsInByZXByb2Nlc3MiLCJCb29sZWFuIiwicmVzdWx0Iiwic291cmNlIiwiaW5kZXhPZiIsIm5lZWRzQ29tcGlsZSIsImNoZWNrIiwiY2hlY2tTaGFk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SUFBMUMsRUFBZ0Q7QUFDckQsaUJBQU9KLE1BQU0sSUFBTixDQUFQO0FBQ0Q7QUFDRjtBQUNGO0FBMU1pQztBQTJNbkMiLCJmaWxlIjoic2hhZGVyLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBTaGFkZXJMaWIgfSBmcm9tICcuLi9jb3JlJ1xuaW1wb3J0IHsgYXNzaWduRGVmYXVsdHMgfSBmcm9tICcuLi91dGlscydcbmltcG9ydCB7IFNjb3BlZENvbnRleHQgfSBmcm9tICcuLi9zY29wZSdcbmltcG9ydCB7IFNoYWRlckRlZmluZXMgfSBmcm9tICcuL2RlZmluZXMnXG5cbmV4cG9ydCBjbGFzcyBTaGFkZXIgZXh0ZW5kcyBDb21wb25lbnQge1xuICBzdGF0aWMgZGVmYXVsdHMoKSB7IHJldHVybiB7IC4uLlNoYWRlckxpYi5kZWZhdWx0cygpLCBkZWZpbmVzOiB7fSB9IH1cbiAgY29uc3RydWN0b3IoY3R4LCBpbml0aWFsU3RhdGUgPSB7fSkge1xuICAgIGFzc2lnbkRlZmF1bHRzKGluaXRpYWxTdGF0ZSwgU2hhZGVyLmRlZmF1bHRzKCkpXG4gICAgY29uc3QgeyBzaGFkZXJOYW1lIH0gPSBpbml0aWFsU3RhdGVcbiAgICBjb25zdCBjb250ZXh0Q2FjaGUgPSB7fVxuICAgIGNvbnN0IHNoYWRlckNhY2hlID0ge31cbiAgICBjb25zdCBzaGFkZXJMaWIgPSBuZXcgU2hhZGVyTGliKHsgLi4uaW5pdGlhbFN0YXRlIH0pXG5cbiAgICBjb25zdCBpbmplY3RTaGFkZXJEZWZpbmVzID0gQ29tcG9uZW50LmNvbXBvc2UoXG4gICAgICBuZXcgU2hhZGVyRGVmaW5lcyhjdHgsIHsgLi4uaW5pdGlhbFN0YXRlLmRlZmluZXMgfSksXG4gICAgKVxuXG4gICAgbGV0IGRpZERlZmluZXNDaGFuZ2UgPSBmYWxzZVxuXG4gICAgbGV0IGluamVjdENvbnRleHQgPSBudWxsXG5cbiAgICBsZXQgZnJhZ21lbnRTaGFkZXJVbmNvbXBpbGVkID0gbnVsbFxuICAgIGxldCB2ZXJ0ZXhTaGFkZXJVbmNvbXBpbGVkID0gbnVsbFxuICAgIGxldCBmcmFnbWVudFNoYWRlciA9IG51bGxcbiAgICBsZXQgdmVydGV4U2hhZGVyID0gbnVsbFxuXG4gICAgbGV0IGhhc2hNYXAgPSB7fVxuXG4gICAgc3VwZXIoY3R4LCBpbml0aWFsU3RhdGUsIHVwZGF0ZSlcbiAgICBmdW5jdGlvbiB1cGRhdGUoc3RhdGUsIGJsb2NrLCBwcmV2aW91c1N0YXRlKSB7XG4gICAgICBpbmplY3RTaGFkZXJEZWZpbmVzKChyZWdsQ29udGV4dCkgPT4ge1xuICAgICAgICBsZXQge2ZvcmNlQ29tcGlsZSA9IGZhbHNlfSA9IHN0YXRlXG4gICAgICAgIGNvbnN0IHtkZWZpbmVzfSA9IHJlZ2xDb250ZXh0XG5cbiAgICAgICAgaWYgKE9iamVjdC5rZXlzKGRlZmluZXMpLmxlbmd0aCkge1xuICAgICAgICAgIGlmIChzaGFkZXJMaWIucHJlcHJvY2Vzc29yLmRlZmluZShkZWZpbmVzKSkge1xuICAgICAgICAgICAgZGlkRGVmaW5lc0NoYW5nZSA9IHRydWVcbiAgICAgICAgICAgIGZvcmNlQ29tcGlsZSA9IHRydWVcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZm9yY2VDb21waWxlIHx8IHNob3VsZENvbXBpbGUocmVnbENvbnRleHQsIHN0YXRlKSkge1xuICAgICAgICAgIGNvbXBpbGUocmVnbENvbnRleHQsIHN0YXRlKVxuICAgICAgICB9XG5cbiAgICAgICAgc2V0SW5qZWN0Q29udGV4dChyZWdsQ29udGV4dCwgc3RhdGUpXG5cbiAgICAgICAgZGlkRGVmaW5lc0NoYW5nZSA9IGZhbHNlXG4gICAgICAgIGlmICgnZnVuY3Rpb24nID09IHR5cGVvZiBpbmplY3RDb250ZXh0KSB7XG4gICAgICAgICAgaW5qZWN0Q29udGV4dChzdGF0ZSwgYmxvY2spXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYmxvY2soc3RhdGUpXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaGFzaChzdHIpIHtcbiAgICAgIGlmIChoYXNoTWFwW3N0cl0pIHsgcmV0dXJuIGhhc2hNYXBbc3RyXSB9XG4gICAgICByZXR1cm4gKGhhc2hNYXBbc3RyXSA9IHNoYWRlckxpYi5oYXNoKHN0cikpXG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0U2hhZGVyRnJvbUNhY2hlKHJlZ2xDb250ZXh0LCBjdXJyZW50U3RhdGUsIHNoYWRlcikge1xuICAgICAgc2hhZGVyID0gZ2V0VmlhYmxlU2hhZGVyKHJlZ2xDb250ZXh0LCBjdXJyZW50U3RhdGUsIHNoYWRlcilcbiAgICAgIHJldHVybiBzaGFkZXJDYWNoZVtoYXNoKHNoYWRlcildXG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc2V0SW5qZWN0Q29udGV4dChyZWdsQ29udGV4dCwgY3VycmVudFN0YXRlKSB7XG4gICAgICBjb25zdCBvcHRzID0ge1xuICAgICAgICBjb250ZXh0OiB7XG4gICAgICAgICAgZnJhZ21lbnRTaGFkZXI6ICh7ZnJhZ21lbnRTaGFkZXI6IGZzfSkgPT4gZnJhZ21lbnRTaGFkZXIgfHwgZnMsXG4gICAgICAgICAgdmVydGV4U2hhZGVyOiAoe3ZlcnRleFNoYWRlcjogdnMgfSkgPT4gdmVydGV4U2hhZGVyIHx8IHZzLFxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICghY3VycmVudFN0YXRlLmZyYWdtZW50U2hhZGVyICYmICFjdXJyZW50U3RhdGUudmVydGV4U2hhZGVyKSB7XG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBjb25zdCByZXF1ZXN0ZWRGcmFnbWVudFNoYWRlciA9IGdldFNoYWRlckZyb21DYWNoZShcbiAgICAgICAgcmVnbENvbnRleHQsXG4gICAgICAgIGN1cnJlbnRTdGF0ZSxcbiAgICAgICAgY3VycmVudFN0YXRlLmZyYWdtZW50U2hhZGVyKVxuXG4gICAgICBjb25zdCByZXF1ZXN0ZWRWZXJ0ZXhTaGFkZXIgPSBnZXRTaGFkZXJGcm9tQ2FjaGUoXG4gICAgICAgIHJlZ2xDb250ZXh0LFxuICAgICAgICBjdXJyZW50U3RhdGUsXG4gICAgICAgIGN1cnJlbnRTdGF0ZS52ZXJ0ZXhTaGFkZXIpXG5cbiAgICAgIGlmICghcmVxdWVzdGVkVmVydGV4U2hhZGVyICYmICFyZXF1ZXN0ZWRGcmFnbWVudFNoYWRlcikge1xuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgaWYgKHJlcXVlc3RlZEZyYWdtZW50U2hhZGVyICYmIHJlcXVlc3RlZEZyYWdtZW50U2hhZGVyICE9IGZyYWdtZW50U2hhZGVyKSB7XG4gICAgICAgIGZyYWdtZW50U2hhZGVyID0gcmVxdWVzdGVkRnJhZ21lbnRTaGFkZXJcbiAgICAgIH1cblxuICAgICAgaWYgKHJlcXVlc3RlZFZlcnRleFNoYWRlciAmJiByZXF1ZXN0ZWRWZXJ0ZXhTaGFkZXIgIT0gdmVydGV4U2hhZGVyKSB7XG4gICAgICAgIHZlcnRleFNoYWRlciA9IHJlcXVlc3RlZFZlcnRleFNoYWRlclxuICAgICAgfVxuXG4gICAgICBpZiAoJ3N0cmluZycgPT0gdHlwZW9mIGZyYWdtZW50U2hhZGVyKSB7XG4gICAgICAgIG9wdHMuZnJhZyA9IGZyYWdtZW50U2hhZGVyXG4gICAgICB9XG5cbiAgICAgIGlmICgnc3RyaW5nJyA9PSB0eXBlb2YgdmVydGV4U2hhZGVyKSB7XG4gICAgICAgIG9wdHMudmVydCA9IHZlcnRleFNoYWRlclxuICAgICAgfVxuXG4gICAgICBpZiAoJ3N0cmluZycgPT0gdHlwZW9mIG9wdHMudmVydCB8fCAnc3RyaW5nJyA9PSB0eXBlb2Ygb3B0cy5mcmFnKSB7XG4gICAgICAgIGlmIChpbmplY3RDb250ZXh0KSB7XG4gICAgICAgICAgaWYgKGluamVjdENvbnRleHQub3B0cy52ZXJ0ID09IG9wdHMudmVydCkge1xuICAgICAgICAgICAgaWYgKGluamVjdENvbnRleHQub3B0cy5mcmFnID09IG9wdHMuZnJhZykge1xuICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgaWQgPSAoKG8pID0+IFtvLnZlcnR8fCcnLCBvLmZyYWd8fCcnXS5tYXAoaGFzaCkuam9pbignJykpKG9wdHMpXG4gICAgICAgIGlmIChudWxsID09IGNvbnRleHRDYWNoZVtpZF0pIHtcbiAgICAgICAgICBpbmplY3RDb250ZXh0ID0gY3R4LnJlZ2wob3B0cylcbiAgICAgICAgICBjb250ZXh0Q2FjaGVbaWRdID0gaW5qZWN0Q29udGV4dFxuICAgICAgICAgIGluamVjdENvbnRleHQub3B0cyA9IG9wdHNcbiAgICAgICAgfSBlbHNlIGlmIChjb250ZXh0Q2FjaGVbaWRdICE9IGluamVjdENvbnRleHQpIHtcbiAgICAgICAgICBpbmplY3RDb250ZXh0ID0gY29udGV4dENhY2hlW2lkXVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY29tcGlsZShyZWdsQ29udGV4dCwgY3VycmVudFN0YXRlKSB7XG4gICAgICBpZiAoZGlkRGVmaW5lc0NoYW5nZSB8fCAhaXNTaGFkZXJDYWNoZWQoY3VycmVudFN0YXRlLnZlcnRleFNoYWRlcikpIHtcbiAgICAgICAgY29tcGlsZVZlcnRleFNoYWRlcigpXG4gICAgICB9XG5cbiAgICAgIGlmIChkaWREZWZpbmVzQ2hhbmdlIHx8ICFpc1NoYWRlckNhY2hlZChjdXJyZW50U3RhdGUuZnJhZ21lbnRTaGFkZXIpKSB7XG4gICAgICAgIGNvbXBpbGVGcmFnbWVudFNoYWRlcigpXG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIGNvbXBpbGVTaGFkZXIodHlwZSwgc2hhZGVyKSB7XG4gICAgICAgIGxldCBjb21waWxlZCA9IG51bGxcbiAgICAgICAgbGV0IHVuY29tcGlsZWQgPSBudWxsXG4gICAgICAgIGlmIChpc1ZpYWJsZVNoYWRlcihzaGFkZXIpKSB7XG4gICAgICAgICAgdW5jb21waWxlZCA9IGdldFZpYWJsZVNoYWRlcihyZWdsQ29udGV4dCwgY3VycmVudFN0YXRlLCBzaGFkZXIpXG4gICAgICAgICAgY29tcGlsZWQgPSBzaGFkZXJMaWIuY29tcGlsZShgJHtzaGFkZXJOYW1lfSAoJHt0eXBlfSlgLCB1bmNvbXBpbGVkKVxuICAgICAgICAgIGNvbXBpbGVkID0gc2hhZGVyTGliLnByZXByb2Nlc3MoY29tcGlsZWQpXG4gICAgICAgICAgcmV0dXJuIHtjb21waWxlZCwgdW5jb21waWxlZH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbFxuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBpc1NoYWRlckNhY2hlZChzaGFkZXIpIHtcbiAgICAgICAgcmV0dXJuIEJvb2xlYW4oZ2V0U2hhZGVyRnJvbUNhY2hlKHJlZ2xDb250ZXh0LCBjdXJyZW50U3RhdGUsIHNoYWRlcikpXG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIGNvbXBpbGVWZXJ0ZXhTaGFkZXIoKSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGNvbXBpbGVTaGFkZXIoJ3ZlcnRleCcsIGN1cnJlbnRTdGF0ZS52ZXJ0ZXhTaGFkZXIpXG4gICAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgICB2ZXJ0ZXhTaGFkZXIgPSByZXN1bHQuY29tcGlsZWRcbiAgICAgICAgICB2ZXJ0ZXhTaGFkZXJVbmNvbXBpbGVkID0gcmVzdWx0LnVuY29tcGlsZWRcbiAgICAgICAgICBzaGFkZXJDYWNoZVtoYXNoKHZlcnRleFNoYWRlclVuY29tcGlsZWQpXSA9IHZlcnRleFNoYWRlclxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIGNvbXBpbGVGcmFnbWVudFNoYWRlcigpIHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gY29tcGlsZVNoYWRlcignZnJhZ21lbnQnLCBjdXJyZW50U3RhdGUuZnJhZ21lbnRTaGFkZXIpXG4gICAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgICBmcmFnbWVudFNoYWRlciA9IHJlc3VsdC5jb21waWxlZFxuICAgICAgICAgIGZyYWdtZW50U2hhZGVyVW5jb21waWxlZCA9IHJlc3VsdC51bmNvbXBpbGVkXG4gICAgICAgICAgc2hhZGVyQ2FjaGVbaGFzaChmcmFnbWVudFNoYWRlclVuY29tcGlsZWQpXSA9IGZyYWdtZW50U2hhZGVyXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRWaWFibGVTaGFkZXIocmVnbENvbnRleHQsIGN1cnJlbnRTdGF0ZSwgc2hhZGVyKSB7XG4gICAgICBjb25zdCB7ZGVmaW5lc30gPSBzaGFkZXJMaWJcbiAgICAgIGxldCBzb3VyY2UgPSBudWxsXG4gICAgICBpZiAoJ3N0cmluZycgPT0gdHlwZW9mIHNoYWRlcikge1xuICAgICAgICBzb3VyY2UgPSBzaGFkZXJcbiAgICAgIH0gZWxzZSBpZiAoJ2Z1bmN0aW9uJyA9PSB0eXBlb2Ygc2hhZGVyKSB7XG4gICAgICAgIHNvdXJjZSA9IHNoYWRlcihyZWdsQ29udGV4dCwgY3VycmVudFN0YXRlKVxuICAgICAgfVxuICAgICAgcmV0dXJuIHNvdXJjZVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzVmlhYmxlU2hhZGVyKHNoYWRlcikge1xuICAgICAgcmV0dXJuIFsnc3RyaW5nJywgJ2Z1bmN0aW9uJ10uaW5kZXhPZih0eXBlb2Ygc2hhZGVyKSA+IC0xXG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc2hvdWxkQ29tcGlsZShyZWdsQ29udGV4dCwgY3VycmVudFN0YXRlKSB7XG4gICAgICBsZXQgbmVlZHNDb21waWxlID0gZmFsc2VcbiAgICAgIGNoZWNrKCdmdW5jdGlvbicgIT0gdHlwZW9mIGluamVjdENvbnRleHQpXG4gICAgICBjaGVja1NoYWRlcih2ZXJ0ZXhTaGFkZXJVbmNvbXBpbGVkLCBjdXJyZW50U3RhdGUudmVydGV4U2hhZGVyKVxuICAgICAgY2hlY2tTaGFkZXIoZnJhZ21lbnRTaGFkZXJVbmNvbXBpbGVkLCBjdXJyZW50U3RhdGUuZnJhZ21lbnRTaGFkZXIpXG4gICAgICByZXR1cm4gbmVlZHNDb21waWxlXG5cbiAgICAgIGZ1bmN0aW9uIGNoZWNrKGNvbmQpIHtcbiAgICAgICAgaWYgKGNvbmQpIHsgbmVlZHNDb21waWxlID0gdHJ1ZSB9XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIGNoZWNrU2hhZGVyKGN1cnJlbnQsIG5leHQpIHtcbiAgICAgICAgbGV0IGNvbmQgPSBmYWxzZVxuICAgICAgICBuZXh0ID0gZ2V0VmlhYmxlU2hhZGVyKHJlZ2xDb250ZXh0LCBjdXJyZW50U3RhdGUsIG5leHQpXG4gICAgICAgIGlmIChzaGFkZXJDYWNoZVtoYXNoKG5leHQpXSkge1xuICAgICAgICAgIHJldHVybiBjaGVjayhmYWxzZSlcbiAgICAgICAgfSBlbHNlIGlmICgnc3RyaW5nJyAhPSB0eXBlb2YgY3VycmVudCAmJiAnc3RyaW5nJyA9PSB0eXBlb2YgbmV4dCkge1xuICAgICAgICAgIHJldHVybiBjaGVjayh0cnVlKVxuICAgICAgICB9IGVsc2UgaWYgKCdzdHJpbmcnID09IHR5cGVvZiBuZXh0ICYmIGN1cnJlbnQgIT0gbmV4dCkge1xuICAgICAgICAgIHJldHVybiBjaGVjayh0cnVlKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXX0=
\No newline at end of file