local-traffic 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -13
- package/dist/local-traffic.js +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ That is a secure http/2 (or insecure http1.1) reverse-proxy installed on your ma
|
|
|
5
5
|
- with 0 transitive dependency
|
|
6
6
|
- with 1 install step
|
|
7
7
|
- with a startup time of a few milliseconds
|
|
8
|
-
- with one
|
|
8
|
+
- with one 29kb index.js file
|
|
9
9
|
|
|
10
10
|
How simple is that ?
|
|
11
11
|
|
|
@@ -29,7 +29,8 @@ npx local-traffic
|
|
|
29
29
|
{
|
|
30
30
|
"mapping": {
|
|
31
31
|
"/npm/": "https://www.npmjs.com/",
|
|
32
|
-
"/my-static-webapp/
|
|
32
|
+
"/my-static-webapp/": "file:///home/user/projects/my-static-webapp/",
|
|
33
|
+
"/my-non-existing-webapp/": "file:///home/user/random/404.html",
|
|
33
34
|
"/welcome/": "data:text/html,<a href=\"https://ac.me/acme.js\">See my hobby project</a>",
|
|
34
35
|
"/(see-this-example|yet-another-example)": "http://example.com/$$1",
|
|
35
36
|
"/config/": "config://",
|
|
@@ -48,15 +49,15 @@ npx local-traffic
|
|
|
48
49
|
|
|
49
50
|
2. Go to [http://localhost:8080/prettier](http://localhost:8080/prettier) with your browser
|
|
50
51
|
3. Go to [http://localhost:8080/npm/](http://localhost:8080/npm) with your browser
|
|
51
|
-
4. Go to [http://localhost:8080/my-static-webapp/index.html](http://localhost:8080/my-static-webapp/index.html)
|
|
52
|
-
5. Go to [http://localhost:8080/
|
|
53
|
-
6. Go to [http://localhost:8080/
|
|
54
|
-
7. Go to [http://localhost:8080/
|
|
55
|
-
8. Go to [http://localhost:8080/
|
|
56
|
-
9.
|
|
57
|
-
10.
|
|
58
|
-
11.
|
|
59
|
-
12. Your
|
|
52
|
+
4. Go to [http://localhost:8080/my-static-webapp/index.html](http://localhost:8080/my-static-webapp/index.html) to test your webapp
|
|
53
|
+
5. Go to [http://localhost:8080/my-non-existing-webapp/admin/permissions](http://localhost:8080/my-non-existing-webapp/admin/permissions) to test your 404 page (>= 0.1.1)
|
|
54
|
+
6. Go to [http://localhost:8080/see-this-example](http://localhost:8080/see-this-example) or to [http://localhost:8080/yet-another-example](http://localhost:8080/yet-another-example) with your browser. Starting 0.0.89 and above, it supports regular expressions, and it is able to match them against the destination through string interpolation. Start with a double dollar sign (`$$`) followed by the index of the value in the [match array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match#return_value)
|
|
55
|
+
7. Go to [http://localhost:8080/welcome/](http://localhost:8080/welcome/) with your browser (data urls work with version >= 0.0.95)
|
|
56
|
+
8. Go to [http://localhost:8080/logs/](http://localhost:8080/logs/) to watch the request logs
|
|
57
|
+
9. Go to [http://localhost:8080/config/](http://localhost:8080/config/) to change the config in a web editor
|
|
58
|
+
10. You can use the [http://localhost:8080/recorder/](recorder) to turn your proxy into a mock server. There is a user interface and also an API (documented [here](#recorder-api))
|
|
59
|
+
11. From the web config editor, create a SSL keypair and start working with a self signed SSL certificate right away
|
|
60
|
+
12. Your page will use /jquery-local/jquery.js instead of the CDN asset, and will serve the file from your hard drive
|
|
60
61
|
|
|
61
62
|
## usage
|
|
62
63
|
|
|
@@ -71,7 +72,7 @@ npx local-traffic [location-of-the-local-traffic-config-file]
|
|
|
71
72
|
### from a node.js application (>= 0.0.72)
|
|
72
73
|
|
|
73
74
|
```bash
|
|
74
|
-
node -e '
|
|
75
|
+
node -e 'require("local-traffic").start({ /* configuration goes here */ })'
|
|
75
76
|
```
|
|
76
77
|
|
|
77
78
|
## how to change mappings to local / non-local
|
|
@@ -94,13 +95,36 @@ All boolean settings default to false when unspecified.
|
|
|
94
95
|
- `dontTranslateLocationHeader`: (`boolean`) when getting a response location header, in case `replaceResponseBodyUrls` does not change the URL, change the origin to the proxy anyway
|
|
95
96
|
- `dontUseHttp2Downstream`: (`boolean`) force calling downstream services in http1.1 only (to save some time)
|
|
96
97
|
- `simpleLogs`: (`boolean`) disable colored logs for text terminals
|
|
97
|
-
- `logAccessInTerminal`: (`boolean`) write an access log in the terminal on each call (
|
|
98
|
+
- `logAccessInTerminal`: (`boolean` | 'with-mapping') write an access log in the terminal on each call (>= 0.1.2 : 'with-mapping' will log the key used to find the target)
|
|
98
99
|
- `websocket`: (`boolean`) true to activate websocket connections proxying via sockets. Required for logs UI.
|
|
99
100
|
- `disableWebSecurity`: (`boolean`) true for easygoing values in cross origin requests or content security policy headers
|
|
100
101
|
- `connectTimeout`: (`number`) max time before aborting the connection (defaults to 3000ms)
|
|
101
102
|
- `socketTimeout`: (`number`) max time waiting for a response (defaults to 3000ms)
|
|
102
103
|
- `unwantedHeaderNamesInMocks`: (`string[]`) header names that won't get added to the mock request matchers
|
|
103
104
|
|
|
105
|
+
## config API
|
|
106
|
+
|
|
107
|
+
(>= 0.1.1)
|
|
108
|
+
The configuration can be manipulated programmatically with an API.
|
|
109
|
+
It can be used if someone needs to automatically switch the routes or the options.
|
|
110
|
+
It can be used for canary deployment strategy (to switch between odd domain and even domain)
|
|
111
|
+
|
|
112
|
+
### post, put
|
|
113
|
+
|
|
114
|
+
Argument : the config itself
|
|
115
|
+
|
|
116
|
+
Updates the config, returns the new config once the update is complete
|
|
117
|
+
|
|
118
|
+
### get, head
|
|
119
|
+
|
|
120
|
+
Retrieves the current configuration.
|
|
121
|
+
use `Accept: application/json` to use the API mode.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
$ curl https://localhost:8443/config/ -XGET -k -H'Accept: application/json'
|
|
125
|
+
{"mapping":{"/config/":"config://","":"https://github.com/"},"port":443,"replaceRequestBodyUrls":true,"replaceResponseBodyUrls":true}
|
|
126
|
+
```
|
|
127
|
+
|
|
104
128
|
## recorder API
|
|
105
129
|
|
|
106
130
|
(>= 0.0.86)
|
package/dist/local-traffic.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var e,t=this&&this.__awaiter||function(e,t,n,o){return new(n||(n=Promise))((function(r,s){function i(e){try{l(o.next(e))}catch(e){s(e)}}function a(e){try{l(o.throw(e))}catch(e){s(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,a)}l((o=o.apply(e,t||[])).next())}))},n=this&&this.__rest||function(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&t.indexOf(o)<0&&(n[o]=e[o]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var r=0;for(o=Object.getOwnPropertySymbols(e);r<o.length;r++)t.indexOf(o[r])<0&&Object.prototype.propertyIsEnumerable.call(e,o[r])&&(n[o[r]]=e[o[r]])}return n};Object.defineProperty(exports,"__esModule",{value:!0}),exports.update=exports.serve=exports.determineMapping=exports.send=exports.cleanEntropy=exports.replaceTextUsingMapping=exports.replaceBody=exports.acknowledgeWebsocket=exports.readWebsocketBuffer=exports.createWebsocketBufferFrom=exports.websocketServe=exports.recorderHandler=exports.quickStatus=exports.errorListener=exports.load=exports.start=void 0;const o=require("http2"),r=require("http"),s=require("https"),i=require("url"),a=require("fs"),l=require("zlib"),d=require("path"),c=require("crypto"),u=require("process"),p=require("os");var m,g,h,f;!function(e){e[e.ERROR=124]="ERROR",e[e.INFO=93]="INFO",e[e.WARNING=172]="WARNING"}(m||(m={})),function(e){e.INBOUND="↘️ ",e.PORT="☎️ ",e.OUTBOUND="↗️ ",e.RULES="🔗",e.MOCKS="🌐",e.STRICT_MOCKS="🕸️",e.AUTO_RECORD="📼",e.REWRITE="✒️ ",e.LOGS="📝",e.RESTART="🔄",e.WEBSOCKET="☄️ ",e.COLORED="✨",e.SHIELD="🛡️ ",e.NO="⛔",e.ERROR_1="❌",e.ERROR_2="⛈️ ",e.ERROR_3="☢️ ",e.ERROR_4="⁉️ ",e.ERROR_5="⚡",e.ERROR_6="☠️ "}(g||(g={})),function(e){e.INBOUND="INBOUND",e.OUTBOUND="OUTBOUND"}(h||(h={})),function(e){e.PROXY="proxy",e.MOCK="mock"}(f||(f={}));const v=(0,d.resolve)((0,p.homedir)(),".local-traffic.json"),y=(0,d.resolve)((0,u.cwd)(),u.argv.slice(-1)[0].endsWith(".json")?u.argv.slice(-1)[0]:v),b=()=>{var e,t;return null!==(t=null===(e=u.hrtime.bigint)||void 0===e?void 0:e.call(u.hrtime))&&void 0!==t?t:(()=>{const e=(0,u.hrtime)();return 1e3*e[0]+e[1]/1e6})()},O=e=>{const t=new Date;return`${e?"":"[36m"}${`${t.getHours()}`.padStart(2,"0")}${e?":":"[33m:[36m"}${`${t.getMinutes()}`.padStart(2,"0")}${e?":":"[33m:[36m"}${`${t.getSeconds()}`.padStart(2,"0")}${e?"":"[0m"}`},k=function(e,n){return t(this,void 0,void 0,(function*(){var t,o,r,s,i,a,l;const d=n.map((e=>e.map((e=>e.text.replace(/⎸/g,"|").replace(/⎹/g,"|").replace(/\u001b\[[^m]*m/g,"").replace(new RegExp(g.INBOUND,"g"),"inbound:").replace(new RegExp(g.PORT,"g"),"port:").replace(new RegExp(g.OUTBOUND,"g"),"outbound:").replace(new RegExp(g.RULES,"g"),"rules:").replace(new RegExp(g.NO,"g"),"").replace(new RegExp(g.REWRITE,"g"),"+rewrite").replace(new RegExp(g.WEBSOCKET,"g"),"websocket").replace(new RegExp(g.SHIELD,"g"),"web-security").replace(new RegExp(g.MOCKS,"g"),"mocks").replace(new RegExp(g.STRICT_MOCKS,"g"),"mocks (strict)").replace(new RegExp(g.AUTO_RECORD,"g"),"auto record").replace(new RegExp(g.LOGS,"g"),"logs").replace(new RegExp(g.RESTART,"g"),"restart").replace(new RegExp(g.COLORED,"g"),"colored").replace(/\|+/g,"|"))).join(" | ")));if(null===(t=null==e?void 0:e.config)||void 0===t?void 0:t.simpleLogs)for(let t of d)console.log(`${O(null===(o=null==e?void 0:e.config)||void 0===o?void 0:o.simpleLogs)} | ${t}`);else for(let t of n){const n=t.map((e=>`[48;5;${e.color}m${e.text}`));console.log(`${O(null===(r=null==e?void 0:e.config)||void 0===r?void 0:r.simpleLogs)}${t.map((e=>{var t;return`[48;5;${e.color}m${"".padEnd((null!==(t=e.length)&&void 0!==t?t:64)+1)}`})).join("▐")}[0m`),yield new Promise((e=>u.stdout.moveCursor(-1e3,-1,(()=>e(void 0)))));let o=9;for(let e=0;e<n.length;e++)yield new Promise((e=>u.stdout.moveCursor(-1e3,0,(()=>u.stdout.moveCursor(o,0,(()=>e(void 0))))))),u.stdout.write(n[e]),o+=(null!==(s=t[e].length)&&void 0!==s?s:64)+2;console.log("[0m");for(let n of d)null===(i=null==e?void 0:e.notifyLogsListeners)||void 0===i||i.call(e,{event:n,level:(c=null!==(l=null===(a=null==t?void 0:t[0])||void 0===a?void 0:a.color)&&void 0!==l?l:m.INFO,c===m.ERROR?"error":c===m.WARNING?"warning":"info")})}var c}))},w=(e,t)=>{var n;const o=Array(4).fill(0).map((()=>t?Math.floor(256*Math.random()):0)),r=e.split("").map(((e,t)=>e.charCodeAt(0)^o[3&t])),s=e.length,i=t?128:0,a=e.length<126?Buffer.from(Uint8Array.from([129,i+s]).buffer):e.length<65535?Buffer.concat([Buffer.from(Uint8Array.from([129,126|i]).buffer),Buffer.from(Uint8Array.from([s>>8]).buffer),Buffer.from(Uint8Array.from([255&s]).buffer)]):Buffer.concat([Buffer.from(Uint8Array.from([129,127|i]).buffer),Buffer.concat((null!==(n=Number(s).toString(16).padStart(16,"0").match(/.{2}/g))&&void 0!==n?n:["0"]).map((e=>parseInt(e,16))).map((e=>Buffer.from(Uint8Array.from([e]).buffer))))]),l=Buffer.from(Int8Array.from(o).buffer),d=Buffer.from(Int8Array.from(r).buffer);return Buffer.concat(t?[a,l,d]:[a,d])};exports.createWebsocketBufferFrom=w;const R=(e,t)=>{var n;if(!(t||1&e.readUInt8(0)))return{payloadLength:0,mask:[0,0,0,0],body:""};const o=t?0:e.readUInt8(1),r=o>>7,s=127&o,i=t?t.payloadLength:127!==s?s:e.readUInt8(2)<<8+e.readUInt8(3),a=t?t.mask:r?Array(4).fill(0).map(((t,n)=>e.readUInt8(n+4))):[0,0,0,0],l=t?0:r?8:4,d=Array(e.length-l).fill(0).map(((t,n)=>String.fromCharCode(e.readUInt8(n+l)^a[3&n]))).join("");return{payloadLength:i,mask:a,body:(null!==(n=null==t?void 0:t.body)&&void 0!==n?n:"").concat(d)}};exports.readWebsocketBuffer=R;const x=(e,t)=>{const n=(0,c.createHash)("sha1");n.update(t+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");const o=n.digest("base64");e.allowHalfOpen=!0,e.write(`HTTP/1.1 101 Switching Protocols\r\ndate: ${(new Date).toUTCString()}\r\nconnection: upgrade\r\nupgrade: websocket\r\nserver: local\r\nsec-websocket-accept: ${o}\r\n\r\n`)};exports.acknowledgeWebsocket=x;const E=function(e){return S(e,this.configListeners)},$=function(e){const{response:t}=e,o=n(e,["response"]);return Promise.all([S(e,this.logsListeners.filter((e=>e.wantsResponseMessage))),S(o,this.logsListeners.filter((e=>!e.wantsResponseMessage)))])},S=(e,t)=>{if(!t.length)return;const n=JSON.stringify(e),o=new Set(t.map((e=>e.wantsMask))),r=o.has(!1)&&w(n,!1),s=o.has(!0)&&w(n,!0),i=e=>{e.stream.errored&&e.stream.destroy()};t.forEach((e=>{e.stream.closed||e.stream.errored||(e.wantsMask?e.stream.write(s,"ascii",(()=>i(e))):e.stream.write(r,"ascii",(()=>i(e))))}))},C=function(){var e,t;return[{color:52,text:`${g.PORT} ${(null!==(e=this.config.port)&&void 0!==e?e:"").toString()}`,length:11},{color:53,text:`${g.OUTBOUND} ${this.config.dontUseHttp2Downstream?"H1.1":"H/2 "}${this.config.replaceRequestBodyUrls?g.REWRITE:" "}`,length:11},{color:54,text:`${g.INBOUND} ${this.config.ssl?"H/2 ":"H1.1"}${this.config.replaceResponseBodyUrls?g.REWRITE:" "}`,length:11},{color:55,text:""+(this.mode===f.PROXY&&this.mockConfig.autoRecord?`${g.AUTO_RECORD}${this.mockConfig.mocks.size.toString().padStart(3)}`:this.mode===f.PROXY?`${g.RULES}${Object.keys(null!==(t=this.config.mapping)&&void 0!==t?t:{}).length.toString().padStart(3)}`:`${this.mockConfig.strict?g.STRICT_MOCKS:g.MOCKS}${this.mockConfig.mocks.size.toString().padStart(3)}`),length:7},{color:56,text:`${this.config.websocket?g.WEBSOCKET:g.NO}`,length:4},{color:57,text:`${this.config.simpleLogs?g.NO:g.COLORED}`,length:4},{color:93,text:`${this.config.disableWebSecurity?g.NO:g.SHIELD}`,length:4}]},I=function(){return t(this,void 0,void 0,(function*(){this.log([this.buildQuickStatus()]),this.notifyConfigListeners(this.config)}))};exports.quickStatus=I;const B=(e,t,n,o,r)=>`${W(128163,"error",e.message)}\n<p>An error happened while trying to proxy a remote exchange</p>\n<div class="alert alert-warning" role="alert">\nⓘ This is not an error from the downstream service.\n</div>\n<div class="alert alert-danger" role="alert">\n<pre><code>${e.stack||`<i>${e.name} : ${e.message}</i>`}${e.errno?`<br/>(code : ${e.errno})`:""}</code></pre>\n</div>\nMore information about the request :\n<table class="table">\n<tbody>\n<tr>\n<td>server mode</td>\n<td>${t}</td>\n</tr>\n<tr>\n<td>phase</td>\n<td>${n}</td>\n</tr>\n<tr>\n<td>requested URL</td>\n<td>${o}</td>\n</tr>\n<tr>\n<td>downstream URL</td>\n<td>${r||"<no-target-url>"}</td>\n</tr>\n</tbody>\n</table>\n</div></body></html>`,q=(e,t,n)=>`<table id="table-access" class="table table-striped" style="display: block; width: 100%; overflow-y: auto">\n<thead>\n<tr>\n<th scope="col"${!0===n.captureResponseBody?' style="min-width: 120px"':""}>...</th>\n<th scope="col">Date</th>\n<th scope="col">Level</th>\n<th scope="col">Protocol</th>\n<th scope="col">Method</th>\n<th scope="col">Status</th>\n<th scope="col">Duration</th>\n<th scope="col">Upstream Path</th>\n<th scope="col">Downstream Path</th>\n</tr>\n</thead>\n<tbody id="access">\n</tbody>\n</table>\n<table id="table-proxy" class="table table-striped" style="display: none; width: 100%; overflow-y: auto">\n<thead>\n<tr>\n<th scope="col">Date</th>\n<th scope="col">Level</th>\n<th scope="col">Message</th>\n</tr>\n</thead>\n<tbody id="proxy">\n</tbody>\n</table>\n<script type="text/javascript">\nfunction start() {\ndocument.getElementById('table-access').style.height =\n(document.documentElement.clientHeight - 150) + 'px';\nconst socket = new WebSocket("ws${t.ssl?"s":""}://${e}/local-traffic-logs${n.captureResponseBody?"?wantsResponseMessage=true":""}");\nsocket.onmessage = function(event) {\nlet data = event.data\nlet uniqueHash;\ntry {\nconst { uniqueHash: uniqueHash1, ...data1 } = JSON.parse(event.data);\ndata = data1;\nuniqueHash = uniqueHash1;\n} catch(e) { }\nif (document.getElementById('mock-mode')?.checked) return;\nif (${!0===n.captureResponseBody} && \ndata?.downstreamPath?.startsWith('recorder://') &&\n!data?.upstreamPath?.endsWith('?forceLogInRecorderPage=true'))\nreturn;\nconst time = new Date().toISOString().split('T')[1].replace('Z', '');\nconst actions = getActionsHtmlText(uniqueHash, data.response);\nif(data.statusCode && uniqueHash) {\nconst color = getColorFromStatusCode(data.statusCode);\nconst statusCodeColumn = document.querySelector("#event-" + data.randomId + " .statusCode");\nif (statusCodeColumn)\nstatusCodeColumn.innerHTML = '<span class="badge bg-' + color + '">' + data.statusCode + '</span>';\n\nconst durationColumn = document.querySelector("#event-" + data.randomId + " .duration");\nif (durationColumn) {\nconst duration = data.duration > 10000 ? Math.floor(data.duration / 1000) + 's' :\ndata.duration + 'ms';\ndurationColumn.innerHTML = duration;\n}\n\nconst protocolColumn = document.querySelector("#event-" + data.randomId + " .protocol");\nif (protocolColumn) {\nprotocolColumn.innerHTML = data.protocol;\n}\n\nconst replayColumn = document.querySelector("#event-" + data.randomId + " .replay");\nif (replayColumn) {\nreplayColumn.innerHTML = actions;\n}\n} else if (uniqueHash) {\naddNewRequest(data.randomId, actions, time, data.level, data.protocol, data.method, \n'<span class="badge bg-secondary">...</span>', '⏱',\ndata.upstreamPath, data.downstreamPath);\n} else if(data.event) {\ndocument.getElementById("proxy")\n.insertAdjacentHTML('afterbegin', '<tr><td scope="col">' + time + '</td>' +\n'<td scope="col">' + (data.level || 'info')+ '</td>' + \n'<td scope="col">' + data.event + '</td></tr>');\n}\ncleanup();\n};\nsocket.onerror = function(error) {\nconsole.log(\`[error] \${JSON.stringify(error)}\`);\nsetTimeout(start, 5000);\n};\n};\nfunction show(id) {\n[...document.querySelectorAll('table')].forEach((table, index) => {\ntable.style.display = index === id ? 'block': 'none'\n});\n[...document.querySelectorAll('.navbar-nav .nav-item .nav-link')].forEach((link, index) => {\nif (index === id) { link.classList.add('active') } else link.classList.remove('active');\n});\n}\nfunction remove(event) {\nevent.target.closest('tr').remove();\nif (window.updateState) window.updateState();\n}\nfunction cleanup() {\nconst currentLimit = parseInt(document.getElementById('limit').value)\nfor (let table of ['access', 'proxy']) {\nwhile (currentLimit && document.getElementById(table).childNodes.length && \ndocument.getElementById(table).childNodes.length > currentLimit) {\n[...document.getElementById(table).childNodes].slice(-1)[0].remove();\n}\n}\n}\nfunction replay(event) {\nconst uniqueHash = event.target.dataset.uniquehash;\nconst { method, url, headers, body } = JSON.parse(atob(uniqueHash));\nfetch(url, {\nmethod,\nheaders,\nbody: !body || !body.length ? undefined : atob(body)\n});\n}\nfunction getActionsHtmlText(uniqueHash, response) {\nconst edit = ${!0===n.captureResponseBody} && uniqueHash\n? '<button data-response="' + (response ?? "") +\n'" data-uniquehash="' + uniqueHash + \n'" data-bs-toggle="modal" data-bs-target="#edit-request" type="button" ' +\n'class="btn btn-primary">📝</button>'\n: ''\nconst remove = ${!0===n.captureResponseBody} && uniqueHash\n? '<button onclick="javascript:remove(event)" type="button" ' +\n'class="btn btn-primary">❌</button>'\n: ''\nconst replay = ${!1===n.captureResponseBody} && uniqueHash ? '<button data-response="' + \nbtoa(JSON.stringify(response ?? {})) +\n'" data-uniquehash="' + uniqueHash + '" onclick="javascript:replay(event)" ' +\n'type="button" class="btn btn-primary">🔁</button>' : '';\nreturn edit + replay + remove\n}\nfunction addNewRequest(\nrandomId, actions, time, level, protocol, method, \nstatusCode, duration, upstreamPath, downstreamPath\n) {\ndocument.getElementById("access")\n.insertAdjacentHTML('afterbegin', '<tr id="event-' + randomId + '">' +\n'<td scope="col" class="replay">' + actions + '</td>' +\n'<td scope="col">' + time + '</td>' +\n'<td scope="col">' + (level || 'info')+ '</td>' + \n'<td scope="col" class="protocol">' + protocol + '</td>' + \n'<td scope="col" class="method">' + method + '</td>' + \n'<td scope="col" class="statusCode">' + statusCode + '</td>' +\n'<td scope="col" class="duration text-end">' + duration + '</td>' +\n'<td scope="col" class="upstream-path">' + upstreamPath + '</td>' + \n'<td scope="col">' + downstreamPath + '</td>' + \n'</tr>');\n}\nfunction getColorFromStatusCode(statusCode) {\nreturn Math.floor(statusCode / 100) === 1 ? "info" :\nMath.floor(statusCode / 100) === 2 ? "success" :\nMath.floor(statusCode / 100) === 3 ? "dark" :\nMath.floor(statusCode / 100) === 4 ? "warning" :\nMath.floor(statusCode / 100) === 5 ? "danger" :\n"secondary";\n}\nwindow.addEventListener("DOMContentLoaded", start);\n<\/script>`,N=(e,t,n)=>{let o={};try{o=JSON.parse(t.toString("ascii"))}catch(e){}if("object"!=typeof o||Object.keys(o).filter((e=>!["strict","mode","mocks","autoRecord"].includes(e))).length||!Array.isArray(o.mocks)&&void 0!==o.mocks)return void e.log([[{text:`${g.MOCKS} invalid mocks update received`,color:m.WARNING}]]);const{mocks:r,mode:s,strict:i,autoRecord:a}=o,l=r?new Map(r.map((({response:t,uniqueHash:n})=>[z(e.config,n),t]))):null,d=s!==e.mode&&s===f.PROXY,c=(!d||!0===a)&&(null!=a?a:e.mockConfig.autoRecord),u=void 0!==c&&c!=e.mockConfig.autoRecord,p=s!==e.mode&&s===f.MOCK||null!==l&&e.mockConfig.mocks.size!==l.size,h=null!=i?i:e.mockConfig.strict,v=null!=s?s:e.mode,y=!!h!=!!e.mockConfig.strict,b=n;ee(e,b?{mode:v,mockConfig:{autoRecord:!1,strict:h,mocks:new Map}}:{mode:v,mockConfig:{strict:h,autoRecord:c,mocks:null!=l?l:e.mockConfig.mocks}}),setTimeout((()=>{var t;return e.log([d?[{text:`${g.RULES} ${Object.keys(null!==(t=e.config.mapping)&&void 0!==t?t:{}).length.toString().padStart(5)} loaded mapping rules`,color:m.INFO}]:null,p?[{text:`${h?g.STRICT_MOCKS:g.MOCKS} ${(null!=l?l:e.mockConfig.mocks).size.toString().padStart(5)} loaded mocks`,color:m.INFO}]:null,y?[{text:`${h?g.STRICT_MOCKS:g.MOCKS} mocks strict mode : ${null!=h?h:e.mockConfig.strict}`,color:m.INFO}]:null,u?[{text:`${v===f.PROXY?g.AUTO_RECORD:h?g.STRICT_MOCKS:g.MOCKS} mocks auto-record : ${c}`,color:m.INFO}]:null,d||p||u||y||b?e.buildQuickStatus():null].filter((e=>e)))}),1)};exports.recorderHandler=N;const T=(e,n,o,i,a,l,d,c,u)=>t(void 0,void 0,void 0,(function*(){const t={hostname:e.hostname,path:i,port:e.port?e.port:"https:"===e.protocol?443:80,protocol:e.protocol,rejectUnauthorized:!1,method:a.method,headers:Object.assign(Object.assign({},Object.assign({},...Object.entries(l).filter((([e])=>!e.startsWith(":")&&"transfer-encoding"!==e.toLowerCase())).map((([e,t])=>({[e]:t}))))),{host:e.hostname})};let p=null;const m=p||[...L].includes(e.protocol)?null:yield new Promise((i=>{const l="https:"===e.protocol?(0,s.request)(t,i):(0,r.request)(t,i);l.on("error",(e=>{p=Buffer.from(B(e,u,"request",n,o)),i(null)})),c&&(l.write(d),l.end()),c||(a.on("data",(e=>l.write(e))),a.on("end",(()=>l.end())))}));if(p)throw p;return{alpnProtocol:"HTTP1.1",error:null,data:null,hasRun:!1,events:{},on:function(e,t){return"response"===e?null==t?void 0:t(Object.assign(Object.assign({},m.headers),{":status":m.statusCode,":statusmessage":m.statusMessage})):m.on(e,t)},end:function(){return this},request:function(){return this},write:function(){return this}}})),j={logs:(e,t)=>J(`${W(128250,"logs","")}\n<nav class="navbar navbar-expand-lg navbar-dark bg-primary nav-fill">\n<div class="container-fluid">\n<ul class="navbar-nav">\n<li class="nav-item">\n<a class="nav-link active" aria-current="page" href="javascript:show(0)">Access</a>\n</li>\n<li class="nav-item">\n<a class="nav-link" href="javascript:show(1)">Proxy</a>\n</li>\n</ul>\n<span class="navbar-text">\nLimit : <select id="limit" onchange="javascript:cleanup()"><option value="-1">0 (clear)</option><option value="10">10</option>\n<option value="50">50</option><option value="100">100</option><option value="200">200</option>\n<option selected="selected" value="500">500</option><option value="0">Infinity (discouraged)</option>\n</select> rows\n</span>\n</div>\n</nav>\n${q(e,t.config,{captureResponseBody:!1})}\n</body></html>`),config:(e,t)=>J(`${W(127899,"config","")}\n<link href="${M}jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">\n<script src="${M}jsoneditor/dist/jsoneditor.min.js"><\/script>\n<script src="${M}node-forge/dist/forge.min.js"><\/script>\n<div id="ssl-modal" class="modal" tabindex="-1" role="dialog">\n<div class="modal-dialog" role="document">\n<div class="modal-content">\n<div class="modal-header">\n<h5 class="modal-title">SSL keypair generation in progress</h5>\n</div>\n<div class="modal-body">\n<p>Wait a few seconds or move your mouse to increase the entropy.</p>\n</div>\n</div>\n</div>\n</div>\n<div id="jsoneditor" style="width: 400px; height: 400px;"></div>\n<script>\n// create the editor\nconst container = document.getElementById("jsoneditor")\nconst options = {mode: "code", allowSchemaSuggestions: true, schema: {\ntype: "object",\nproperties: {\n${Object.entries(Object.assign(Object.assign({},A),{ssl:{cert:"",key:""}})).map((([e,t])=>`${e}: {type: ${"unwantedHeaderNamesInMocks"===e?'"array","items": {"type":"string"}':"number"==typeof t?'"integer"':"string"==typeof t?'"string"':"boolean"==typeof t?'"boolean"':'"object"'}}`)).join(",\n ")}\n},\nrequired: [],\nadditionalProperties: false\n}}\n\nfunction save() {\nsocket.send(JSON.stringify(editor.get()));\n}\n\nfunction generateSslCertificate() {\nconst sslModal = new bootstrap.Modal(document.getElementById('ssl-modal'), {});\nsslModal.show()\nsetTimeout(function() {\nconst keypair = forge.pki.rsa.generateKeyPair(2048);\nconst certificate = forge.pki.createCertificate();\nconst now = new Date();\nconst fiveYears = new Date(new Date(now).setFullYear(now.getFullYear() + 5));\nObject.assign(certificate, {\npublicKey: keypair.publicKey,\nserialNumber: "01",\nvalidity: {\nnotBefore: now,\nnotAfter: fiveYears,\n},\n});\ncertificate.sign(keypair.privateKey, forge.md.sha256.create());\nconst key = forge.pki.privateKeyToPem(keypair.privateKey);\nconst cert = forge.pki.certificateToPem(certificate);\nconst existingConfig = editor.get();\neditor.set({ ...existingConfig, ssl: { key, cert },\nport: parseInt(("" + existingConfig.port).replace(/(80|[0-9])80$/, '443'))\n});\nsslModal.hide();\n}, 100);\n}\n\nconst editor = new JSONEditor(container, options);\nlet socket;\nconst initialJson = ${JSON.stringify(t.config)}\neditor.set(initialJson)\neditor.validate();\neditor.aceEditor.commands.addCommand({\nname: 'save',\nbindKey: {win: 'Ctrl-S', mac: 'Command-S'},\nexec: save,\n});\n\nwindow.addEventListener("DOMContentLoaded", function() {\ndocument.getElementById('jsoneditor').style.height =\n(document.documentElement.clientHeight - 150) + 'px';\ndocument.getElementById('jsoneditor').style.width =\nparseInt(window.getComputedStyle(\ndocument.querySelector('.container')).maxWidth) + 'px';\nconst sslButton = document.createElement('button');\nsslButton.addEventListener("click", generateSslCertificate);\nsslButton.type="button";\nsslButton.classList.add("btn");\nsslButton.classList.add("btn-primary");\nsslButton.innerHTML="🔒";\ndocument.querySelector('.jsoneditor-menu')\n.appendChild(sslButton);\nconst saveButton = document.createElement('button');\nsaveButton.addEventListener("click", save);\nsaveButton.type="button";\nsaveButton.classList.add("btn");\nsaveButton.classList.add("btn-primary");\nsaveButton.innerHTML="💾";\ndocument.querySelector('.jsoneditor-menu')\n.appendChild(saveButton);\nsocket = new WebSocket("ws${t.config.ssl?"s":""}://${e}/local-traffic-config");\nsocket.onmessage = function(event) {\neditor.set(JSON.parse(event.data))\neditor.validate()\n}\n});\n<\/script>\n</body></html>`),recorder:(e,t,n)=>{var o,r,s,i,a,l,d,c,u,p;return(null===(o=n.url)||void 0===o?void 0:o.endsWith("?forceLogInRecorderPage=true"))?J('{"ping":"pong"}',{contentType:"application/json; charset=utf-8"}):"GET"===n.method&&(null===(s=null===(r=n.headers)||void 0===r?void 0:r.accept)||void 0===s?void 0:s.includes("application/json"))?J(JSON.stringify(Object.assign(Object.assign({},t.mockConfig),{mode:t.mode,mocks:[...t.mockConfig.mocks.entries()].map((([e,t])=>({uniqueHash:e,response:t})))})),{contentType:"application/json; charset=utf-8"}):["PUT","POST","DELETE"].includes(null!==(i=n.method)&&void 0!==i?i:"")?J('{"status": "acknowledged"}',{contentType:"application/json; charset=utf-8",onOutboundWrite:e=>N(t,e,"DELETE"===n.method)}):J(`${W(9210,"recorder","")}\n<link href="${M}jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">\n<script src="${M}jsoneditor/dist/jsoneditor.min.js"><\/script>\n<script src="${M}pako/dist/pako.min.js"><\/script>\n<form>\n<div id="commands"${t.mockConfig.autoRecord?' style="filter:blur(8px)"':""}>\n<span>Mode : </span>\n<div class="btn-group" role="group" aria-label="Server Mode">\n<input type="radio" class="btn-check" name="server-mode" id="record-mode" autocomplete="off"${t.mode===f.PROXY?" checked":""}>\n<label class="btn btn-outline-primary" for="record-mode">⏺ Record</label>\n<input type="radio" class="btn-check" name="server-mode" id="mock-mode" autocomplete="off"${t.mode===f.MOCK?" checked":""}>\n<label class="btn btn-outline-primary" for="mock-mode">🌐 Mock</label>\n</div>\n<span>Actions : </span>\n<button type="button" class="btn btn-light" id="add-mock">➕ Mock from dummy request</button>\n<button type="button" class="btn btn-light" id="upload-mocks">📥 Upload mocks</button>\n<button type="button" class="btn btn-light" id="download-mocks">📦 Download mocks</button>\n<button type="button" class="btn btn-light" id="delete-mocks">🗑 Delete mocks</button>\n</div>\n<div class="row">\n<div class="col-lg" style="max-width: 200px">\n<div class="form-check form-switch" id="strict-mock-mode-form-control">\n<input class="form-check-input" type="checkbox" id="strict-mock-mode"${t.mockConfig.strict?' checked="checked"':""}>\n<label class="form-check-label" for="strict-mock-mode">Strict mock mode</label>\n</div>\n</div>\n<div class="col-lg" style="max-width: 200px">\n<div class="form-check form-switch">\n<input class="form-check-input" type="checkbox" id="auto-record-mode"${t.mockConfig.autoRecord?' checked="checked"':""}>\n<label class="form-check-label" for="auto-record-mode">Auto record mode</label>\n</div>\n</div>\n<div class="col-lg"> </div>\n</div>\n<input type="hidden" id="limit" value="0"/>\n<div class="modal fade" id="edit-request" tabindex="-1" \naria-labelledby="edit-request-label" aria-hidden="true">\n<div class="modal-dialog" style="max-width: 900px">\n<div class="modal-content">\n<div class="modal-header">\n<h1 class="modal-title fs-5" id="edit-request-label">Edit request to /</h1>\n<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>\n</div>\n<div class="modal-body">\n<div class="container">\n<div class="row">\n<div class="col-lg">\n<h2>Request :</h2>\n<div id="uniqueHash-editor" style="width: 400px; height: 400px;"></div>\n</div>\n<div class="col-lg">\n<h2>Response : </h2>\n<div id="response-editor" style="width: 400px; height: 400px;"></div>\n</div>\n</div>\n</div>\n</div>\n<div class="modal-footer">\n<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>\n<button type="button" class="btn btn-primary" onclick="javascript:saveRequest()">Save changes</button>\n</div>\n</div>\n</div>\n</div>\n<script>\nconst xmlOrJsonPrologsInBase64 = [\n"eyJ","PD94bWw=","PCFET0NUWVBF","PCFkb2N0eXBl","PGh0bWw","PEhUTUw","H4sIAAAAAAAA", "W3tc"\n];\nfunction getMocksData () {\nreturn JSON.stringify(\n[...document.querySelectorAll('button[data-uniqueHash]')].map(button => ({\nresponse: button.attributes['data-response']?.value,\nuniqueHash: button.attributes['data-uniqueHash']?.value}))\n)\n}\nfunction updateState () {\nfetch("http${t.config.ssl?"s":""}://${e}${null!==(d=null===(l=Object.entries(null!==(a=t.config.mapping)&&void 0!==a?a:{}).find((([e,t])=>{var n;return null===(n=null==t?void 0:t.toString())||void 0===n?void 0:n.startsWith("recorder:")})))||void 0===l?void 0:l[0])&&void 0!==d?d:"/recorder/"}", {\nmethod: 'PUT',\nheaders: { 'Content-Type': 'application/json' },\nbody: '{"strict":' + document.getElementById('strict-mock-mode').checked +\n',"autoRecord":' + document.getElementById('auto-record-mode').checked +\n',"mode":"' + \n(document.getElementById('mock-mode').checked ? "mock" : "proxy") + '"' +\n',"mocks":' + getMocksData() + '}'\n})\n}\nfunction loadMocks(mocksHashes) {\nconst time = new Date().toISOString().split('T')[1].replace('Z', '');\nlet mocks = [];\ntry {\nmocks = mocksHashes.map(mock => ({...mock, \nrequest: JSON.parse(atob(mock.uniqueHash)),\nresponse: JSON.parse(atob(mock.response))\n}));\n} catch(e) { }\nmocks.forEach(mock => {\nconst randomId = window.crypto.randomUUID();\nconst actions = getActionsHtmlText(mock.uniqueHash, mock.response);\naddNewRequest(randomId, actions, time, 'info', 'HTTP/2', mock.request.method, \n'<span class="badge bg-' + \ngetColorFromStatusCode(mock.response.status) + '">' + \nmock.response.status + \n'</span>', \n'0ms', mock.request.url, \n'N/A');\n});\n}\ndocument.getElementById('add-mock').addEventListener('click', () => {\nconst iframe = document.createElement('iframe');\niframe.style.display = 'none';\niframe.onload = function() { iframe.parentNode.removeChild(iframe); };\niframe.src = "http${t.config.ssl?"s":""}://${e}${null!==(p=null===(u=Object.entries(null!==(c=t.config.mapping)&&void 0!==c?c:{}).find((([e,t])=>{var n;return null===(n=null==t?void 0:t.toString())||void 0===n?void 0:n.startsWith("recorder:")})))||void 0===u?void 0:u[0])&&void 0!==p?p:"/recorder/"}?forceLogInRecorderPage=true";\ndocument.body.appendChild(iframe);\n});\ndocument.getElementById('upload-mocks').addEventListener('click', () => {\nconst time = new Date().toISOString().split('T')[1].replace('Z', '');\nconst fileInput = document.createElement('input');\nfileInput.type = "file";\nfileInput.multiple = "multiple";\nfileInput.onchange = function() {\nconst fileReader = new FileReader();\n[...fileInput.files].reduce((promise, file) =>\npromise.then(result => new Promise(resolve => {\nfileReader.readAsText(file);\nfileReader.onload = function(){\nresolve(result.concat(fileReader.result));\n};\n})), Promise.resolve([]))\n.then(files => files.flatMap(file => JSON.parse(file)))\n.catch(e => [])\n.then(mocks => loadMocks(mocks))\n.then(() => updateState());\n}\nfileInput.click();\n});\ndocument.getElementById('download-mocks').addEventListener('click', () => {\nconst link = document.createElement('a');\nlink.href = URL.createObjectURL(new Blob([getMocksData()], {\ntype: "application/json",\n}));\nlink.download = "mocks-" + new Date().toISOString() + ".json";\nlink.click();\nURL.revokeObjectURL(link.href);\n})\ndocument.getElementById('delete-mocks').addEventListener('click', () => {\ndocument.getElementById('limit').value = -1;\ncleanup();\nupdateState();\ndocument.getElementById('limit').value = 0;\n})\ndocument.getElementById('record-mode').addEventListener('change', () => {\ndocument.getElementById('limit').value = 0;\ncleanup();\nupdateState();\n})\ndocument.getElementById('mock-mode').addEventListener('change', () => {\nupdateState();\n})\ndocument.getElementById('auto-record-mode').addEventListener('change', (e) => { \nupdateState();\ndocument.getElementById('table-access').style.filter = \ndocument.getElementById('auto-record-mode').checked ? 'blur(8px)' : 'blur(0px)';\ndocument.getElementById('commands').style.filter = \ndocument.getElementById('auto-record-mode').checked ? 'blur(8px)' : 'blur(0px)';\ndocument.getElementById('alert-about-auto-record-mode').style.display = \ndocument.getElementById('auto-record-mode').checked ? 'block' : 'none';\ndocument.getElementById('strict-mock-mode-form-control').style.filter = \ndocument.getElementById('auto-record-mode').checked ? 'blur(8px)' : 'blur(0px)';\n\n})\ndocument.getElementById('strict-mock-mode').addEventListener('change', (e) => { \nupdateState();\n})\nfunction saveRequest () {\n$('#edit-request').modal("hide");\n\nconst requestBeingEdited = window.requestBeingEdited;\nlet request = uniqueHashEditor.get();\nlet response = responseEditor.get();\nif (typeof request.body === "object") {\nrequest.body = JSON.stringify(request.body);\n}\nif (typeof response.body === "object") {\nresponse.body = JSON.stringify(response.body);\n}\nconst oldRequest = JSON.parse(atob(requestBeingEdited.attributes['data-uniqueHash'].value));\nconst oldResponse = JSON.parse(atob(requestBeingEdited.attributes['data-response'].value));\nconst requestProlog = requestBeingEdited.attributes['data-requestProlog']?.value;\nconst responseProlog = requestBeingEdited.attributes['data-responseProlog']?.value;\nconst requestPrologHasChanged = request.body.substring(0, 10) !== oldRequest.body.substring(0, 10);\nconst responsePrologHasChanged = response.body.substring(0, 10) !== response.body.substring(0, 10);\nif (requestProlog === "H4sIAAAAAAAA" && !requestPrologHasChanged) {\nrequest.body =\nbtoa([...pako.gzip(request.body)].map(e => String.fromCharCode(e)).join(""));\n} else if ((requestProlog === null || !request.body.startsWith(requestProlog ?? "")) && \nrequest.body.substring(0, 10) !== oldRequest.body.substring(0, 10)) {\nrequest.body = btoa(request.body);\n}\nif (responseProlog === "H4sIAAAAAAAA" && !responsePrologHasChanged) {\nresponse.body =\nbtoa([...pako.gzip(response.body)].map(e => String.fromCharCode(e)).join(""));\n} else if ((responseProlog === null || !response.body.startsWith(responseProlog ?? "")) && \nresponse.body.substring(0, 10) !== oldResponse.body.substring(0, 10)) {\nresponse.body = btoa(response.body);\n}\nrequest = btoa(JSON.stringify(request));\nresponse = btoa(JSON.stringify(response));\nrequestBeingEdited.setAttribute('data-uniqueHash', request);\nrequestBeingEdited.setAttribute('data-response', response);\nconst row = requestBeingEdited.closest('tr');\nrow.querySelector("td.method").innerHTML = uniqueHashEditor.get().method;\nrow.querySelector("td.upstream-path").innerHTML = uniqueHashEditor.get().url;\nwindow.requestBeingEdited = undefined;\nupdateState();\n}\ndocument.getElementById('edit-request').addEventListener('show.bs.modal', event => {\nconst request = JSON.parse(atob(event.relatedTarget.attributes['data-uniqueHash'].value));\nconst response = JSON.parse(atob(event.relatedTarget.attributes['data-response'].value));\nconst requestProlog = xmlOrJsonPrologsInBase64.find(prolog => request.body?.startsWith(prolog));\nconst responseProlog = xmlOrJsonPrologsInBase64.find(prolog => response.body?.startsWith(prolog));\nif (requestProlog) {\nevent.relatedTarget.setAttribute('data-requestProlog', requestProlog);\nrequest.body = request.body.startsWith("H4sIAAAAAAAA") \n? pako.ungzip(new Uint8Array(atob(request.body).split("").map(e => e.charCodeAt(0))), {to: "string"})\n: atob(request.body);\nrequest.body = request.body.startsWith("{\\"") || request.body.startsWith("[{\\"")\n? JSON.parse(request.body) : request.body;\n}\nif (responseProlog) {\nevent.relatedTarget.setAttribute('data-responseProlog', responseProlog);\nresponse.body = response.body.startsWith("H4sIAAAAAAAA") \n? pako.ungzip(new Uint8Array(atob(response.body).split("").map(e => e.charCodeAt(0))), {to: "string"})\n: atob(response.body);\nresponse.body = response.body.startsWith("{\\"") || response.body.startsWith("[{\\"")\n? JSON.parse(response.body) : response.body;\n}\nwindow.requestBeingEdited = event.relatedTarget;\nwindow.uniqueHashEditor.set(request);\nwindow.responseEditor.set(response);\ndocument.getElementById('edit-request-label').innerText = "Edit request to " + request.url;\n})\n\nsetTimeout(() => {\nloadMocks(${JSON.stringify([...t.mockConfig.mocks.entries()].map((([e,t])=>({uniqueHash:e,response:t}))))});\nwindow.uniqueHashEditor = new JSONEditor(document.getElementById("uniqueHash-editor"), {\nmode: "code", allowSchemaSuggestions: true, schema: {\ntype: "object",\nproperties: {\nmethod: {type: "string"},\nurl: {type: "string"},\nbody: {oneOf: [{type:"string"},{type:"object"},{type:"array"}]},\nheaders: {type: "object"},\n},\nrequired: [],\nadditionalProperties: false\n}});\nwindow.responseEditor = new JSONEditor(document.getElementById("response-editor"), {\nmode: "code", allowSchemaSuggestions: true, schema: {\ntype: "object",\nproperties: {\nbody: {oneOf: [{type:"string"},{type:"object"},{type:"array"}]},\nheaders: {type: "object"},\nstatus: {type: "integer"}\n},\nrequired: [],\nadditionalProperties: false\n}});\n${t.mockConfig.autoRecord?";document.getElementById('strict-mock-mode-form-control').style.filter='blur(8px)';;document.getElementById('table-access').style.filter='blur(8px)';":""}\ndocument.forms[0].reset();\n}, 10)\n<\/script>\n</form>\n<div class="alert alert-warning" role="alert"\nstyle="display:${t.mockConfig.autoRecord?"block":"none"};left:20%;right:20%;position:absolute;z-index:1;" id="alert-about-auto-record-mode">\nⓘ Auto-record mode and recorder webapp are known to be mutually exclusive.\n<br/><br/>Changing the mocks on both sides is somehow hard to sort out.\n<br/>This is triggering concurrent modifications in the mock config.\n<hr/>\nHere is what you can do :\n<ul>\n<li>If you want to record mocks using a frontend app, turn off the auto-record mode.</li>\n<li>If you want to record mocks with the recorder API only, close this app.</li>\n</ul>\n</div>\n${q(e,t.config,{captureResponseBody:!0})}\n</body>\n</html>`)},file:(e,t,n,o)=>{const r=null==o?void 0:o.target,s=(0,d.resolve)("/",r.hostname,...r.pathname.replace(/[?#].*$/,"").replace(/^\/+/,"").split("/").map(decodeURIComponent));return{alpnProtocol:"file",error:null,data:null,hasRun:!1,run:function(){return this.hasRun?Promise.resolve():new Promise((e=>(0,a.readFile)(s,((t,n)=>{if(this.hasRun=!0,!t||"EISDIR"!==t.code)return this.error=t,this.data=n,void e(void 0);(0,a.readdir)(s,((t,n)=>{this.error=t,this.data=n,t?e(void 0):Promise.all(n.map((e=>new Promise((t=>(0,a.lstat)((0,d.resolve)(r.pathname,e),((n,o)=>t([e,o,n])))))))).then((t=>{const n=t.filter((e=>!e[2]&&e[1].isDirectory())).concat(t.filter((e=>!e[2]&&e[1].isFile())));this.data=`${W(128194,"directory",r.href)}<p>Directory content of <i>${r.href.replace(/\//g,"/")}</i></p><ul class="list-group"><li class="list-group-item">📁<a href="${r.pathname.endsWith("/")?"..":"."}"><parent></a></li>${n.filter((e=>!e[2])).map((e=>`<li class="list-group-item">&#x${(e[1].isDirectory()?128193:128196).toString(16)};<a href="${r.pathname.endsWith("/")?"":`${r.pathname.split("/").slice(-1)[0]}/`}${e[0]}">${e[0]}</a></li>`)).join("\n")}</li></ul></body></html>`,e(void 0)}))}))}))))},events:{},on:function(e,t){return this.events[e]=t,this.run().then((()=>{"response"===e&&this.events.response(s.endsWith(".svg")?{Server:"local","Content-Type":"image/svg+xml"}:{Server:"local"},0),"data"===e&&this.data&&(this.events.data(this.data),this.events.end()),"error"===e&&this.error&&this.events.error(this.error)})),this},end:function(){return this},request:function(){return this},write:function(){return this}}},data:(e,t,n,o)=>{var r,s,i,a,l,d;const[,c,u,p]=null!==(s=/^data:([^;,]*)?;?([^,]*)?,(.*)$/.exec(null!==(r=null==o?void 0:o.target.href)&&void 0!==r?r:"data:,"))&&void 0!==s?s:["","","",""],m=decodeURIComponent(p),g="base64"===u?Buffer.from(m,"base64url").toString("binary"):m;return J(t.config.replaceResponseBodyUrls?_(Buffer.from(g),{"content-type":c||"text/plain"},{mapping:null!==(i=t.config.mapping)&&void 0!==i?i:{},proxyHostnameAndPort:e,proxyHostname:null!==(a=null==o?void 0:o.proxyHostname)&&void 0!==a?a:"localhost",key:null!==(l=null==o?void 0:o.key)&&void 0!==l?l:"",direction:h.INBOUND,ssl:!!t.config.ssl,port:null!==(d=t.config.port)&&void 0!==d?d:null==A?void 0:A.port}):g,{contentType:c})}},P=Object.keys(j),L=P.map((e=>`${e}:`)),A={mapping:Object.assign({},...P.filter((e=>"data"!==e&&"file"!==e)).map((e=>({[`/${e}/`]:`${e}://`})))),port:8080,replaceRequestBodyUrls:!1,replaceResponseBodyUrls:!1,dontUseHttp2Downstream:!1,dontTranslateLocationHeader:!1,logAccessInTerminal:!1,simpleLogs:!1,websocket:!0,disableWebSecurity:!1,connectTimeout:3e3,socketTimeout:3e3,unwantedHeaderNamesInMocks:[]},H=(...e)=>t(void 0,[...e],void 0,(function*(e=!0){return new Promise((t=>(0,a.readFile)(y,((n,o)=>{n&&!e&&k(null,[[{text:`${g.ERROR_1} config error. Using default value`,color:m.ERROR}]]);let r=null;try{r=Object.assign({},A,JSON.parse((null!=o?o:"{}").toString()))}catch(e){return r=null!=r?r:Object.assign({},A),k({config:void 0},[[{text:`${g.ERROR_2} config syntax incorrect, ignoring`,color:m.ERROR}]]).then((()=>t(r)))}n&&"ENOENT"===n.code&&e&&y===v?(0,a.writeFile)(y,JSON.stringify(A,null,2),(e=>k(null,e?[[{text:`${g.ERROR_4} config file NOT created`,color:m.ERROR}]]:[[{text:`${g.COLORED} config file created`,color:m.INFO}]]).then((()=>t(r))))):t(r)}))))}));exports.load=H;const U=e=>""==e?"":(0,d.normalize)(e).replace(/\\/g,"/"),M="https://cdn.jsdelivr.net/npm/",D=["host","connection","keep-alive","upgrade","transfer-encoding","upgrade-insecure-requests","proxy-connection"],W=(e,t,n)=>`<!doctype html>\n<html lang="en">\n<head>\n<title>&#x${e.toString(16)}; local-traffic ${t} | ${n}</title>\n<link href="${M}bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"/>\n<script src="${M}jquery/dist/jquery.min.js"><\/script>\n<script src="${M}bootstrap/dist/js/bootstrap.bundle.min.js"><\/script>\n</head>\n<body><div class="container"><h1>&#x${e.toString(16)}; local-traffic ${t}</h1>\n<br/>`,F=({response:e})=>({alpnProtocol:"mock",error:null,data:null,hasRun:!1,run:function(){return this.hasRun?Promise.resolve():new Promise((t=>{try{this.data=JSON.parse(Buffer.from(e,"base64").toString("utf-8"))}catch(e){this.data={}}t(void 0)}))},events:{},on:function(e,t){return this.events[e]=t,this.run().then((()=>{var t;"response"===e&&this.events.response(Object.assign(Object.assign({},this.data.headers),{"X-LocalTraffic-Mock":"1"}),this.data.status),"data"===e&&this.data&&(this.events.data(Buffer.from(null!==(t=this.data.body)&&void 0!==t?t:"","base64")),this.events.end()),"error"===e&&this.error&&this.events.error(this.error)})),this},end:function(){return this},request:function(){return this},write:function(){return this}}),J=(e,t)=>({alpnProtocol:"static",error:null,data:null,outboundData:null,run:function(){return"string"==typeof e?new Promise((t=>{this.data=e,t(void 0)})):e.then((e=>{this.data=e.toString("utf8")}))},events:{},on:function(e,n){return this.events[e]=n,this.run().then((()=>{var n;"response"===e&&this.events.response({Server:"local","Content-Type":null!==(n=null==t?void 0:t.contentType)&&void 0!==n?n:"text/html"},0),"data"===e&&this.data&&(this.events.data(this.data),this.events.end()),"error"===e&&this.error&&this.events.error(this.error)})),this},write:function(e){var n;return this.outboundData=e,e instanceof Buffer&&(null===(n=null==t?void 0:t.onOutboundWrite)||void 0===n||n.call(t,e)),this},end:function(){return this},request:function(){return this}}),_=(e,n,o)=>t(void 0,void 0,void 0,(function*(){var r,s;return(null!==(s=null===(r=n["content-encoding"])||void 0===r?void 0:r.toString())&&void 0!==s?s:"").split(",").reduce(((e,n)=>t(void 0,void 0,void 0,(function*(){const t=n.trim().toLowerCase(),o="gzip"===t||"x-gzip"===t?l.gunzip:"deflate"===t?l.inflate:"br"===t?l.brotliDecompress:"identity"===t||""===t?(e,t)=>{t(null,e)}:null;if(null===o)throw new Error(`${t} compression not supported by the proxy`);const r=yield e;return yield new Promise(((e,t)=>o(r,((n,o)=>{n&&t(n),e(o)}))))}))),Promise.resolve(e)).then((e=>{const t=e.length>1e7,r=["text/html","application/javascript","application/json"].some((e=>{var t;return(null!==(t=n["content-type"])&&void 0!==t?t:"").toString().includes(e)}));return!t&&(r||!/[^\x00-\xFF]/.test(e.toString()))?K(e.toString(),{direction:o.direction,proxyHostnameAndPort:o.proxyHostnameAndPort,ssl:o.ssl,mapping:o.mapping}).replace(/\?protocol=wss?%3A&hostname=[^&]+&port=[0-9]+&pathname=/g,`?protocol=ws${o.ssl?"s":""}%3A&hostname=${o.proxyHostname}&port=${o.port}&pathname=${encodeURIComponent(o.key.replace(/\/+$/,""))}`):e})).then((e=>{var t,o;return(null!==(o=null===(t=n["content-encoding"])||void 0===t?void 0:t.toString())&&void 0!==o?o:"").split(",").reverse().reduce(((e,t)=>{const n=t.trim().toLowerCase(),o="gzip"===n||"x-gzip"===n?l.gzip:"deflate"===n?l.deflate:"br"===n?l.brotliCompress:"identity"===n||""===n?(e,t)=>{t(null,e)}:null;if(null===o)throw new Error(`${n} compression not supported by the proxy`);return e.then((e=>new Promise((t=>o(e,((e,n)=>{if(e)throw e;t(n)}))))))}),Promise.resolve(Buffer.from(e)))}))}));exports.replaceBody=_;const K=(e,{direction:t,proxyHostnameAndPort:n,ssl:o,mapping:r})=>Object.entries(r).map((([e,t])=>[e,"string"==typeof t?t:t.replaceBody])).reduce(((e,[r,s])=>L.some((e=>s.startsWith(e)))||""!==r&&!r.match(/^[-a-zA-Z0-9()@:%_\+.~#?&//=]*$/)?e:t===h.INBOUND?e.replace(new RegExp(s.replace(new RegExp(`^(${P.join("|")})://`),"").replace(/[*+?^${}()|[\]\\]/g,"").replace(/^https/,"https?")+"/*","ig"),`http${o?"s":""}://${n}${r.replace(/\/+$/,"")}/`):e.split(`http${o?"s":""}://${n}${r.replace(/\/+$/,"")}`).join(s)),e).split(`${n}/:`).join(`${n}:`);exports.replaceTextUsingMapping=K;const z=(e,t)=>{try{const n="object"==typeof t?t:JSON.parse(Buffer.from(t,"base64").toString("utf-8"));return["access-control-max-age","authorization","cache-control","cookie","date","dnt","expires","if-modified-since","if-unmodified-since","keep-alive","last-modified","pragma","proxy-authenticate","proxy-authorization","referer","retry-after","signed-headers","server-timing","sec-ch-ua","sec-ch-ua-mobile","sec-ch-ua-platform","sec-fetch-dest","sec-fetch-mode","sec-fetch-site","sec-fetch-user","upgrade-insecure-requests","user-agent",...Array.isArray(e.unwantedHeaderNamesInMocks)?e.unwantedHeaderNamesInMocks:[]].forEach((e=>{var t;null===(t=null==n?void 0:n.headers)||void 0===t||delete t[e]})),n.headers=Object.keys(n.headers).sort().reduce(((e,t)=>(e[t]=n.headers[t],e)),{}),Buffer.from(JSON.stringify(n),"utf-8").toString("base64")}catch(e){return t}};exports.cleanEntropy=z;const G=(e,t,n)=>{t.writeHead(e,{"content-type":"text/html","content-length":n.length}),t.end(n)};exports.send=G;const Y=(e,t)=>{var n,o,r,s,a,l,d,c;const u=(null!==(r=null!==(o=null===(n=e.headers[":authority"])||void 0===n?void 0:n.toString())&&void 0!==o?o:e.headers.host)&&void 0!==r?r:"localhost").replace(/:.*/,""),p=e.headers[":authority"]||`${e.headers.host}${(null!==(s=e.headers.host)&&void 0!==s?s:"").match(/:[0-9]+$/)?"":80!==t.port||t.ssl?443===t.port&&t.ssl?"":`:${null!==(a=t.port)&&void 0!==a?a:8080}`:""}`,m=new i.URL(`http${t.ssl?"s":""}://${p}${null!==(l=e.url)&&void 0!==l?l:""}`),g=m.href.substring(m.origin.length),h=Object.assign({},Object.assign({},...Object.entries(null!==(d=t.mapping)&&void 0!==d?d:{}).map((([e,t])=>{var n,o;const r="string"==typeof t?t:null!==(n=null==t?void 0:t.downstreamUrl)&&void 0!==n?n:"";return{[e]:new i.URL((null===(o=null==r?void 0:r.startsWith)||void 0===o?void 0:o.call(r,"data:"))?r:U(r))}}))));let f=null;const[v,y]=null!==(c=Object.entries(h).find((([e])=>{var t;return f=null!==(t=g.match(RegExp(e.replace(/^\//,"^/"))))&&void 0!==t?t:null})))&&void 0!==c?c:["/"],b=f&&y?new i.URL(y.href.replace(/\$\$(\d+)/g,((e,t)=>f[parseInt(t)]))):null;return{proxyHostname:u,proxyHostnameAndPort:p,url:m,path:g,key:v,target:b}};exports.determineMapping=Y;const X=function(e,t,n){var o,a,l,d,c,u,p,h,f,v;if(n.on("error",(()=>{e.log([[{text:`${g.WEBSOCKET} websocket connection reset`,color:m.WARNING}]])})),!e.config.websocket)return n.end("HTTP/1.1 503 Service Unavailable\r\n\r\n"),{};const{key:y,target:b,path:O,url:k}=Y(t,e.config);if(O.startsWith("/local-traffic-logs"))return x(n,null!==(o=t.headers["sec-websocket-key"])&&void 0!==o?o:""),{logsListeners:e.logsListeners.concat({stream:n,wantsMask:!(null!==(l=null===(a=t.headers["user-agent"])||void 0===a?void 0:a.toString())&&void 0!==l?l:"").includes("Chrome"),wantsResponseMessage:[...k.searchParams.entries()].some((([e,t])=>"wantsResponseMessage"===e&&"true"===t))})};if("/local-traffic-config"===O){x(n,null!==(d=t.headers["sec-websocket-key"])&&void 0!==d?d:"");let o=null;return n.on("data",(t=>{const n=R(t,o);if(null===o&&n.body.length<n.payloadLength)o=n;else{if(n.body.length>=n.payloadLength&&0===n.body.length)return{};if(n.body.length>=n.payloadLength){let t;o=null;try{t=JSON.parse(n.body)}catch(t){return e.log([[{text:`${g.ERROR_4} config file NOT read, try again later`,color:m.WARNING}]]),{}}ee(e,{pendingConfigSave:t})}}})),{configListeners:e.configListeners.concat({stream:n,wantsMask:!(null!==(u=null===(c=t.headers["user-agent"])||void 0===c?void 0:c.toString())&&void 0!==u?u:"").includes("Chrome")})}}const w=new i.URL(`${null!==(p=null==b?void 0:b.protocol)&&void 0!==p?p:"https"}//${null!==(h=null==b?void 0:b.host)&&void 0!==h?h:"localhost"}${null===(v=null===(f=t.url)||void 0===f?void 0:f.replace(new RegExp(`^${y}`,"g"),b.pathname))||void 0===v?void 0:v.replace(/^\/*/,"/")}`),E={hostname:w.hostname,path:w.pathname,port:w.port,protocol:w.protocol,rejectUnauthorized:!1,method:t.method,headers:Object.assign(Object.assign({},t.headers),{host:w.hostname,origin:w.origin}),host:w.hostname},$="https:"===w.protocol?(0,s.request)(E):(0,r.request)(E);return $.end(),$.on("error",(t=>{e.log([[{text:`${g.WEBSOCKET} websocket request has errored ${t.errno?`(${t.errno})`:""}`,color:m.WARNING}]])})),$.on("upgrade",((t,o)=>{const r=`HTTP/${t.httpVersion} ${t.statusCode} ${t.statusMessage}\r\n${Object.entries(t.headers).flatMap((([e,t])=>(Array.isArray(t)?t:[t]).map((t=>[e,t])))).map((([e,t])=>`${e}: ${t}\r\n`)).join("")}\r\n`;n.write(r),n.allowHalfOpen=!0,o.allowHalfOpen=!0,o.on("data",(e=>n.write(e))),n.on("data",(e=>o.write(e))),o.on("error",(t=>{e.log([[{text:`${g.WEBSOCKET} downstream socket has errored ${t.errno?`(${t.errno})`:""}`,color:m.WARNING}]])})),n.on("error",(t=>{e.log([[{text:`${g.WEBSOCKET} upstream socket has errored ${t.errno?`(${t.errno})`:""}`,color:m.WARNING}]])}))})),{}};exports.websocketServe=X;const Z=function(e,n,r){return t(this,void 0,void 0,(function*(){var s,a,l,d,p,v,O,k,w,R,x,E,$,S,C,I,q,N,P,H,M,W,J,X,Z,Q,V,ee,te,ne,oe;if(!n.headers.host&&!n.headers[":authority"])return void G(400,r,Buffer.from(B(new Error("client must supply a 'host' header"),e.mode,"proxy",new i.URL(`http${e.config.ssl?"s":""}://unknowndomain${n.url}`))));const{proxyHostname:re,proxyHostnameAndPort:se,url:ie,path:ae,key:le,target:de}=Y(n,e.config),ce=null!=de?de:e.mode===f.MOCK?new i.URL(`http${e.config.ssl?"s":""}://${se}/`):null;if(!ce)return void G(502,r,Buffer.from(B(new Error(`No mapping found in config file ${y}`),e.mode,"proxy",ie)));const ue="data:"===ce.protocol?"":"//",pe=ce.host.replace(RegExp(/\/+$/),""),me=ce.href.substring(`${ce.protocol}${ue}`.length+ce.host.length),ge="file:"===ce.protocol||"data:"===ce.protocol?me:`${me}${U(ae.replace(RegExp(U(le)),""))}`.replace(/^\/*/,"data:"===ce.protocol?"":"/"),he=new i.URL(`${ce.protocol}${ue}${pe}${ge}`),fe=L.some((e=>ce.protocol===e)),ve=(0,c.randomBytes)(20).toString("hex");let ye=null;const be=e.config.replaceRequestBodyUrls||!!e.logsListeners.length;e.config.ssl&&(yield new Promise((e=>setTimeout(e,1))));const Oe=parseInt(null!==(s=n.headers["content-length"])&&void 0!==s?s:"0")>0,ke=!!(null==n?void 0:n.readableLength)||Oe,we=!!(null==n?void 0:n.stream)&&Oe,Re=!!(null===(l=null===(a=n.headers)||void 0===a?void 0:a.accept)||void 0===l?void 0:l.includes("text/event-stream")),xe=!((e.config.ssl&&!1===we||!e.config.ssl&&!1===ke)&&("0"===n.headers["content-length"]||void 0===n.headers["content-length"]));if(be){const t=null!==(d=null==n?void 0:n.stream)&&void 0!==d?d:n;let o=Buffer.from([]);yield Promise.race([new Promise((t=>setTimeout(t,e.config.connectTimeout))),new Promise((e=>{xe?(t.on("data",(e=>{o=Buffer.concat([o,e])})),t.on("end",e),t.on("error",e)):e(void 0)}))]),xe&&!o.length&&(yield e.log([[{text:`${g.ERROR_4} body replacement error ${ae.slice(-17)}`,color:m.WARNING}]])),ye=e.config.replaceRequestBodyUrls?yield _(o,n.headers,{proxyHostnameAndPort:se,proxyHostname:re,key:le,mapping:null!==(p=e.config.mapping)&&void 0!==p?p:{},port:null!==(v=e.config.port)&&void 0!==v?v:A.port,ssl:!!e.config.ssl,direction:h.OUTBOUND}):o}const Ee=e.logsListeners.some((e=>e.wantsResponseMessage)),$e=e.mockConfig.autoRecord&&e.mode===f.PROXY,Se=z(e.config,{method:null!==(O=n.method)&&void 0!==O?O:"GET",url:null!==(k=n.url)&&void 0!==k?k:"",headers:Object.assign({},...Object.entries(n.headers).filter((([e])=>!e.startsWith(":"))).map((([e,t])=>({[e]:t})))),body:(e.mode===f.MOCK||Ee||$e)&&null!==(w=null==ye?void 0:ye.toString("base64"))&&void 0!==w?w:""});e.config.logAccessInTerminal&&!he.pathname.startsWith("/:/")&&(yield e.log([[{color:"GET"===n.method?22:"POST"===n.method?52:"PUT"===n.method?94:"DELETE"===n.method?244:"OPTIONS"===n.method?19:"PATCH"===n.method?162:"HEAD"===n.method?53:"TRACE"===n.method?6:"CONNECT"===n.method?2:0,text:(null!==(R=n.method)&&void 0!==R?R:"GET").toString(),length:null===(x=n.method)||void 0===x?void 0:x.length},{color:8,text:he.pathname.toString().padStart(62-(null!==($=null===(E=n.method)||void 0===E?void 0:E.length)&&void 0!==$?$:3)).substring(0,62-(null!==(C=null===(S=n.method)||void 0===S?void 0:S.length)&&void 0!==C?C:3)),length:62-(null!==(q=null===(I=n.method)||void 0===I?void 0:I.length)&&void 0!==q?q:3)}]]));const Ce=e.mode===f.MOCK&&!fe,Ie=Ce?null!==(N=e.mockConfig.mocks.get(Se))&&void 0!==N?N:null===(P=Array.from(e.mockConfig.mocks.entries()).filter((([t])=>{var n;const o=JSON.parse(Buffer.from(Se,"base64").toString("ascii")),r=JSON.parse(Buffer.from(t,"base64").toString("ascii"));return r.method===o.method&&r.url===o.url&&(!r.body||r.body===o.body)&&Object.entries(null!==(n=r.headers)&&void 0!==n?n:{}).every((([t,n])=>{var r,s,i,a;return!n||(null===(i=null===(s=null===(r=e.config)||void 0===r?void 0:r.unwantedHeaderNamesInMocks)||void 0===s?void 0:s.includes)||void 0===i?void 0:i.call(s,t))||(null===(a=o.headers)||void 0===a?void 0:a[t])===n}))})).sort((([e],[t])=>{var n,o;const r=JSON.parse(Buffer.from(t,"base64").toString("ascii")),s=JSON.parse(Buffer.from(e,"base64").toString("ascii")),i=r.body?1:0,a=s.body?1:0;return Object.keys(null!==(n=r.headers)&&void 0!==n?n:{}).length+i-Object.keys(null!==(o=s.headers)&&void 0!==o?o:{}).length-a}))[0])||void 0===P?void 0:P[1]:null;if(Ce&&!Ie&&e.mockConfig.strict)return void G(502,r,Buffer.from(B(new Error("No corresponding mock found in the server. \nTry switching back to the proxy mode"),e.mode,"mock",ie)));let Be=null;const qe=b(),Ne=Object.assign(Object.assign({},[...Object.entries(n.headers)].filter((([e])=>!D.includes(e.toLowerCase()))).reduce(((e,[t,n])=>(e[t]=(e[t]||"")+(Array.isArray(n)?n:[n]).map((e=>null==e?void 0:e.replace(ie.hostname,pe))).join(", "),e)),{})),{origin:ce.href,referer:he.toString(),"content-length":null!==(M=null!==(H=null==ye?void 0:ye.length)&&void 0!==H?H:n.headers["content-length"])&&void 0!==M?M:0,":authority":pe,":method":n.method,":path":ge,":scheme":ce.protocol.replace(":","")}),Te=Ce&&Ie?F({response:Ie}):fe?j[ce.protocol.replace(/:$/,"")](se,e,n,{target:he,proxyHostname:re,key:le}):yield((e,n,r)=>t(void 0,void 0,void 0,(function*(){var e,t;let s=null,i="https:"===(null===(e=null==r?void 0:r.target)||void 0===e?void 0:e.protocol)&&!n.config.dontUseHttp2Downstream;const a=i?n.mode!==f.PROXY&&(null===(t=null==n?void 0:n.mockConfig)||void 0===t?void 0:t.strict)?null:yield Promise.race([new Promise((e=>{const t=(0,o.connect)(r.target,{timeout:n.config.connectTimeout,sessionTimeout:n.config.socketTimeout,rejectUnauthorized:!1,protocol:r.target.protocol},((n,o)=>{i=i&&!!o.alpnProtocol,e(i?t:null)}));t.on("error",(e=>{s=i?Buffer.from(B(e,n.mode,"connection",r.url,r.target)):null}))})),new Promise((e=>setTimeout((()=>{i=!1,e(null)}),n.config.connectTimeout)))]):null;if(s)throw s;return i?a:null})))(0,e,{target:he,url:ie}).then((t=>t||T(ce,ie,he,ge,n,Ne,ye,be,e.mode))).catch((e=>(Be=e,null))),je=(null===(J=null===(W=null==Te?void 0:Te.alpnProtocol)||void 0===W?void 0:W.startsWith)||void 0===J?void 0:J.call(W,"h2"))?"HTTP/2":null!==(X=null==Te?void 0:Te.alpnProtocol)&&void 0!==X?X:"HTTP1.1";e.notifyLogsListeners({level:"info",protocol:je,method:n.method,upstreamPath:ae,downstreamPath:he.href,randomId:ve,uniqueHash:Se}),Be instanceof Buffer||(Be=null);const Pe=!Be&&(null==Te?void 0:Te.request(Ne,{endStream:e.config.ssl?!(null==we||we):!ke}));if("object"==typeof Pe&&(null===(Z=null==Pe?void 0:Pe.on)||void 0===Z||Z.call(Pe,"error",(t=>{const n=-505===t.errno;Be=Buffer.from(B(t,e.mode,"stream"+(n?" (error -505 usually means that the downstream service does not support this http version)":""),ie,he))}))),Be)return void G(502,r,Be);Be=null,we&&Pe&&!be?(n.stream.on("data",(e=>{Pe.write(e)})),n.stream.on("end",(()=>Pe.end()))):ke&&Pe&&!be?(n.on("data",(e=>{Pe.write(e)})),n.on("end",(()=>Pe.end()))):Pe&&be&&xe&&!Pe.writableEnded&&(Pe.write(ye),Pe.end());const{outboundResponseHeaders:Le}=yield new Promise((e=>{var t,n;return null!==(n=null===(t=null==Pe?void 0:Pe.on)||void 0===t?void 0:t.call(Pe,"response",(t=>{e({outboundResponseHeaders:t})})))&&void 0!==n?n:e({outboundResponseHeaders:{}})}));let Ae=null;try{Le.location&&(Ae=new i.URL(Le.location.startsWith("/")?`${ce.origin}${Le.location.replace(/^\/+/,"/")}`:Le.location.replace(/^file:\/+/,"file:///").replace(/^(http)(s?):\/+/,"$1$2://")))}catch(t){yield e.log([[{text:`${g.ERROR_4} location replacement error ${(null!==(Q=Le.location)&&void 0!==Q?Q:"").slice(-13)}`,color:m.WARNING}]])}const He=e.config.replaceResponseBodyUrls&&Ae?new i.URL(K(Ae.href,{direction:h.INBOUND,proxyHostnameAndPort:se,ssl:!!e.config.ssl,mapping:null!==(V=e.config.mapping)&&void 0!==V?V:{}}).replace(new RegExp(`^(${L.join("|")})/+`),"")):Ae,Ue=Ae?(null==He?void 0:He.origin)!==Ae.origin||e.config.dontTranslateLocationHeader?He:`${ie.origin}${He.href.substring(He.origin.length)}`:Ae,Me=null!=Be?Be:yield new Promise((e=>{var t,n;let o=Buffer.alloc(0);Pe?(null===(t=null==Pe?void 0:Pe.on)||void 0===t||t.call(Pe,"data",(t=>{o=Buffer.concat([o,"string"==typeof t?Buffer.from(t):t]),Re&&e(o)})),null===(n=null==Pe?void 0:Pe.on)||void 0===n||n.call(Pe,"end",(()=>{e(o)}))):e(o)})).then((t=>{var n,o;return e.config.replaceResponseBodyUrls&&t.length?L.some((e=>ce.protocol===e))?t:_(t,Le,{proxyHostnameAndPort:se,proxyHostname:re,key:le,direction:h.INBOUND,mapping:null!==(n=e.config.mapping)&&void 0!==n?n:{},port:null!==(o=e.config.port)&&void 0!==o?o:A.port,ssl:!!e.config.ssl}).catch((t=>(G(502,r,Buffer.from(B(t,e.mode,"stream",ie,he))),Buffer.from("")))):t})),De=Object.assign(Object.assign({},Object.entries(Object.assign(Object.assign(Object.assign(Object.assign({},Le),e.config.replaceResponseBodyUrls&&!Re?{"content-length":`${Me.byteLength}`}:{}),e.config.disableWebSecurity?{"content-security-policy":"report only","access-control-allow-headers":"*","access-control-allow-method":"*","access-control-allow-origin":"*"}:{}),Re?{"cache-control":"no-cache","x-accel-buffering":"no"}:{})).filter((([e])=>!e.startsWith(":")&&!D.includes(e.toLowerCase()))).reduce(((e,[t,n])=>{const o=pe.split("").map(((e,t)=>pe.substring(t).startsWith(".")&&pe.substring(t))).filter((e=>e)),r=[pe].concat(o).reduce(((e,t)=>(Array.isArray(e)?e:[e]).map((e=>"string"==typeof e?e.replace(`Domain=${t}`,`Domain=${ie.hostname}`):e))),n);return e[t]=(e[t]||[]).concat(r),e}),{})),Ue?{location:[Ue]}:{});try{Object.entries(De).forEach((([e,t])=>t&&r.setHeader(e,t)))}catch(e){}const We=null!==(ee=Le[":status"])&&void 0!==ee?ee:200;try{e.config.ssl?r.writeHead(We,De):r.writeHead(We,"HTTP/2"===je?"":null!==(ne=null===(te=Le[":statusmessage"])||void 0===te?void 0:te.toString())&&void 0!==ne?ne:"",De)}catch(e){}Re?(r.write(Me),null===(oe=null==Pe?void 0:Pe.on)||void 0===oe||oe.call(Pe,"data",(e=>r.write(e)))):Me?r.end(Me):r.end();const Fe=b(),Je=Ee||$e?Buffer.from(JSON.stringify({body:null==Me?void 0:Me.toString("base64"),headers:Le,status:We})).toString("base64"):"";e.notifyLogsListeners({randomId:ve,statusCode:We,protocol:je,duration:Math.floor(Number(Fe-qe)/1e6),uniqueHash:Se,response:Je}),!$e||e.config.logAccessInTerminal||fe||(e.mockConfig.mocks.set(Se,Je),u.stdout.moveCursor(0,-1,(()=>u.stdout.clearLine(-1,e.quickStatus))))}))};exports.serve=Z;const Q=(e,t)=>{"EACCES"===t.code&&setTimeout((()=>e.log([[{text:`${g.NO} permission denied for this port`,color:m.ERROR}]])),10),"EADDRINUSE"===t.code&&setTimeout((()=>e.log([[{text:`${g.ERROR_6} port is already used. NOT started`,color:m.ERROR}]])),10)};exports.errorListener=Q;const V=e=>ee({config:Object.assign(Object.assign({},A),e)},{server:null});exports.start=V;const ee=(e,n)=>t(void 0,void 0,void 0,(function*(){var s,i,l,d,c,u,p,h,v,b,O,w,R,x,S,B,q,N,T,j,P,L,A,U,M,D;if(0===Object.keys(null!=n?n:{}).length&&e.server)return n;if(null==n?void 0:n.pendingConfigSave)return(0,a.writeFile)(y,JSON.stringify(n.pendingConfigSave,null,2),(t=>{var n,o;t?null===(n=e.log)||void 0===n||n.call(e,[[{text:`${g.ERROR_4} config file NOT saved`,color:m.ERROR}]]):null===(o=e.log)||void 0===o||o.call(e,[[{text:`${g.COLORED} config file saved... will reload`,color:m.INFO}]])})),e;if(null===(null==n?void 0:n.configListeners)&&(yield Promise.all((null!==(s=e.configListeners)&&void 0!==s?s:[]).map((e=>new Promise((t=>e.stream.end(t))))))),null===(null==n?void 0:n.logsListeners)&&(yield Promise.all((null!==(i=e.configListeners)&&void 0!==i?i:[]).map((e=>new Promise((t=>e.stream.end(t))))))),null===(null==n?void 0:n.server)&&e.server){const t=yield Promise.race([new Promise((t=>{var n;return null===(n=e.server)||void 0===n?void 0:n.close(t)})).then((()=>!0)),new Promise((e=>setTimeout(e,5e3))).then((()=>!1))]);t||(yield null===(l=e.log)||void 0===l?void 0:l.call(e,[[{text:`${g.RESTART} error during restart (websockets ?)`,color:m.WARNING}]]))}(null!==(d=e.configListeners)&&void 0!==d?d:[]).concat(null!==(c=e.logsListeners)&&void 0!==c?c:[]).filter((e=>e.stream.errored||e.stream.closed)).forEach((e=>e.stream.destroy()));const W=null!==(u=null==n?void 0:n.config)&&void 0!==u?u:e.config,F=null!==(h=null!==(p=null==n?void 0:n.mode)&&void 0!==p?p:e.mode)&&void 0!==h?h:f.PROXY,J=null!==(w=null!==(b=null===(v=null==n?void 0:n.mockConfig)||void 0===v?void 0:v.autoRecord)&&void 0!==b?b:null===(O=e.mockConfig)||void 0===O?void 0:O.autoRecord)&&void 0!==w&&w,_=null!==(B=null!==(x=null===(R=null==n?void 0:n.mockConfig)||void 0===R?void 0:R.strict)&&void 0!==x?x:null===(S=e.mockConfig)||void 0===S?void 0:S.strict)&&void 0!==B&&B,K=null!==(j=null!==(N=null===(q=null==n?void 0:n.mockConfig)||void 0===q?void 0:q.mocks)&&void 0!==N?N:null===(T=e.mockConfig)||void 0===T?void 0:T.mocks)&&void 0!==j?j:new Map,z=(null===(null==n?void 0:n.configListeners)?[]:null!==(L=null!==(P=null==n?void 0:n.configListeners)&&void 0!==P?P:e.configListeners)&&void 0!==L?L:[]).filter((e=>!e.stream.errored&&!e.stream.closed)),G=(null===(null==n?void 0:n.logsListeners)?[]:null!==(U=null!==(A=null==n?void 0:n.logsListeners)&&void 0!==A?A:e.logsListeners)&&void 0!==U?U:[]).filter((e=>!e.stream.errored&&!e.stream.closed)),Y=e;return Object.assign(Y,{config:W,logsListeners:G,configListeners:z,mode:F,mockConfig:{mocks:K,strict:_,autoRecord:J},configFileWatcher:void 0===Y.configFileWatcher?(0,a.watchFile)(y,(()=>t(void 0,void 0,void 0,(function*(){return ee(Y,yield function(e){return t(this,void 0,void 0,(function*(){var t,n,o,r,s;const i=e.config,a=yield H(!1),l=[];if(!a)return{};if(isNaN(null!==(t=null==a?void 0:a.port)&&void 0!==t?t:NaN)||(null!==(n=null==a?void 0:a.port)&&void 0!==n?n:-1)>65535||(null!==(o=null==a?void 0:a.port)&&void 0!==o?o:-1)<0)return yield e.log([[{text:`${g.PORT} port number invalid. Not refreshing`,color:m.ERROR}]]),{};if((null===(r=null==a?void 0:a.mapping)||void 0===r?void 0:r[""])||l.push([{text:`${g.ERROR_3} default mapping "" not provided.`,color:m.WARNING}]),"object"!=typeof a.mapping)return e.log([[{text:`${g.ERROR_5} mapping should be an object. Aborting`,color:m.ERROR}]]),{};a.replaceRequestBodyUrls!==i.replaceRequestBodyUrls&&l.push([{text:`${g.REWRITE} request body url ${a.replaceRequestBodyUrls?"":"NO "}rewriting`,color:m.INFO}]),a.replaceResponseBodyUrls!==i.replaceResponseBodyUrls&&l.push([{text:`${g.REWRITE} response body url ${a.replaceResponseBodyUrls?"":"NO "}rewriting`,color:m.INFO}]),a.dontTranslateLocationHeader!==i.dontTranslateLocationHeader&&l.push([{text:`${g.REWRITE} response location header ${a.dontTranslateLocationHeader?"NO ":""}translation`,color:m.INFO}]),a.dontUseHttp2Downstream!==i.dontUseHttp2Downstream&&l.push([{text:`${g.OUTBOUND} http/2 ${a.dontUseHttp2Downstream?"de":""}activated downstream`,color:m.INFO}]),a.disableWebSecurity!==i.disableWebSecurity&&l.push([{text:`${g.SHIELD} web security ${a.disableWebSecurity?"de":""}activated`,color:m.INFO}]),a.websocket!==i.websocket&&l.push([{text:`${g.WEBSOCKET} websocket ${a.websocket?"":"de"}activated`,color:m.INFO}]),a.logAccessInTerminal!==i.logAccessInTerminal&&l.push([{text:`${g.LOGS} access terminal logging ${a.logAccessInTerminal?"on":"off"}`,color:m.INFO}]),a.simpleLogs!==i.simpleLogs&&l.push([{text:`${g.COLORED} simple logs ${a.simpleLogs?"on":"off"}`,color:m.INFO}]),Object.keys(a.mapping).join("\n")!==Object.keys(null!==(s=i.mapping)&&void 0!==s?s:{}).join("\n")&&l.push([{text:`${g.RULES} ${Object.keys(a.mapping).length.toString().padStart(5)} loaded mapping rules`,color:m.INFO}]),a.port!==i.port&&l.push([{text:`${g.PORT} port changed from ${i.port} to ${a.port}`,color:m.INFO}]),a.ssl&&!i.ssl&&l.push([{text:`${g.INBOUND} ssl configuration added`,color:m.INFO}]),!a.ssl&&i.ssl&&l.push([{text:`${g.INBOUND} ssl configuration removed`,color:m.INFO}]);const d=a.port!==i.port||JSON.stringify(a.ssl)!==JSON.stringify(i.ssl);return d&&l.push([{text:`${g.RESTART} restarting server`,color:m.INFO}]),setTimeout((()=>null==e?void 0:e.log(l.concat([C.apply(Object.assign(Object.assign({},e),{config:a}))]))),1),{config:a,server:d?null:void 0}}))}(Y))})))):Y.configFileWatcher,log:k.bind(Y,Y),notifyConfigListeners:E.bind(Y),notifyLogsListeners:$.bind(Y),buildQuickStatus:C.bind(Y),quickStatus:I.bind(Y),server:null!==(null==n?void 0:n.server)||(null!==(D=null===(M=null==n?void 0:n.config)||void 0===M?void 0:M.port)&&void 0!==D?D:0)<0?(null==n?void 0:n.server)?Y.server:null:((null==W?void 0:W.ssl)?o.createSecureServer.bind(null,Object.assign(Object.assign({},W.ssl),{allowHTTP1:!0})):r.createServer)(((e,t)=>Z(Y,e,t))).addListener("error",(e=>Q(Y,e))).on("upgrade",((e,t)=>ee(Y,X(Y,e,t)))).listen(null==W?void 0:W.port)}),Y}));exports.update=ee;const te=null!==(e=u.argv.map((e=>e.trim())).filter((e=>e&&!["ts-node","node","npx","npm","exec"].some((t=>e.includes(t)&&!e.match(/npm-cache/)&&!e.match(/_npx/)))))[0])&&void 0!==e?e:"",ne=te.toLowerCase().replace(/[-_]/g,"").includes("localtraffic")&&!te.match(/(.|-)?(test|spec)\.m?[jt]sx?$/),oe=u.argv.some((e=>"--crash-test"===e));if(oe){const e=Math.floor(40151+9e3*Math.random()),t=(t,n)=>(0,r.request)({hostname:"localhost",port:e,path:"/config/",method:"GET",headers:{Accept:"text/html"},timeout:500},(e=>n({response:e,state:t}))).on("error",(e=>n({error:e,state:t}))).end();ee({config:Object.assign(Object.assign({},A),{port:e}),configFileWatcher:null},{server:null}).then((e=>new Promise((n=>setTimeout(t.bind(null,e,n),1e3))))).then((({state:e,response:t})=>200!==t.statusCode?Promise.reject("Crash test has failed"):ee(e,{config:{port:-1},server:null}))).then((e=>new Promise((n=>setTimeout(t.bind(null,e,n),1e3))))).then((({error:e})=>"ECONNREFUSED"!==(null==e?void 0:e.code)?Promise.reject("Server should have stopped"):k({config:{simpleLogs:!0}},[[{text:`${g.COLORED} Crash test successful`,color:m.INFO}]]))).then((()=>(0,u.exit)(0))).catch((()=>(0,u.exit)(1)))}!oe&&ne&&H().then(V).then((e=>e.quickStatus()));
|
|
2
|
+
eval(require('zlib').gunzipSync(Buffer.from('H4sIAAAAAAAAE9W923LjyLYY+D6/4BcIW4dEtpIgqbp0NSSIo1Kpd6m7Sqqty67dh2K3ICIlogUCbADUpUk4YiIcEzMRDtsxPjN2jO3weJ7mE85EzNfsH7A/wbFWXpAAQUrq6jM+7r27BSbyhpUrV657mtOUGWmWBMPM3Lr1EoPRzM1GQdpowH/tn37y7rwgY8l8fjWNhlkQRxajGY1oTGYJy6ZJZETszormcytyPyXxOEgZIZalaic0JTP5ywgsRmZZ8jDzrNiO2H1mMULyoZcNR/AmtRjJc1U71GtnoyS+W1ndgzL4iGyL2X4csV5iMfvWC6eMOFbmimeaGUGUZl40ZPGVEfUyJ2J3RqTNmZEZszKSE0LsbMQiK6AhyT3Lit3Y9iaT8AGAMJ/3B4TwryBQOadRGXYJS7My4Pj8IneWb13FiQU/YiOIDEaOLn9mw8yeJHEWZw8TZo+89Ogu+pTEE5ZkD/bQC0OL0Zg0GpkdRD67P7qyYrLdaTSsqB8PXNaPB2QruLKiaRiuuazRMOXIputCl/GVIUa5ZpnW98nD+DIOUz63xO3g1GJ3VV2Lka1kO7ZDFl1no61kY4Nos+onA5zYwjdNRC8H6X40HbPEuwyZ+jJoxT+mnwzwe+AvySWa5VuiP59dBRGTM7LY/SROspSaP/3E0o+xPw2ZSWe41M5aJydUVLCnE9/LmCt/piy5LX75LGPJOIjYR28yCaJrrVrkqx/DkHnRfpQl8eRBFSZsEnpDdsrus7M0iK6rPYj3b2O/aOMNb6L4LmT+NfvMLtN4eMMyrYHnq9K306srlhQzSJiXscrbb5N4rGrcyXcnpQ9M2DBOfJa89yI/1Dr8ZRoMb04yL5umqowlSZx8CNKMRVrNMPYKSKSZl2TubRz4RmdrGEdpZsRuwn6ZBgmzzFGWTTZNQpNykUloWi5JTUKDomiahCahYVFwBRW84vevYXBpEuoXJRMvG5mEDouSYfIwyWKT0KlWK4mHLIXOJkVhnJoEqd6YXtMRvdpaK5GAPrP3j4+Pjt3u5suBa+KzSaH44PDbI/ebFwPXhCde9nn3+PDg8I9u9+vNgWuKX2Zujedza+zOckJoqXf74PDt0dnhO9f86//8b//z3/9Lw6TM/nR0fOqaf/23/0IWHJ2dqlr/RhYen33YP3HN//If/+7fwM+PR3vf489//q/g58np8cHe6U+q9H//+//89/8SXuyenR79dLy/d3T8Dsr/9f+Hfe1/Pj443XfNv/77/032/+Hoj9jyX/8HXuPkdBem9V/+49/9Myj4vP/25Gjv+32c6T+TjfaOPhwd78NE//3/g9N4f7D/AQf6d/9J1jk8cs2//ru/g0eE5k9d1/zrf/jnxe9NeP+/yOq87AUM83+Xy1665l//p/+1XPbKNf/6f/6n4vdraPd/YZ3cup7PreuVqyAeykCXT2ZujeZza1TXw6fjo7/84AKG3T/I5XDNcTy8MXPraj63rrCV2CS3LqfPrsXcqe0l17f22JtYFnN3mJ0lwdiCU+cqCDOW8NJGY61vZmkrin1mUlP+mdzjf8cmNdk9G5oDO43HzLIy6CiIhuHUZ6mVkUZjjdljPDLb0WTcGnrDEWuXin+KJvdtAv/0O0CD+a5ec13WY45p0gf31s7iD/EdS/a8lFlEkjSr3W/9NGhfU9MkxZhmGA+9MEu8q6tgaMJIt3Iky563SM/K4GBMJ2xIzu1xr/9zNkjve+ttQi/dh57Vob6dsDQObxmxrA6d2sM7n1iECnilYTBkVqsLs7VZ5Kefg2xkmfbPaRyZpFdTy1noc2KP4jHzgwT6NW2ccUtMWXREnIv1GVbNxhNeM1+f+XbKJnmpfitj40mceMlDaxhHV8F1C9sN7cSL/Hj89iFjKbFeEzuLT7IkiK4tc8TuTZLjQBf0RiICX0Dm7pit1jDx0lELAGW6rssIoUeuRdydmeDStuSxKLApQ7xyBV6NkiwYM/syuA6ijMznfEWhox5/dMS5K6sSfdmzXuZYOBjHWebiKoiaFpFjd9mLr1i/M9hg/e6g3WWvc4ARvXOZapq5wFy98zImGl2sz1jPNB3zn/RfvB6b+frsYn2GXMb7eJqkFskv7Innn8DxYm1Ss2MC1FnPdHibF2NnoeXHIJpm7Le1PWHDOPJXtMWmnbGZX+T02NWYuUhxwJkFDB/l8JN/FDv5lSW4UhrThKY0oCH1BDXw3Ujb/hohYPdZscn++i/+HvbY3CR62f+7UHY+7XS6l+f9/o/jwVdjsS3lW1iHY3a9fz+xriXVo+a1SagZRJfxNPKdZbXhVBJV4fBfWk9SS1E3nmar+8VzTFROpiFLl9Y8PBLVlnbFjzFRayNhd0mQsWW11Qkm6iuWaVkDfpgVtVspG06TIHtY1gBPX1EfjoJ0ac/aaa3XNywulpFlDbXTXLTzpllscDZvWSM42UXtML5eOilx5MulYcjsLassDn5ReRiHccL8ElrONwSqEmL/HAeRZRpzA35JccXVCJhOoZCa6uQrky8zOw3Gk5B9iK9TAvJKyDIjM+IrwydTO838eJrZiAPWxfrsTo0SP2WUWL6M9VFyY26sz7L8PLogWyxMmVEaNyKC5EVupp/fQiLVyPWSr4U9v+RbuZgFrEesEYyLf9J/+Wbr1db6DD4ijJN8DI/QT35ByNYqOCRPgUMiXyYlOKzPijmUvq52QqYJdHU/8i2rOKuY+KTqqfP6JdnokvwiV5jy1//jX5kkBwoMcKcPAQt9UDkYQtmAs1BfOo5v2d40SePEanXZC9rqUjzImMWHQSZnC9Zs4n6zJdePuZ0tVkizbGODPHOcDh+m7v1EvizNgQA3U1qeuM8GhE42XAWm1M36bFADqbSXIqQ2q0tscjiZRH1axLeEXPZgcdmjOAuuHmBlpcCX6jgQzOeBFNFn7JZFmRPRkN2y0LGGipf1FPcRiqcCe4Gn1DoM5YuQ44j+YV7Pc8YoXdGh67pjzsn3TJRHTYeXCdGqZ955SRRE16ZjBtFVbJKc5ICNQ1TFrLuobxEYGikRdTdJvAfrJbLYodUhHJNhfbLeRy8b2VdhHCfW5qvXX+FPzsNZhDgdAvIss9NJGGQWnES8KR+G2cORl+zFPtvNrA75Me6/aGQDAgKvRHYauFmvu/nG6dBQFW53N1/3uBRvXyXx2DoLouwNzpL/7nc3v6HBRjog9iVWI45q+/rVqxevZOthHA29zOo/2ll38/U8KLqjKxukOztvnlp389WrhjbPAXGeP7Wv66Ym2qudEbmH0/ElS6xUY6q7r0nBwXVfIwsn5Q57tpm3r0tMbtSLnL7ZMQdEEbOJl6TsIMosRruv4bCSL1bOmxXzJYQMQF2h1z8oV4+Lj/NX1UtUPXl0lGGR9foh9ag/cPoh9Qck33pcQ7QudsF+ZW8EV9aalc3n3QZD3dMZzMUCQsWHnk28B1D+fECsczp07KU3Tr9D8X8Dehn7D45p5mqTZT2gLEVXXdg58c7O1zR1u5tfN2LcCpld7re7+bUgbnrbTbK9/WZDL3kBGiJojtNIeku2dEYj3JdFw2jjJSFEm7iHM016b5yX1BekQW6ullffIcc2XKQ9seOt8iAe+THsv2hEg4LfMeUqVkAZcFCGHIQafleJqA0VqugLNEigg0/yAgPq9If7YnFO1NpLbgVFVY407710RCwzHXldk2xFQmNqZRvm5qs3+7vf7r5q7X/Tfdl6+fW73dY3r/Z2W3uvdt923u29efW2C00kAkS2H1yzNLPMSy9lr1+aZIvZXhjGd++98OpowiJ3rUOZ5Ezen55+anftrtHtdI2TuyAbjoLoGo7eLB7GYXqenEcwE8dYn1lSoIStf3a6J3Y/yaHSMI4ihlKXY0wn14nnMygWj46hGH0oRQVw4hgozPOCYUvVaHnDIZtkMGSMfcO/F9o+q1XhnggQ3Lu6kkjuYAA9mAY4q1WctzndK9XHPmYJSydxlDIny10GnJ/FaN+UpeZAUQbBogCArb4aJNSP9JJGyb7zoiw9Fh19ZGnqXTNgSd5a8SNt15Y2HpCcvlXIBSRF8q2CimxJhPvu5OjQTnHZgqsHiyFXy+6ME5ZZmSYE40AfvfSG4Mkbg0nEWuuSRmPdiuhaF85WUdiRhR1QJwNfymAE5o25Lpv5jYYq8VmaJfGDRfKtzL6Kk31vOOLMrKoyDOOU+fN5tZf53NLm1VOvOR6n1PTSYRCYnOEDYxeB07pUKamrxM1HBwUSkIqepz9DZsl5tUmBvwfVFJfLc9wSSqWooZcNaLqozdNOTJJf0FDQ3m5O5RAvtCGkSA/D6H37cZSdpew96PnfxXcR/8Se+b5rd03HfN/eNEDLojcR8uAx+2XK0gysIWdJmPaU7O6YhmHWz+ilNiOhuqhOKE3DHh/W4ZNYNjrH22cN/4oPb5obqOixx7HPXNe94qpfYe4DqX2PjwWC+DHK4T2csiaqy1lptVHct9PgV6atTMHJvCD5hVMzLO8aVSj5+kyYxm7YQ6qJWToAxtwqVZW4ZjkR23T56BeLk+bKiV5Zf+EIvcdv+0giQf91AfnXauH1T1E0uqepchzQEhXr97Lo5OvaTgqJtgctHaXIqOvjmxe1ffhBCibMz+zyROiDZF9cYaR3Ncjpad2h8LjyUFJkq2/btrDu9pjTH3BafTkNQv9PhRXPIgNhtuZiDdThQt5e+dixtE8RJGirzip4Kij3oStt/zQh7s7F+uw7q7v5pvv6BRUSGmX2WBwI+Xm0PdnZjQx8Y4y8yYRFzDfuRkHIjCx5gAM+iw00mxiekbBxnDGD3Q9HXnTNttuTnfNo2w9ujWHopalreiFLMgP/25KSn5HEIROvzJ3zqPGH+82X795sNaLLdLJ1OgpSI0iNKM4MT04E+DYjGzHDV1TLAEYgGDL7PNpu+8HtioF9mFuyMO72JGE728PYZzvreIh4w5v5/GI7wJ+RN2a5AYyEAk++3Q52LkDBDCdLFPcuti+T9o4FXYiaWJ6TC2Cst9vY93Ybxilm+TFOmAGybzL2uAfEZTzN8OsSTmUN5zzazgBH5dfgD5xzBiwlPiT4X3+HM0QG0JntduaLUtB5yZ9tUVe2mIy8tFw3WlpXTIn5xtnxh1KbeGkbbZGqjZL53GyE2VYUtzIvuWZZa5qEjetsy6z21lZf2savVxDcbuOL7fYoG4c7F/QXgeCA3AJqgS9AhuxgmpolOBr8FRDDCfNNI80eAC/8IJ2E3oNjXIbx8GbLuAv8bOQY3U7nb7aM+JYlV2F813pwDDgo+FqMmOdrXz4y0mE8YS6oU8312RooTiJ76E2yaVI6w3pNOeg4iFpyoM3O5N5sAubs2La93c5Gi73uAA+95NUH0O8seSeZ8iWvP7JsFPtLXnKCsmw+0wSxeMnrs4lAhE9eNlrWRYEuei2FBwrKsO64tmJVl6FJFQm4kfdZOBDFEftiFPitiyXY8ycAgn/ZMjg8hw6fRxUQIARCdpU5m52/2UqC6xF/yuIJ/p3EaYAim3eZxuE0Y1u/ttCXyOlumecRzK6QyvwgFUIe8znp3SlTfSWLGYUwqE6BWy8IcdE8IJNBaozjMYsyWxw303BnOwx2DlKjZOA1kmkE32n0ttthgFV2E1YIk6nBIujVFxXOI1nlIZ6qxp4RsewuTm7gzMvExLI4Do1s5GUG8BIgIKd6v2LA9jTUyP52OkyCSWaAS5VrAl/S/tm79XgpwAQUvwIGLlocts4j5SWHthyLGLPzyI+HU/z8a5bthwwe3z4c+FZTp3hNYuN62iMGK2e455GlGsoH0doehgGLsve8ZsvovuoQY8NoTu6bW+dRcGVYYlprLp8YMYRseB4VE2Z3BnBU+Nsy71Kw1CJ7n5pA0px2e33G8nbZBg8SKxgm6mik2auTWd0smTLs0SRqfDuO4gmLDNcoWDVQeq+GVz16KsiJjWC4RhP2AsDieaDnAnixmFZN8/Ttw6l3feiNmdWMvNsm+D3M5zPswJnl+W/tC7iLJ3eWa3AUrE49KAFFfS/zDNfAQht+8OJpFPwyRVXU1nmUJQ9QnTOgM+2doz13qWHb2EPXyA3XQAUDKnOtonNYYzEi1tw6j4oeDFfvDj7EkF6mxszIOe4uXTMQblrANTVJzx6O2PCG+RpmQ9tVZ3huNBoGn1zPLjgeOMF63M+Oe7g0pQuf0243idFonEdrvNF0ojdRLjHN3lWcDEHGOYiORdtPEvObhJxHao7CWyMYM7ED4cCxQFdwcHKk5DVu+mieNkm/O1AG3ubfNqnRbBLVjYernRqucc2yXf7jfTYOwUPSKuBMcSFsqdAiCCoLy1JkFEC3CrApmpACGVAw40PswSNouE9Us2o3xeSKsr04nI5hq6uF/WXKkocTFrJhFieW+QfEnpZpbIiZoi3owDc2DNPQOjeJpG6VvgmcheUiO4gilrw//fgByMF2OvEiebJeev41My6vW01jQ3zehtE0d5pyfA0qG0Zzuw2Nd4CayG/zBQv1hV8mu1HfVe5XWwT5Qmwq1dLYAVan0zF6hmZUK1dpYxU8H9ImCCrl1xtGc5wiqSwNXoKffMUpj5zURHCoXwgF2Y2CQrlfhEK5qDw36FG+L08QN87DF06Pd6Imp/eJU9MLShMTu5NPKTfQkwF6qOwyz/cP2Z3Q1lmlCVDZB0WKIfYxGoVp+bvFzzEKBdQ4j5ZgfIpeWF7yYHKBhWM2NZrA2734trvVpAI/dFInei+TTLKlfRWf9+MnuGB/yTmAKmVJtuv/7A2BlTn9+MFqelcZSy7ZdRDBnIBD3878EqMNexSpJ27MzIcC+NqaalYBLWM+N5ogwDeJ1s5Y0rD4FjUKcvRIefPzCJ3TpxMLf+ocDdd86OcwFCBAqmxiyrLTYMziaWbhyUP5JhVIhu1sLm6jlekBKC4zXNc1XvxeLBIKzV/AIzUvw2livZnck+bvxSo9r8uncUzlPtVBnJ9HGOmCh/A+wNs6v+gj4AfG+fqsajzBlczPLxYWHU0YX7roufi3kB5G8Z0V+NgNqCPradduGIpVapJBYWLBEmqgbEcMdwc6wbIFJMAqiFaBb/QkTjiCfz6PcpjcI+PbkXd76SWtyLs14LkVZGzMn8IguinNDAoqEwN816cBjCBUs5F2gRLV9nzfagIpvGVNYgiiU6kDes1bVlTbEpPPNaCKOgWZ4lyr2Ge4kGlmNbOkSWR/ckfeBZEf3wlDLW5GYiyWWdURFanQ+KlpkrAo+xCMA0AN5QuxdBeGULNJRIDVOaghDe4OhxJ2fGX0m2KPUqOJBLY5wAG5DtgqjdhoGMtGwv6IPRwFoX8Y+ywVBgvBNj+31U7pUxcx+bF+BmUHdG1Bcvl/bWUBobWV5bAuCR6lxQYan7LM5jVGXAiS0o88RqdJSA1Q4bAkpQaqcCpij5fFl/qBDrO7YiDQYNvZeST6Oo9kP+cR+iAYa9jffM4fJNB6xjTicVe+4RjYPXok1GDzIzy/YvcLcDAfUe5RGano5jzqGc3ty2mWxRGeiy3ZrWviGSt/Gr2eYZoED2OT1yxAy+tqi4FHr6h2mbay+PoaVaux74VaMS6Va/4B5t0Sam1TqGP4nEyDn/+Sz8ki4zKLWpMkGCOT0/jDfffbl+/ebW23eYOd5nnkGM1mwSICVn0BUOAACIY3rlmohpwSnXn2hDe/frm3Yr6Ccq/P1rpPnK+xeg3Po8ss9qzKgacvLITVPHllm+YSmGg7VEKhDJmVi/iq09WAYgBM1HHOEXtDAmdDrGp5u5T57PNoKZMt+OuCtS646kIwpEomokaFVS5xyefRan5Y6MWfzBCjDpnLKwB5TVThAuwiSyvBKuQY5HCl4uBxJvqpvPbz2Gw5JyX6YT35y3haY74svCl/fmJDTaGANavi/rIvle2V6Awq4RaLxBx0ifrxTiTStDCuEjvQ8eiRTxHFllVRY/WayKcXqizYr06TAAnAR9u2YfNURDkxhj6eLvDoR06dDkhT/3CJGDelppDQIIzaCIK8XtfoGdylGLQSj1bfhOrpVJgHn9LiBbTwveTmadVfQnVlanlKi1d8AG6rds4js5CvOeQEi+j5/v4tckLcJcAy3x193IujDMpiz2e+SbnBACC+fd7mRHPngv5cmEpnwPPFENIOofqxq7EhmRbyxp2e9PD9PLiyzBgdV8w1GaEez+e6L0tcioVc65siWQFEyWAcJA+u4cEvXMdpDopQRPCtEizMfL7G3WuDlDt6xtwpRXeIkUUCU7CccdeL/qxwQeJOLkYQ3Xph4Bs8Xoez2xB/w4Jb5l9Q7jmi/NXzwUD4R86wgZNQ+AQnpfyTnIAW3+CEuRtD3HMPxMCP3sRKhBOq5hVINW14lBN3p/+DJcM4aEQouJ8TB2Q86rspOIChC1GjkRZeRHToWmv+fI5MRojx9+hgEvZCh9X7NEFctYLYsNEYrrlLatJJzbAAvPlc+Ch54JZX6yYEL/GBjkSUQdALylPicKMyopY7DsNQ9MFdWxutuWtrdfUv3WgrYhajl70ZrsAtLSo5M20R1rpybUaUr5lYjTx36pqqylofQ9kS5wgBDosfnOeEajK4peI8VdiQQEK/p6Mh9/0yljl/sS/z/HpFciNEGmCIDgyM0SsQG+I08gFHsIk2s9Eyt7DCVbEeDmS5g5g+G6haP4uHJ82C71e+WOjsgh43fGKj3qgOyfL68abaeLeaa17J5c95bCaALS1u28GZDJeM5s/nk/l8Op8/zOeXPVbj+IX1BiVfX3Tsol2ie4eXE0H8LNy7PgFJB+cuDFClPh3SKfiPWWXXtDoPNRnrOxvFaQbuTg6z5SMFRsIJKEaOMnRK7fE/Ds8A4WCAs1IZ916+fOG86VD52yle0YQBop9F3jQbxUnwK8M9ypksJ5RqZiHROmJbeGkaXEdW+dcspwsFtm2LMhZlScBSyytOH4zzQP9njY0xHQhvN7PEi9IrlrRYNIx9OKWR6pVC5mU0idVnQJjdHWvWZwMny3kwGEJOg1pOchGmhjo6DuCxO5nPQVfxXj/iFHhID+o6NaFrgXL399x6oFsdCpiBQgixMhoQiJlPykVbnh1HlvT1Q4/pSSmG5dBidAoBo1wkxjRBhAa46cG/kA4bDcsTjtA+oR7YKi0on8+tEDsHbpD3LeuhZzp/CTwtd5uWLdFtEQJYJoSrTScy0MILJ5H0VXJMiDAAr2CKkxf7CRhPfBp56fE0AlxCESZ1ZjmNI6ecuYf3W/jfYzR9NU7DegTpxrbATkJnpsO5N9MZa6Y9KouF/bx4K/wWckKcsS1mlVMW+Y7mNi69SkdBmlOxEEvfI4CXvc1hwXbdGXhWOMKv/3tLen1uvuqIGGIIygZvT9CzCiGCa14NoYBl9xMv8lvhtSwA1hesPkKShuIWhNqYFVejYRxlXhCxpHUVTgPu7jMNy4OAetfkHjfaC9T1YrGnl4Ju1uCaWNPwksBrCVWga04A1MYoYVcl9QDquzvE3NlF/n677aEjjnTyedqQy/rtEnSnu38odyu8fXRDmfhWOGtgCK4ydYztFBXeKHyjOhZ1HOhAWxpNqXvNne14giITam1ds9U1dzqGBRUSst3mL6uVuh1zp9tRb8+jyvtXHXPnVWd5a2y+9P0mvN/s1PXPP4/5rimfzGJMHHRprx1z5yC6CqIgezAsNDlNE++a+UQfps273TGS+C7F32B31Dyt2pEHf9dnv8AGkLz1rEa35ax1c9wGZZ9SQnkbR6VNE6ydygRBfSBfffPT0cmpSc1PZ6e6ABOJQ40QFLMYylhMl7GKaOFqbLcWxp4UQRdLArwXBbVKwLE5y01NeBOUosq2ZovSksjYkxscElJQGsZTOKbizLgEqcmrl5iAdaHfWxczGQNsPtKLSU10vzYdk/N0elAyBEAL9+xSjLMEQyB9WpYFLEOEVUDbZvuaNs/PzaaeCec8HWCeA8MkOQSSwIkLgvTpw4Q5JqSNC4aoiGlD2pctA+KFU5a50+yq9cbMVaKz763S2R0JhIlpslVdYchnILHy2yBkn2F1WLIkl0EclT8smc8T/kkxNTnVEKfrbEEaiSz9nK/oZDM9iIB2O3jUR8zK6GzCImCIODN94t0yB1gbYHh+G3T65h/3YZu83999V7tPhAQLsPEVlDw3UueuBgBPwsazebCf/tKXL30ts1F1niYhve+XguPZH+mo8/XrN998QwWuqxMWjy9+lKzP3uXQB2iY46TtB2nWLn7b4yCyh6COSlgIisWHkKUjxpSVAp1Gh8LxWbiTpsnwSf3+nJo7hSqopj1kqGpdxck14+3xsb4pHPZweKVp2BJWFqlF5b8y7xKNsHhSCTdjP/DC+LrKLGCDlngnawr1dn1dsTj1Lzm64LvRq/KrLMgghOLk5INxwx4mXpAY16A941rWIAKF8XWC3MLo1U59UAnvCY4K4cT82QsywzOu2J3BlXWpEUMoxi06EcMTpOrMIFskxOrC84gZjKcilP7L6tha8leCu1hR5a8uHNRfdjqT+y2D+/rKn+ZOxfV4iY+xdMwTXJvu2lS1L2gzILIhP5fBbZArVwxziDo+A/2iT4YjNvZOptcQVwz1HAPcGKmR4gsHnQlgnxlSp0jRPwuSRAYsxfdKVSIFvEe49TNCZ2kaOrMhA3HVpDcMA93zBWkO0lrlzvrMnEbga8z894g/4BCSHkQfUUmJAkNzlnFiADpIk5rANaamMzOh2HRMTkbMPG86wF5ztvMgOsXklF4oOzHjiB1dmU5fdHcZx8DjmTmdsWg6dvrmXZCNWkJzYw7yAXQYYdaEIh1opqYTRBkDbTHUElOoqSUn1ywGrKml5tJ0ZJFYkbwJiWlETDw9jwz1DxK4nIKSHpMz+o7RH1D0QsPYAC/8pC3llRemYEZDn7rCN8UDO7z03VgT2DmfCzzVHZbA/7yLVblVXOjDwaUcurKByGpmcsdoAnvWLMzliE7NXTw1wC+lStub/Gu4Sb3qs8Np6TWDvLFgQFcOa2KikHK0eqiUGhHpT6hZQJAAsZM03AMoXcFkmO7fkabhRyA6wr/3Mo6zNEu8iY2ly908FGluEgoWV/AXEl3ZKMWQkgNRIUwWQ0sq6Rr8KJjcBHaSerac9Pfs4ZMXJNZm5+WbwlF3WHxHqSVPVVD6StUmiu9K/svqxVVwy35gXpLqr4uH+I7YKcu+nYYh1IICAIT6DZaoVwj2Mo3Q5ojoMplehsHwe/bgyI+2VRHFjAOBF/LcJY5hdrqwCdCIEGQPiFJRnL1lV3HCIHDojmLBLhhbneITKMctXAptAjbOSA2bBLcctFTAbuzb6cjbfPVaQNAiBXhu2EMJxkXr0/gTG9f0Wl6n8gIVc+KttYKiGbsP0kyxhuAHo2H41rnkOFKWWTNw7y/Xp4DPjjGDmVM+BYAJqhUL3yXLBOfZckseFl/w7dabzrzfaX0zIG86621qNF++fNEk0rFFofoo8IWTD3rHkbJHL5+swC3YuftYYKmzkMrTrQAAyKaBF36Xovv0gmef4iLzEiy0VkS9QBSSCC/KvCHjk7CH8XjsRX4K5r49/mwBqoGe1mgC1QTCBnwWIu7sLgDXjr0sCVsnTWoYY28Iv3nL1kkTAA0pRx2kuBITywFGInpHUWMV9/O8sB89uH9V9I9glEtxPCvjTzSI1keL1AG3HN/yBV61/COf61v7j8pHtPoJ+fMNy+WjYukBVLCKv18o2nMGQ84YxlJkRXwkeh2MJ9OM+SdQ09L6LbvyN21FCJrIOt5/hk61Cakz+i33h9JYZ06txSytJnc1agrixKvXwBs9nUy6hDEoty65O5XelH1dwQXKJI9UUP5R5YoqAsE1ud9Ud3PL3FoBsWIlWmMWTZvgioRJBPw9cMW0VNdaaI93y54FP1V/BQChUqXyAryKV8sAtqpGGWJFzSrIXr7d/0KQqb5xJJ1OS7fkknReUWWCPUEEoBXOH0I1VWgzwWxIpRVGz7tpT5NwiWaqSOK8KmKNK1uaM3PCs/5NYpRFnq9lQR0SOily9l7TGZW0qHU6I01luqgzSuXL9Lk6o0cE0UwzSRPKxeOM+zpw9wKwCmaLnhRSziWDBeuj5jzCqJZqipvUng/UPqquqdRjv9v/sH+6X1LRCUV14GrKOqViBu8O0xQLLO1ihqkl2fKfv9Y0jo5EEuLPaOpi7s7PVkaZmp+GBaTQv32z2e2AGZMj4H9v+reJdxPzlvBU3wZiVHSNkOQRTeC66lMZqUwT3CTuqPgVkWlCmKx2PnKPisKYoqm9gNpdJ/F0IjV04gfa4kLvEqB1wrOQfEQ/yPNoO4gmUxnsnnh+EOseuS0MtzUNYGbBSgRNMRTXxM/iSygK4FuGMWT9yZhrxldX4mNLWZVMQwTwmvKjcFpVJ+B4moVBxBTpBvGnPNxO4w+ARlsGB992G/v50g9SocaPfg64mHzZ1xRjcVfnF/A1oMrSvkXpBWGthdt/afGFf/dKj+oQeDT+fZ4P4BveCI/zb17xEXnaHn86Hj/I1DbK6fr5g0wn4ErU4q6Dwhd//9WWcYbl3CvnC7oHJ9aaAV5vGe/Emy8fgsGqlwZ49a67ZbzD8sXuazTQSXy3aG8PW+G1UgmPvXuZUWYT9MDV6kBDOLoa+Jhi4kY+Qe421VIo1OKVY9BXh9q2XuiqheWSTmLRZXxf32mVWImkZE2J9KI98wsKVUJ/bVQsF3i/MAzm/ERfseGNyI60sAFqIPz7gPM3wkpzKquFVYmwfxm8Foba2S0y0T8fXjs8j8tCTZ1sjgLfZ5GpOz4ou3+7ztRiXHmShFaidkoGpvOoOIlC5l8+lKvLz8ZKfA6uiazpSmPUIgJ8U4cAz7RKdWusUsZV2nq1+Jli3jugEFKpwbLYaG+3R90nkJ8WKgqKCCg/SMeBZqXTj+89rLrzCPWp2L/qnH6qL5YTLATH5s6xzHm23R5t6sxNweq2fpvVawWyyqFFVBIcfeXBJWv9hUOvMumVYHoVx5kA3lMOlSIyYNnq7uCKPvewUqxEXdAVCKIy4omYO+AXYHAHhNpTa9lfxc6KnLvj8CgBxeinJAbPtIPoLSYfNlyjfx6Z7OE7EE/effPy8vOdC4973+6fdg7PPv/57bf8583l5mGH/eVtCD//OOpcfr6Dp/3R2ekZPL1/mR7sin9MapifX2RD8zwabJVjUdDc9w5yzVh64ElF5Hs0gJkDoq+FtgEKD5pCmBOr4O4YFo4hJDjjUmg0siwJLuFenH6zFF3XHPTERYh6Bpzl7Yo6qmUO6lFSjsHRwo3FZ3PTGvqbrtTlSt/rssdGxVIrq4TK4aXOrx3CFsCv/SqA+yaUtCvynFfu4KjJsl24nutifSQrRCXnX6UNMfGqyFrHksqFWn7Pd8y2bNg2c7NiZTyrGBlB747nQQsk3lpLo1EYGlF0xvgYByO/ltr0KhxOk8i0RRgaVoqmWd1T9exf6AkZAkcEdD4phZLqoGfwW9QMx5D5OTCesKm6Bu4X56dvOjTWNfOmsKxqKAqsN1azsCmgNEs1O+UXpz8Cpwju0+8a/UGRvkqWacPiFkaGEjewbSNzBsGc0ml3IZ4bKth6UDfVt31tbRVsjfYsUpPYiuuJZCIEOSEFEhXI6cq0Avx2RZEL5uzs4J1mZV2Z+KkyfWqUZ7hVTTmzNBCWh3JSo4lp4zebqids93iyGY6LS2IGS5MSjtekyMPEAVatIGMTZdqa86jZGafViWHo/XnUPGzvlvJALN9cQhhukkX9dBNP1SYFWqsvWHCVeIjFy/TfvEKTm53gcXmSOvE+5jKrWzLYiIEA41iUQWIEkQmBq5r5W7Jl5No4ydBwjeecBxN1HkyXnQfDlefBsDf8x3AeTGWDaeU8mPQm5fNgpf5b1/1jcgZduS8hLvBqKVLpyo/nINbvlBvuKgjZAUpyK1AU3mMbVRttLoA9UGKW3oynYRZMQnwrn8s1pE98BYX1KR3jiSu+71tVYMk8M0Vn8JTCB/rTIbMgKRj46VLsBSCGTmd4HQPm4E5YOg0zgKTu1SuuohQALiaAht/dFOkldrhVeluzEznrB52JoeSNIKVO4QVRZlpCqLozQjaGu6zPIz5n/ESYGz7YV6GXQQgq/IJS7aTBOWJDcarA+/5A9SQOvp3q0VuMxbGslKtGRncrkCNGWo+jdlnx9hzkRs3+coT0+OkOmX1A/W+4kI1aVOJ06ez4A7oTvQ3jS6tfZkcGVPNNXLAGUXkyY/fyExCZoQtM/7Zs00EmOH5bqWxfgApmmLDb+EabofoCDstVoNQUjE8D5NPyBBmu0YL8mnqusmqioif31HnsK8qMac1HIFn4TV/ReeQjVs5L53afMqtndV7Dkq8ag/FBjGesw+r8a8+bWsHsawnRII0K/uqI9GhLe5R2q//G0+DpsDH9fqum9yqH9QVzA3bQcJ6QSHilBv7/H3A9gqg1UuhvQ1QYpeQFLDWB/JRft5qlVE1NYqNmywI1Mk/eWqQx4nFSLIiuQVnKNMFn8Z2Q+KRCVc8hvF92ZuTVhI7QVY+VWuAGJryppcyAybjABUy6UAuFkv62qljS34qztNSzEF2WdV16vdi39lrmneTe+6F/rABRFUYXYbdazySSyhVsI/au4Pdbui/UXwudi+ZcbYjL85TutDZKMaZ1yUd7Zp96o7pOtTHfe+ke7g2/6J1LBen0ki+Y1QH/PILe7sXy1FdaMvPKKNri1w+zuorKVVuCN6BgSbMKacLWlnxsDf6LRGHApqPDw/WvwaS8CbjCFJnT2uv7tHv6SuljDatmriAkYn68MtALQbDchCegIzxZ4ZevU93+x89fsuuriLgM2PWLXkcSloBbpwtfBO+F+WoALyGXDvFSowrIH0VajbisBHqZMgqoL9LD4jyoT2DHMyqQraLLpVWl9m5L9aoTkJRlu5KGWAtElEqq8PTWikZqaRoLwoCxFTUdlRKUwljxXTWVdeYLtZxJSrmo6w9MUXdpV+UcZU/qcZqAE/PSkxwbivyWdcz8Ci6mwlkscjAQJGNfppznaFKe77OsZF16bnKH9ISFXsb8U+4b/ryDM1l+aj6p82ccm8vsb1z7NhHVdkqHVemCA16lZvK/YQhtWy4bY+Eo0nLvlqFSu1X085+WgaHtOEktlh0WZWJMDEjiiWR1GiFhBdG/uHK4xO5wmlO5jxqJbuUyatD3zLLYMVQAH4HsnYt9PWPas/NzyKs6ny+v0ud14Is01CsNaDil5suOrectTImJohUk0slu8ZFLzpXftjj6ifDFq1M5Xp4+dX2BltVZtkL6oLhEWkEpzqOWktYsVEF7F+gzhOBoB5XquCQh8UrFifQkasw9UprifACdKmjVqj4wJuZlVRYaIU6WAl6UHqbQYi4E2fyuDtgkJ8shthhltjTKetHxhXB78z9MeLU0Y89ERYnP4GiQhLXl3G49w2hmx+hX4oxpJXyYloKn4UpN3VZenl5Of0tA8VIUfAbUqx4//6Aw/4cFIDdvFq9UmPhvhe1yL0Rz63dRZbn6vQrLu1yhwiz1gHZJjd7AyClP+57KuBkUEaqhM7qD/W++OW8FtFATaDom6AHNvO56vZXX6nEf0RVay8XrVHe1NIWYNdGLfEOaLuHSOm8yMbyEGRCxATfbQUqe8TSbemH4ABe7htM0uMVbVuGuU/wPipl4E+xIeC0bcWRcxnCNYeAzvL41jcdsFN8ZIy/xodc0TjIjnmayI3nNa5YE19cM8B5SUIjEXjBTHvOGjglBpEYS6Yigl1ECPqPvGdymmhp3cBsfXNw39CLDj/EKVZ6RC64GvMJXkOPB0H1cMQNsyq/5u0rQZcc3vMmEGmhijq+ucGCvAkNbuy9wVdeQzEHc6yrgvfvpwIijEIKfMYgTbzP0JhO7kkVM+Mo9KYNVR89gBQ8q8AtscaUUVoI/X8w0xQNYaepaHepL6yKxzLZJkyInpG3biQ3SG/zScij1/jCwv1pvQ8BNUfrjeXuDFwlmqi24KZ8BNT07PoAwzDiC2F5Sn/4PrcaP5f5LptGSXHg2r9SrGk2JU0rVxNwdq0NDNOKCDZlYKbUsESgXXFlaV+5ah65l87m5f3Dy7uAYEkbC4viM6MPihN2M3/MMU3Yjnn+TiaScZEsN6AdJabylHWQ91dqRHwRJoCLOoTB3p/RRmfioEM4CYpWXtVhEygi1LI4dGXA5MY0GRPwjTL2ZQpzIzUp5nVl/c9BoMPAcCNJ3QYKy/gNmzRTm7BX1AdSYCnKr+Ex1OfU3L6npyw4RB8H8mW9PdtQwhnC5hitL8MpmXqlAwPM25PVq/OG+09n8dsskeHszpNzRshGGQZqJ0KYdLTFgUSzyA/JgkL3u1ranQsm0rVBEQrZN0jNt23RM28zNHbjqmPvawB3HkDAQNzpceVkFjExOw+Aa49VTWZ9Zi0DvIdxeOPjnNSmcYLqvSf60eZuQ+k17rW1c/fKUvI13YMOTuSMe1KcVmWLOI4S5vAm1em2zQueciP8TyIv5WCZPscWwWp8N5C5JppGl358+K2f8bDS0ZopHtFINAnZ6e22S3owHskEan6EHHsW6J6fpmMHYu2bt9PZ6434cmrlTqZ/TDqE8Hao2LvxuNCx9DlBkqZeE6u9EelWRPE+fPxSUvwWLrOIthoHyPKH/gDlGOSVelR0RKUafhxUP3CLdYftH3rT/4xYdfEV6Wz2r/yM+Ucv+iqy3bUhSoRzFlp5VnCJoTllJL3EQ8A5dTIPYNyEclP9/QMfu4hlkTQi9BndDUEyZ6P2l584bU/FqmoSmtrnMyyDCIHBnvKUyASrfNkGL9PP6LAnT3q+lvHwQG2wKatbiCaWG8zmPNp2EXoD5oYSbnFPE467yoIO43FlO0f/2vTi+dyP/E2ZzLhc7hY/2AqhLFase2xzjgTngGbZkP95iPzfsQW8NecRNk3ICD7zuyD44fHt0dviOQn6YtTXdzZCnoC58zdU7zAhT8dLmI5/Jkc+wUk6c63II8jAneU4/uHoK9l1C37sfChqMqcEuCKFnrgJ+XfLpDzol5zt/DXcsZ1/gWSPt1qx/wVOhXAwcPka7fYHEj3/om86bDlV4o/J/Atogt1OPUfDKj6PsLGXvs2yyWVypLt+cQrZr0O18ENmyeKozeF2TsAyT6AcQpfoB8givdam6CdBZ61C49foyZJD4hQ2nCaRBWutScT+g0L84L9gLypvoJcszrTn9QU4/uhZkDdIzmIOOhg1qMpgzd62jCFMt91OwdJeKzQGWLmo0rGOkMbQm6WlXJT3l2V2MMxQRJgm7DeJpymPWiryn2AiynmrHTzWjNGalgzU29w+P9g9PAS0izjkK1hHzhnNqh9liE3exB6qp+wSFjHsxz/GqO70uJnxNBAUGIlmXL+/YmomMtxzMeR1cNhVc0oco8+4hqWGcwB6mRnAdxTD6Y2BJYHYSCOi+iztW881FoDQarIcriOeQXMKK8u6M4gpuEkw8LtaT9VamsUVvyMOjU4O7AfqL83VK7feOPhwd778rt19oy/P913wqIQ485Bo7zZ6WnF9eIdHjieF1lr/iU83UAVBRVi4kpBVOGW5NrkDMQZ/JAwvICk3q6mVOpt3cepaEkAZ5LSnpp1HsNMl8rjOYcLibEtmNSExSpMhP3aSicrdE6nK2kaDefTezso0uQFGntuvryB2p22Jk/hJN8gEgBDa4USaaaLB+vo7ZwzD1r0lIIRBZVkBDQSaCJdP13LDMe9Oh6/UuZOZiJpGZ6cLIV+t8rLwNoLhwGJ3qjUppn2sara+vz9KNbn7hxHTCGya1NddnYCSe5EWDRLnMW3GvP6QzbZWdKS0tpzPJB05/SCcDxZRrcuAj+U4YodWjEhicfYGoGfYHqYTFBQDybgtQ0LsfBXA/u7CyJoDRNB0UXKM4GXth8CsjFtM0DOfn8Mltk9B38n6EdnvoQ94Mn4XBbWJHLGtHk3HbpN+6fZOzKqY4puCmbGreMDZpeSGklqfmdHKdeHg/0eLdEOptC25WG04TJg0WkEsfGaWW1vOAflfctXSxvebHQ/SFR+EHlFfZODRCL7p2TRbxeFTm+fAXI4K5lMcqQpxRSp9mrM+y3JjDJSj5dps3W0x3ojJG8twiwzRtF0kklyY8addmOEGbvshugs9Py2xSmcLP+gwup3CdSX0/bQkSLjjWRxtvj7pPBpaKm07aOxf0J1e7lonlaN0p658wju0fXP8E+hU48Qs1iHbM63ICkzJISQDhOXP0M7/oaJbnmS5m/37iNb/n6ElC9mNJkuRs9Ts2/tICNjU8FYkCP3KtedfMiVZfhHk9XdzWgVncuFR0iJbTyn1LIDJKqP93JqUT+r0rjtEqZgPoguES3I5F8qV3qqQWxxe4A9ZbxGuFiozqmOiwghvSK5Xx+o25GmujZVgbrcDa6GlY+4geSKJPTfSZJmjqyBT1IofL9ED7/1EpiipoxEg50g7b6EjhMsqMAMyM0RAWnu8rLR9bDVQqOb1KgXnzecRvNMgo+z32RU7or+JarCdehSW0V3r+u4XbOfpKR6OYgsFj13Is3sdR2EMoWkt4PBoi8/Nu7YrsLAnGGFukXVhFY9cEJxdABjBU3LfUr55nX0+jX4OJY/oMosOYLA4i/OmYl4ksukziLAzeMUhVBUnxHTPwWZQF2YPsmdcU9GWWCemL5Lg1QCoQoItJNevpBTIusmfw/oebQNLpBLhB5huXD2g0Q57qQvLcicsFISaxsubCLDGZ2EoKaT9qNDIrIpRZMZGMJ6HVI5np4pkCMRNixU6XfU0Tt69tX1oOCVNJMqovIMprYIMxlHet3w+onUEacqECcLB4DOkSvn5VZq6sZ2tZo2El8/lau//j+X2n0zq///bbQdvOwM2TlRQEvT+WCuis0MXFtnqu1x9W1IKiGDV3MSrspAgQS8E015n2nry9zL1L097fvNhtSPui2/+xMdhoABa4XDprSLHMbV/TC73l+izWY5BL3cC70hRz3ieWgz6w6HZ9hnu5rAlGfaUuW21w2ybJL7j0oqEKrieNqysaK8KRPU446iOX9QtOQclTJRy3DPjDEgnJSMlU9xh9iEr0IQL6UKUOUCh+SuoQKeqwV0sbIkEbot9KG6Jn0AZ10aZakSoLElsg0zNlzWViSLYFZIELuHD/TZUilBhvIk1U2nWMSoR2fxUk6o9w5mg7KavfPxHfKmqbJCB6VHQ6SVWX02d0iTZGmwnYEDV06Cc0HRQoEZSULJoapW8iTi3cwCud/e0xShbtH61z65yQr9bbpKe6sqAvEWqMV1fKF6Dt0S5i5LiQ/c2m63YJcfoDVHiGbkeu4fuCSqa6OolhUL4JGtOk0VhL1Gz6La/1627rbzutbyzyPzp/89P5hv1P/9BrtNvuAObYaKwFgoD3mJO5rqvMDL1CMwP4csyu9+8nVlpXePGjtT77IGAxB4YUFPak7OsA+iTr3N8g7WuqNqLOQ5mWuWEVPGPQV1mpM9LqDhb4RJNsmMTMiT6Gff4V6DsWPlv7am1O6tNN02n3v9ro/bg+yy0y758Pzs8HXFekOWug+qRNuRqlZ5KNUgdm+yuTUBNytdMLngkiLqV/iPKyOsrq/0gGG+ccHgQ0deaGsbERlj6I09V2aR5Wb63/Y3tAxBukuAKjnjSwpNUru+SrmcK2Z5KqIuFpO/Il/nQuFjY8+KOiOeAj373uH8Xm/8FV5C55UERYeuWV9uwS8T5bKd5vyZu0uPeb9KNrQXo6uAQRs//g9aqeUG0NveGIqeSNoPeKbwKoCFES8CcCboXdT4KEgQ4ruGpxtyvmt9IgGjJeNo0WSktKs9BLM9UQVWHe9dhTOjGYFRwOQz5oUahPNWFXLMGUvQnLkoeWB3dnwJ1wwXXEfJE/D+YoMqtmwZjr5FI2bA1HramnP7fG8SV6DmlFk9DLwLlPFGKSq5aP151qBeJ28qIgDbJywTTFia3SBUIVWBIAr23b5evLmb3cAEZ6q946/cFAZfzReEmN0aiaUmoSYWfzOU8SYGR9NsAb32S1kjW0aGyD594in2GxfjYokm33swHKbrOc0BV3zkWESozWbegC7RfMVlleXICMYfv7/OYs9wex6/6iXWifcWMRQA7O4YpFvcS7y1ecwplOJGgdqJdQqI60m5fhXh/3L2LAv3VL5J3yJOoihbqoM3Ur7gtljjBymYKa6YitkD2UeUJtFZfzhKofdNFbcIYo7PMaOXTsr5BA0smyacznYJcudZ2rK8BBJl4+rJRwxRHtcC4e+AXTdN6gLIMc+HyeIff+8uULV5Y1GrwMvJCcIplQKF5XvQ/ATp5fwDlwQcduYeW5kImKqhmKJlqGItA0QV77BZ+E/AK8QMbck6yIJxzbcRJcBxJNCB0tWmefcDG17sRQ47QBDgyQ9qjM+RWIpoxltZzgCo1UycKzyGvQsK7HwjEkXuxRYzoXBRXqaethaRoUfNKy7Rdc3hI9CiqFUq4mcyADf+p8ttLCXbQfDhyPwo3cXo6sPDKVV9rt2/1b+lC4Hw2r+ahGWpKpAanI56IjLqFfC6QWbCErObq2qfljG/jdqtgO7fNyMSS36pttc0Av3atG46FXwOqh6sH4GFtpFIt+pbOUNQwlmt4QLgJ2ZSegab2sMqEQAjLmt8Ffo5vPLeUOWM6lRpx9lqHnCJNs0d8KZP2Tq1sZQGPLr57QLp2gI3pFb1EqLF1Ujhpbtngz7ef9tydHe9/vn+aGckoxCtObgT7+tdfSwnG3xqT/kGqsrLxI+vHS8XbX7hqvOi8M0AIHQ2acRd6tF4Tg9XKenEfwrwmnHf/MGQDmQQGGg+sGYXeUu38Lek15LxR8503JXF65FAlv51aG8hMrosU+zAqKDSyJ+oLWDXso64yEyoDiPeAyqjV1EJzFb+mmOxO+QhEF7iP96KU3zpoVVRy6ODFWM9D4nMGSm3frjy5OajUllrk3SuIxMwkfXjo3iZvT8ZaMIztlXjIcffISb1wK0OJSoyKXZl0XQjXOkz7DiQPCfA5LUYW+uJLKdd0bMtOB7z8D+Jgv1OTEiBNPtV8Rw1HrT0uO1ftWRmOiq0YajYiH/vEzZzuyJ94DWMo/8DModqMtCMBHfya95o5bqdpoIEeh1xHoNcu3Hm3Nr7DOtuLCNykr3WTNzWaCdysMiTU7d6kzDvhpUQPSbnrXXhAZoG9KarcwneV5xIC/W7yjOAOvPnkLylVwraN9peRpiD9ViD98CuIPJeIPlyD+tDddgvgwc44Kdzovs5hT8VKOcWlLbehCZkKU4c0cxWPRfLTYvMq7jXojnWXMi3u4bxUYrtyseh/Qlezxql57sj57yC+oCZqDS+VlU0qzeCt7uC2dqV8pcZ0euzOp3HXuinAUpLJ3hesO+k/eIbdIJXDgt3ikCcOMapGUPpkP9nsR/qgykMrAukfv9inM1TAjfWKcWXTuBNeYE1qpkdN16bECpKaYIzi9pTI+l1jHBBxgEr1AUpJ1bvyj66UzM3vGkSmjaUdeyh0dmQ9eEmAdjOLehaWecyL47CVHKp+Ccp6xkJRp0UYXeKJCd/DJf2YJ6HVzHCtVKVz134Jq53DKLlz+WwC+0DsW8bllaTsjvczpZwPBU2eoR80wwKX2JmD0EoFRLzT1Jy/Yirh4aSUgMmMg6HsvvDqaMIwKiuuKNFoPmmnRASg0aVR5Gesv42euacHfy8udv3hNo2dOQSb3+L0mgGRcYzAV2qJZ3v2TYC//rLOXEU0KzQFauh8z+UrJfUJv6QO9oXf0mK7TfXpC7+kefUsP6Cn9hf5MP9CP9B39jn5P/0T/TBmjGaMRozFD78eoJA83GkVBRb4Xc8PZ/MV62enQpKQsObQKQ4jJb0I0xtOU2z/CB8MzmjBC0xAXShDK+G1iItE2XRCDWX2+3mmE0Z5+PPaCCIKRpkkIdzwTYW2tCAcJq5cOUoYsbiBIcchQQPCYZIR9BsxvVDC/dMiESOWzns8cVrn46KnzX5+l4EFPlD1pbcgq0H3V2VwB3YvD2BASuHEFTgkQY6pzJeuzSzh5KvANmAKRAdeWcLkUjn5WkHDUl7dNOmFQDAumzjVxKnI1NdoQ6JjXKusbLtZnWo/5+mzK8gvBoG3ITqUu4ppf7sWqE5nP6+c3ZrB7x5Cx+bMVsurkPlseKPK4vXPhRF7+xSahI1ZmXha+YX02gf9cM4DtFXM1m49Wl7v00lsG0ahDkbP87UPGUmJtdnTF4YjdCzb7gWlCv3HJXLYQg1OKpZjP19aqwpDwIdZxrtGwavwMwERV5JlgtFvsHOOGuUoQ19xICopQ0T0OFvRnHZPsdOgRc9fWFr3jgVMGIVTw5vP5DaN39VU5QSaNxg2jx1qVskBXqyXWRLjF6xKLaxI0Rha1q+hp1OLjgrfcOnPXLKsMz7UuMDxsPl+rKT8CjynL7PAL/paCTNeTrgAsilOXTHOZqVxYUQescjiREOF0MtIfkK2yT34CG6RfNTxrGFKI/3Y5RgY5gQpmzdZZz8oq7MFMzUEILv2YMn5S86os8k3wv870c5uBo53mdTeAJWk01mKB6gq7V8lqmLJGbCJIpsCPdWN9FjIVFfo1qT/ICX14dCeKAIdfrbgwRdDZsvNm4WASJ041PG5SDFujaQUxCcLj9Miy26JFVd9827sVoWQiPk1H3VIY29HZKRqYc+LEQqDbBwiUCY0iesyu01YQQk+gUW0OiUaDVS4/pPfM/UHtMjoTAo38rofaizsfeg/8QlU8wWXdG3Hfq1bxpncDKt16qahey60x6NL6z7Wra6yk+HLMRT7cmoE2l6fToZglxaowCfP5PpvPT4BSyGnfif38oCIvHliNeUn/rLveHSpFgUSo1awJhGs01kZMi4jW9XYOqHwVcTEh20NLIBsqnFZ2y+fusZ7HAL6g2xP2dvmwsel0tir7k++x6k24vc1Nh9/gqhe+gsKzctk3L52aO1R7my9fOubRp9ODo8OT0ovuN475afd073259PWmY77f331XHu+FY54e7+6Vu37tmHtHh4f7e5UZOx2KxEYdkse1eHrcO+afq7u/UQ4gR55i60VT7WhYl8iwLq17VMDvxSYfO5MdZdUab3gFfek177uJ558AIlivN1tq/ifqUN2vnc6+nM6+5Ny0zzzpnTgvSCsmpSSWevd7qvv72u7vZff3Nd3v9fZ49/KD9Z4PVM9va3t+K3t+W9PzQe8Ae0axjW+FPU67tC3baKxdMfqWuXusJ0c9LRM4nncLsj7es9JGPe2dqnX+xeXiPXfKWpG2S6c8+tUhMgBuiQfGfX2EhZcOgwD4mWRZw3rXDdlOqmwSAVzQ7qo7rBMguFgyTYDdXEtQnzqf87/4RsQlLLEmRm6iKG7F7APWRHAUfEBAQGqPcqS+dByN5nPFHAYKHXTvZyXC1RvqVjg1rL5oW38dyNeBNPxloCi0CmY1Xs2s4lq7bsT1B9xxAc8e2i+ZUpVL8W9aTpo+L0BHtQMHPMxs2XU6NHRT9UMiSMkB42mrK46KoFXXNnbTurZgGyratsBACRfcaCD9RYL0l353oITsPeAd3zLOgVSub32W9G0exgZGDgPbA0p8ntpJCeLg4ck9fWzjPDpNHgx+qyrUvPSGN5BoSXmBYkYmTRXCg7a4pA7c+0FJMjxl7pFF6CFzH9Hv9lcxNoMFzuZbzXey7HFLKk6ZYhty/xn8L3g3ko2K6jIivcjpR4MidcDS4NKAaTpxzXOTGgAW7pRD6ExopYW2gQqfKzjjtJN10TVG4NIHJT39XMdtLZ4MP/d+dp4o9n7ofXA6VNeVORNGTUckH3bkqURNB3MHO9fwFtPtQa6MQnOgQGI6/Pp3Qn+BU6fReMt6P2nhfm9ZTpwr1tvt17VuO9yJcGCljIJecSYUWqNC4bVEDkkK4cZ5gEGQgbOEdvLpwSiMZoi9nAbTQDcXKILIxErokSc4UX0vawijWYzWIsmd1qeNENsldINehBtrTckbWpxPjc9ZQRmWuLgLesEjzh8VpPVwDAt06kKAhiRWImnZLBPpJaJ6IZum3JP8tFqtlJxiiXVI2ZHkcIVGS8so4QaNxtoa2ACKIDvKrEB4gKDneEkyx+9K3aBXJpGMRoKK6UHKyCJQtbZEepXkNdoDPf+pxee21qXMEtOgS2BEQDmgCH0qfORlPJQR9ELlymJ1KFvcELkWJZ7N55+sIaMBoyNGrwH1Dxl9YPSSCSqNGcLQXow5UQ6Yy9DQDkLfz6xA8HeKA/konn5R6PwLK4Fbx7aPss7HJS5G72SFd5zT+EjN0Sb4F3Hnj82C7H336LgaHfuu952DPXTtrrnF7CjOgquHD7rsb81CdstCx4TbEM0CvX5m0hCpiJ00qXwSuvXCyoMlI0nHxYWLzi2jWnLae5YTelATpjefW+JIlCrLT8xdO2BqW5c+VdAz65DRGYv8E24uL6nlpV4RlHp3jDhrRxAjg84VVe/nT0wjHt8L0H5S432CWwv1dfp+Pv+er9AnRkvWKOk30XrVeYUuhGhU2jpgbnlHZYovEGrJDSvqmYbFlVjQ2pimPNflmHlRamSQRxKYC92oJpyA/JilejwKT98IhNm45VZNYqLXDWK+CDU7qLdMHDCyJdaB3rFGA0Czdsl6ltRFVjWAn5gyEXIDnVYNtX+43z8xERRKiHNU7vax/pZ3BJ1cskYDlYeiHSih9yOf+Y2Gpbp6YISqhsKUJANHpZLrvdAk7bLcrdeti6CqGie36rmzAnX0gFyJQCruV1g0raWTA1eSstseMNwrGsxybIFn9gdWuMrsguqGBwM2GtYH3UCivSrrlUzS48YT4T6wrveykGATfSSc+hpoFuLV8LHdrkRbAO4SK+0RUWu9u77ptNGVsXDoeVxHLIeu1RMrceRPrjZLHbZ/6v2Jx7cJdfKLJepkoWB4X6dTLufDajQ+MM2a+Efrg6CWs7qkY8uUzTXK3qqe+c8r9cx/7v0ZMWNpYNF7PbCovcHjiojzgdEz5n6AbYt4/l7h+XuJFQT4ZvkDUu1o7NySXF+992j5CzTEer9gelQDSJY+v4DpfJSG2wPWO2DOIxu3ZDUBx4ih1SFbn9T3PG0Hg5e42ruaz1yNLaTGf7kk0BMnGxB6DLIrjwOm1VD1FRMp4tPxFFIkciZjih3xoCVMlZoG5Qz3GL4q9e8qm2gvc361MrrLnm8gqcP7KjJHK5GZqxzKRpN4udEEtAxLjSa54v8gVVu9vmDh6JbHajnCxDR5mi1Y1M+PivUVkX5V7Ud62mWEPr6sa8esN1sQqi/WZx+ZffmQCTtufpGDRqbobzHBntZLKopakzgMhg+mYyYM2RHILA2BYOUIMXRMUjFUjvnVsipS3F5eg1MGrMEnzL+uFGgGyc1bWGRS8x6TtYetS1ww2KHwmjd+gnmo0Xi+YkVlOZuwJTnF4IWidxkpDWrDoJUK5aRjDBXB/QkbSPoTLwZHVYK+SI858I1Kl1OTO6XQ51y8Q78cF5zRLmjxS9PzYFwkWo+LGGhNn9QfqAzMCaEgCaAK6Iz1ZvL8dfpnbIDrgHxKZV98ZqSINVPGuQzU1SnL+HGC36rnHRLH8zumVEWMubusbzrcra+s9GGsx5iz2eng+CWJItEiud4x+pkRp1Ik5TTXdX/GPGGKhLGCSSwNPhae4OXIe0X0M7bEZzcCPgIsdJ+Z/qnHrGeJOVkfWXGcxOzx8yRm83nMFo425u4kmhcgcT6yXoK89EcEAHLVQmT7lqsxv2MuN4b2VsTczdCMymf1Uc3qY52FVJl5dxkVl0i84wkPFqo65lIJV5dICwdP5x0ribv+NOGI+NHLRvZVGMeJdTgdX7LE+pa1Thlpd9lrUhZpiwtXvgOkXjthGudTY2adz6/YfF5nKkrR0kS/Y4RO7TTz4WaCcXzL9qZJGidWh7a6/JBXbyH+MPkQRMCgUmb/Mg2GNyc8A5VID6BFDIKP4p/FWjGmYgbN/d29vX00sfK88Y1GVWFTw2YfHuXGBL6IJ0TwWRQw37iKEy5/wpg1aTcJ7UKGof3dd++ODw7PTvafOSpn7l/n2D/csOCF4Hz0YExT5tvoto+Esy6HJh+8AAiKAhJDXMYEZDLmYsYGlXz0kSP3DNTZOZ1x24DQSBVQh9m4mew8QrA/NasO9wYNSlFJ3Cf0iN4Jn9C39BC9QT/RXfqBvqdn9DNoOWBLL1pfygYasJnwWatgoyLWQ9OeLgQ1EC2j5apcqDVNi+yoOkPKU33KOFS4WquW02V1CWBrIjfg3t46BFA223hxlHg+j2tHqU22iiPYtm3cBWEIiQpjrybzKhxvTAufqcsrW4oAIcr5SU+tWopyXWxRctTr67aZivMXk9oZINqZuE+BLp1byT3okZkFq2cGmb9/x5kJpNXwV6njn+IEtxitKDFP9FYf8oyXo/B8oVr6trXOaoU3o6/YC1Ju0gXF9lY2n0s/TuUCuYCWml9jHXIe75+c7h6f5kKv4U/xzpqEIdkxLOWgnho9Uu8Ml2sBwCvXEFwPNRauiF5lC5hSDisdlDlVtdTcER/OSlGCAPYJKSUUUG8hL0IS40Uegpi+UyzddNHkIzwDKoFOyiHtW9V2pJ4mdYYjn1V99NhCKUQpSb+371R3R+rpQbF/t0+1TWnxR4WbXdVXTvZ6U3Jb0bu5kd3cLOnmqNE4oj+pmZ6op3U157unzvlOVriT9jRtoPXeuprv/tL5av5Ii12cNBon9PuKyReeDnVnoafNVfMfQt5LH+ewd6h59yybauGOsNgDmpnZnfHRm0DSvyeT/15/oISGXfV5n5Zhd+2e+9T7tBhaqFfY7e1WN+VadVc2GmsL25L+ccWXlEmA/h3v1Xd8WPyOpZQDrO8rCMv73vvf9g0/uKzi2CI4uR9kgKbzjpbDk/9Iq5Gbv1K8ge9bWmCGM0MkcL6nHG+dn2ix4ZzvctEHMEqfQV5jiaMw6Qd74aXIMw8/1FUBT8zRHjHrB8rUXUbCk1nPo/msaCS8SwXyiWzJhF2KhobitP1orXUJ9dz+AKNewlIcb5Aeeod6UkFEAc2Xv6qigwwFh96h9LHSbSwrWgFn2+qSndevXr14pTWNH28KOsFWl2x3JBe81LTw6QiOWhQ9IhQKjSC69cIAJI8YYhevEpaO6i8coBwcC5kntIlJ9WatN1vfRC2BZ0+m6cha4IJf5IbPrrxpmKkQItNEs+AkiW8Dn/n24vlPqDSGrkmVTzGLxyKmX+VqpHQUT0Mf7ujzIoP3aBu7l3GSLYdFuMTzHrjFJa8ajcWvP97/fHxwup+rwFGMDJgmIcQCLHPuh9CgwyPDzBMG4ktpksi7Exou056W51fVrK6coLg9u36Glct4njTFFWYVnOaK90+bqjKhcRUMzniVLQenDC7smagQxNGSeS9696gpL76qm62KakBbd3tTTW6xec/0GU7LG2bBLdySoRnS6+a3oOjmc1sorpvXyfuD/Q/vMKbZkEpxPrdF9fnCvGomo3h4nIP6VTd0bUQ1DK1+IV75bPWINTorHLs2ZGBxFh+O/niSG1xVb2SiohHG13g75/psDf1j63rrmTHo8asxC0vqOkB37vgNn+CBh5eIymaOGV9d6ZG86uuKG4Two4qfdd+ihH9eDb4iRYgWzcSk64fTVTAFadXuolurU9OApB/UWbtAwgf9TdG+dh+ffdg/gdD1JaNz7U9t7MArAnZzz2cKkkYyDVlaA0c4BhGCPE/W4jS003IId7OCejCJx8b6jLfJwWMWYIk/6lYKQ/AC/nexf2EwzI00DYVyRmhvDc/3azB7TXT5W3pMGChiF/oUTJHvVuAxn1dUYTg0rHalHOeizCV+PVkWMr4Q6/HERUXFwhcuONqd2pD4+eExsyFT6UmcMCe07ylNDRiICGiyaFerQ4Wy0+cOkxw/IctJbv1AnLIqFKOmnBoeF9hs59i+hFRXP9AfCOV6+70Ks30vasj3Jb2+s6feXk6D0P9ToQB3DtQrTS3unKpSbZZrK7RMGjP5WcmZZ0sVDhrzVrnxTd/In3ufnQ7Z7vSWDtv7wdYm6EjGUXMSBMTpxTa/9wmPFMavB+BfiIrWR9add0JnPE0E+Ajizb1g2JHd4mSUDfHPIFughc32fF8uQ8mDlKH8ATUqCTh4Dyie/El1Q+wQO1n8PARZTugPwm9PatSnE0gV6kaM3ki1H3M1c83LTvdVd+Mb9uIrLOR2H7iQIHPFfbbl7CVFFhf97sCJuJQQnBrNNl/btindIXmQorRLzXYxHLl8kYL0/33V6eQ804Z+sQuaoBgPKay64EbWjN+AUa7FLW3PskvM+FfkpEb6xM1ZsVosSVgdleOGNfQCUwbton6z0HDO+Kw1u1gGyaQ3OzzVYmF80+6ggblb5l7ipSMjk/lfrrwgZL4JN9NAbiXx2fyjWt2cluZOfq/ZC9jDlM19iBI83v/27GT/nVkQCc17HS+GW/gQvm2kXDTybpmRZvFkgl9TXGs3028z7OT5EsODBpZ0imzQ1TRctDaUdMxWh05tdh9kxOpojs2VV5AjIF+7aTQeGo2P8laSjGmgLNkUUff6P/xXGIOyWOkTAQA=','base64')).toString('utf8'))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-traffic",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"main": "./dist/local-traffic.js",
|
|
5
5
|
"private": false,
|
|
6
6
|
"keywords": [
|
|
@@ -20,19 +20,19 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"start": "./dist/local-traffic.js",
|
|
22
22
|
"typescript": "tsc",
|
|
23
|
-
"
|
|
23
|
+
"zipify": "node ./zipify.js ./dist/terser.js > ./dist/local-traffic.js",
|
|
24
24
|
"remove-useless-whitespaces": "cat ./dist/index.js | sed -e 's/^[ \t]*//' > ./dist/minified.js",
|
|
25
25
|
"terser": "terser ./dist/minified.js -c -m --toplevel > ./dist/terser.js",
|
|
26
26
|
"chmod": "chmod a+x ./dist/local-traffic.js",
|
|
27
27
|
"clean": "rm -rf dist",
|
|
28
|
-
"build": "npm run clean && npm run typescript && npm run remove-useless-whitespaces && npm run terser && npm run
|
|
28
|
+
"build": "npm run clean && npm run typescript && npm run remove-useless-whitespaces && npm run terser && npm run zipify && npm run chmod",
|
|
29
29
|
"crash-test": "node ./dist/local-traffic.js --crash-test",
|
|
30
30
|
"test": "node ./test/tests.spec.mjs"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@types/node": "^20.14.
|
|
34
|
-
"terser": "^5.31.
|
|
35
|
-
"typescript": "^5.
|
|
33
|
+
"@types/node": "^20.14.10",
|
|
34
|
+
"terser": "^5.31.2",
|
|
35
|
+
"typescript": "^5.5.3"
|
|
36
36
|
},
|
|
37
37
|
"bin": {
|
|
38
38
|
"local-traffic": "dist/local-traffic.js"
|