From 48e03a816683c797a5d47c02e1a0f2d34541e064 Mon Sep 17 00:00:00 2001 From: Sjoerd Date: Mon, 30 Nov 2020 17:35:16 +0100 Subject: [PATCH 01/45] Allow Crewlink to connect to server over TLS --- src/main/hook.ts | 8 ++++---- src/renderer/App.tsx | 3 ++- src/renderer/Settings.tsx | 14 +++++++++++++- src/renderer/Voice.tsx | 2 +- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/hook.ts b/src/main/hook.ts index a8644743..bb7ea894 100644 --- a/src/main/hook.ts +++ b/src/main/hook.ts @@ -70,16 +70,16 @@ async function loadOffsets(event: Electron.IpcMainEvent): Promise { diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 7c713e1a..f2b3c823 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -27,6 +27,10 @@ const store = new Store({ type: 'string', default: '54.193.94.35:9736' }, + secure: { + type: 'boolean', + default: false + }, pushToTalkShortcut: { type: 'string', default: 'V' @@ -78,6 +82,7 @@ export interface ISettings { }, hideCode: boolean; stereoInLobby: boolean; + secure: boolean; } export const settingsReducer = (state: ISettings, action: { type: 'set' | 'setOne', action: [string, any] | ISettings @@ -111,7 +116,7 @@ export default function Settings({ open, onClose }: SettingsProps) { useEffect(() => { setUnsavedCount(s => s + 1); - }, [settings.microphone, settings.speaker, settings.serverIP]); + }, [settings.microphone, settings.speaker, settings.serverIP, settings.secure]); const [devices, setDevices] = useState([]); const [_, updateDevices] = useReducer((state) => state + 1, 0); @@ -241,6 +246,13 @@ export default function Settings({ open, onClose }: SettingsProps) { action: ['serverIP', ev.target.value] })} value={settings.serverIP} /> +
setSettings({ + type: 'setOne', + action: ['secure', !settings.secure] + })}> + + +
setSettings({ type: 'setOne', action: ['hideCode', !settings.hideCode] diff --git a/src/renderer/Voice.tsx b/src/renderer/Voice.tsx index 6e7c94b2..3a1842ce 100644 --- a/src/renderer/Voice.tsx +++ b/src/renderer/Voice.tsx @@ -148,7 +148,7 @@ export default function Voice() { const connectionStuff = useRef({ pushToTalk: settings.pushToTalk, deafened: false } as any); useEffect(() => { // Connect to voice relay server - connectionStuff.current.socket = io(`ws://${settings.serverIP}`, { transports: ['websocket'] }); + connectionStuff.current.socket = io(`${settings.secure ? 'wss' : 'ws'}://${settings.serverIP}`, { transports: ['websocket'] }); const { socket } = connectionStuff.current; socket.on('connect', () => { From 65c9766d6fc6e5c426c716a5ebfd14558d8e8895 Mon Sep 17 00:00:00 2001 From: Sjoerd Date: Mon, 30 Nov 2020 18:10:03 +0100 Subject: [PATCH 02/45] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 99b1197e..6c78d772 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crewlink", - "version": "1.1.2", + "version": "1.1.3", "license": "GPL-3.0-or-later", "description": "Free, open, Among Us proximity voice chat", "repository": { From bf45a44e4443ef0323b167ba954d099e444f03d7 Mon Sep 17 00:00:00 2001 From: Sjoerd Date: Wed, 2 Dec 2020 00:35:30 +0100 Subject: [PATCH 03/45] Allow protocol specifier in Voice Server field --- package.json | 1 + src/main/hook.ts | 8 ++-- src/renderer/App.tsx | 5 +-- src/renderer/Settings.tsx | 81 ++++++++++++++++++++++++++--------- src/renderer/Voice.tsx | 2 +- src/renderer/css/settings.css | 5 +++ 6 files changed, 73 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 6c78d772..7f605a99 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "publish": "yarn compile && electron-builder --win --x64 --publish always" }, "dependencies": { + "ajv": "^6.12.6", "analyser-frequency-average": "^1.0.0", "audio-activity": "^1.0.0", "axios": "^0.21.0", diff --git a/src/main/hook.ts b/src/main/hook.ts index bb7ea894..9b0648fa 100644 --- a/src/main/hook.ts +++ b/src/main/hook.ts @@ -70,16 +70,16 @@ async function loadOffsets(event: Electron.IpcMainEvent): Promise { diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index f2b3c823..c7a1e909 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -1,11 +1,33 @@ import Store from 'electron-store'; import React, { useContext, useEffect, useReducer, useState } from "react"; import { SettingsContext } from "./App"; +import Ajv from 'ajv'; import './css/settings.css'; const keys = new Set(['Space', 'Backspace', 'Delete', 'Enter', 'Up', 'Down', 'Left', 'Right', 'Home', 'End', 'PageUp', 'PageDown', 'Escape', 'LControl', 'LShift', 'LAlt', 'RControl', 'RShift', 'RAlt']); +const validateURL = new Ajv().compile({ + type: 'string', + format: 'uri' +}); + const store = new Store({ + migrations: { + '1.1.3': store => { + const serverIP = store.get('serverIP'); + if (typeof serverIP === 'string') { + const serverURL = `http://${serverIP}`; + if (validateURL(serverURL)) { + store.set('serverURL', serverURL) + } else { + console.warn('Error while parsing the old serverIP property. Default URL will be used instead.'); + } + + // @ts-ignore: Old serverIP property no longer exists in ISettings + store.delete('serverIP') + } + } + }, schema: { alwaysOnTop: { type: 'boolean', @@ -23,13 +45,10 @@ const store = new Store({ type: 'boolean', default: false, }, - serverIP: { + serverURL: { type: 'string', - default: '54.193.94.35:9736' - }, - secure: { - type: 'boolean', - default: false + default: 'http://54.193.94.35:9736', + format: 'uri' }, pushToTalkShortcut: { type: 'string', @@ -73,7 +92,7 @@ export interface ISettings { microphone: string; speaker: string; pushToTalk: boolean; - serverIP: string; + serverURL: string; pushToTalkShortcut: string; deafenShortcut: string; offsets: { @@ -82,7 +101,6 @@ export interface ISettings { }, hideCode: boolean; stereoInLobby: boolean; - secure: boolean; } export const settingsReducer = (state: ISettings, action: { type: 'set' | 'setOne', action: [string, any] | ISettings @@ -102,8 +120,34 @@ interface MediaDevice { label: string; } -export default function Settings({ open, onClose }: SettingsProps) { +type URLInputProps = { + initialURL: string, + onValidURL: (url: string) => void +}; + +function URLInput({ initialURL, onValidURL }: URLInputProps) { + const [isValidURL, setURLValid] = useState(true); + const [currentURL, setCurrentURL] = useState(initialURL); + + useEffect(() => { + setCurrentURL(initialURL); + }, [initialURL]); + + function onChange(event: React.ChangeEvent) { + setCurrentURL(event.target.value); + + if (validateURL(event.target.value)) { + setURLValid(true); + onValidURL(event.target.value); + } else { + setURLValid(false); + } + } + + return +} +export default function Settings({ open, onClose }: SettingsProps) { const [settings, setSettings] = useContext(SettingsContext); const [unsavedCount, setUnsavedCount] = useState(0); const unsaved = unsavedCount > 2; @@ -116,7 +160,7 @@ export default function Settings({ open, onClose }: SettingsProps) { useEffect(() => { setUnsavedCount(s => s + 1); - }, [settings.microphone, settings.speaker, settings.serverIP, settings.secure]); + }, [settings.microphone, settings.speaker, settings.serverURL]); const [devices, setDevices] = useState([]); const [_, updateDevices] = useReducer((state) => state + 1, 0); @@ -241,17 +285,12 @@ export default function Settings({ open, onClose }: SettingsProps) {
- setSettings({ - type: 'setOne', - action: ['serverIP', ev.target.value] - })} value={settings.serverIP} /> -
-
setSettings({ - type: 'setOne', - action: ['secure', !settings.secure] - })}> - - + { + setSettings({ + type: 'setOne', + action: ['serverURL', url] + }) + }} />
setSettings({ type: 'setOne', diff --git a/src/renderer/Voice.tsx b/src/renderer/Voice.tsx index 3a1842ce..058c7d43 100644 --- a/src/renderer/Voice.tsx +++ b/src/renderer/Voice.tsx @@ -148,7 +148,7 @@ export default function Voice() { const connectionStuff = useRef({ pushToTalk: settings.pushToTalk, deafened: false } as any); useEffect(() => { // Connect to voice relay server - connectionStuff.current.socket = io(`${settings.secure ? 'wss' : 'ws'}://${settings.serverIP}`, { transports: ['websocket'] }); + connectionStuff.current.socket = io(settings.serverURL, { transports: ['websocket'] }); const { socket } = connectionStuff.current; socket.on('connect', () => { diff --git a/src/renderer/css/settings.css b/src/renderer/css/settings.css index 5eb7eccc..167c538d 100644 --- a/src/renderer/css/settings.css +++ b/src/renderer/css/settings.css @@ -46,6 +46,11 @@ input[type="text"] { padding: 5px; border-radius: 5px; } + +.form-control.m .input-error { + border-color: #b00020 +} + input[type="text"]:focus { border-color: white; } From efa1ecefdaaede31e977fcf843fde5f2c4ed8b72 Mon Sep 17 00:00:00 2001 From: Sjoerd Date: Wed, 2 Dec 2020 17:43:26 +0100 Subject: [PATCH 04/45] Use matching Ajv constructor settings to electron-store --- src/renderer/Settings.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index c7a1e909..f92eddfd 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -6,7 +6,10 @@ import './css/settings.css'; const keys = new Set(['Space', 'Backspace', 'Delete', 'Enter', 'Up', 'Down', 'Left', 'Right', 'Home', 'End', 'PageUp', 'PageDown', 'Escape', 'LControl', 'LShift', 'LAlt', 'RControl', 'RShift', 'RAlt']); -const validateURL = new Ajv().compile({ +const validateURL = new Ajv({ + allErrors: true, + format: 'full' +}).compile({ type: 'string', format: 'uri' }); From 79e5c874bc4bea959a6e1da81ef1a4437329497d Mon Sep 17 00:00:00 2001 From: Ottomated Date: Fri, 4 Dec 2020 13:15:59 -0800 Subject: [PATCH 05/45] tweak UI, embed chime, and don't keep mounted --- src/renderer/MicrophoneSoundBar.tsx | 6 +++--- src/renderer/Settings.tsx | 7 ++----- src/renderer/TestSpeakersButton.tsx | 6 ++++-- src/renderer/css/settings.css | 19 +++++++++++++++++++ static/chime.mp3 | Bin 0 -> 202754 bytes 5 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 static/chime.mp3 diff --git a/src/renderer/MicrophoneSoundBar.tsx b/src/renderer/MicrophoneSoundBar.tsx index 79e5e0ed..1514dda3 100644 --- a/src/renderer/MicrophoneSoundBar.tsx +++ b/src/renderer/MicrophoneSoundBar.tsx @@ -1,7 +1,7 @@ import React, { useContext, useEffect, useState } from 'react' import { SettingsContext } from './App'; -const TestMicrophoneButton: React.FC = () => { +const TestMicrophoneButton = function() { const [{ microphone }] = useContext(SettingsContext) const [error, setError] = useState(false) const [rms, setRms] = useState(0) @@ -44,9 +44,9 @@ const TestMicrophoneButton: React.FC = () => { } }, [microphone]) - if (error) return

Could not connect to microphone

+ if (error) return

Could not connect to microphone

- return
+ return
} export default TestMicrophoneButton diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 78d1008d..fdcc0660 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -197,10 +197,8 @@ export default function Settings({ open, onClose }: SettingsProps) { )) } + {open && }
- - -
+ {open && }
- -
setSettings({ type: 'setOne', action: ['pushToTalk', false] diff --git a/src/renderer/TestSpeakersButton.tsx b/src/renderer/TestSpeakersButton.tsx index 44109092..0023af82 100644 --- a/src/renderer/TestSpeakersButton.tsx +++ b/src/renderer/TestSpeakersButton.tsx @@ -1,12 +1,14 @@ import React, { useContext } from 'react' import { SettingsContext } from './App'; +// @ts-ignore +import chime from '../../static/chime.mp3'; const TestSpeakersButton = () => { const [{ speaker }] = useContext(SettingsContext) const testSpeakers = () => { const audio = new Audio(); - audio.src = "https://downloads.derock.dev/chime.mp3" + audio.src = chime; if (speaker.toLowerCase() !== 'default') (audio as any).setSinkId(speaker) @@ -14,7 +16,7 @@ const TestSpeakersButton = () => { audio.play(); } - return + return } export default TestSpeakersButton diff --git a/src/renderer/css/settings.css b/src/renderer/css/settings.css index 5eb7eccc..5f698e2d 100644 --- a/src/renderer/css/settings.css +++ b/src/renderer/css/settings.css @@ -67,4 +67,23 @@ select { flex-direction: column; justify-content: start; align-items: center; +} + +.microphone-bar { + width: 200px; + height: 10px; + background: #1d1d1d; + border: 1px solid rgba(255, 255, 255, 0.5); + border-radius: 5px; +} + +.microphone-bar-inner { + background: #e74c3c; + height: 10px; + border-radius: 5px; +} + +.test-speakers { + width: fit-content; + margin: 5px auto; } \ No newline at end of file diff --git a/static/chime.mp3 b/static/chime.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..344ed313af7f728548eb66bd57b2b693922919bd GIT binary patch literal 202754 zcmeFZcT`hd+wQwk2q6Rr)qwOSofSHY5UTWEMKtu@i-3p;y%zy#qI9WBQ|Tl$rTNf1 zhzbaZ1w}IC&a6hPlZrO3C4*a3J{SijF^P9jGW?G6*YCO3wj1drWRJV_6`ImR}U{=zrc{Nh^S~%Y(jEsMs`kK zeo@KY^2&R44G&t{9=CV(k_U#Kj!jI?%q_00K7X;fy}SSJ;PA`0<6nP1{Ny5?|6HWf zpBMj81pmEqaviK@Sl<6={`>g%2>d+)|DTM&2@?hZK;b1Lll)tNIz{`HrWzT58tG4s zj~xq)S28IreCwi{D-l_-i%ZwZ5*b^(mUf;<=r2`E(~J$L?7$3#H5&$f3=NI71_ymq z$7MBC8ZgG(%zZ3&&E;`nay(K`#>|$JJY)GjhzJ-VVsTaD-!04=W-4SW4NEJ~$Tk{c zQ~WUqLE{H_m7W#KY>s;bJ#YIFzyTds$^i*uEVzDv!d!Ng3qlvM*}{T)i6{a&p9@?p zX0YASm3rYy%WD_&K~Q7xD$kck)vmuK3w_6i3;cRkZ&QI98W0RJ8};Hx!t(M!rSjFW zTbJc5bmMiqPC4ycCL`nGI3+v6=g*xBT7C3rV3rF=QYuJgysb>HiMC9-pR&tV`i3jH z^%3{r96wQ*-${hO(jm3^Hco!MX|Dt~%Vp6J*1NzlfVS1vEk$KJ;ixkHv`;y(o;+sg z_?a1T|Mp;Fig$_DU=oLe~eER+w#5k+rP+ zmA0wPN%F(O0}GM&EcZ&THY@Zlun(XePEMY3#(1Y+Z)|0j z2-pOTJ{hHpU=yhxM3ch7HS#XVNj`)uOn7ywBBLm0O}Uen^qhk=pNW~k%g1XtWrGU( zF9cX2$5BlfxJEAca*(&zb!zAAQ>QZGM-P^_)Lt5+f{f529a;%?O9e458G_&w^=U@E zVmuX5X&OV`EGKhPNW4u-yrTqjtel_|aYN80V`GvW;HpA~WKZERQBWSeEM5t?7b}{D zmITTD3oXb76@~&->T&8X2p^KzP+ZN>W@Z6yDlCTSnV}%kmUp98M0<}mHfsj~%YaQj z?W{edr@jRk(gnrAQcAl9fD!gU4l_KLCL$&dxLRV?2ESLuPsNJY(?~{D4q!y9@7IJ% zu^QX{Dq{}f2kHg+&bXo{j92GXZ%RIcd5nU2j3Ik5i+kGR`>FHBpgHQ@&{N7u8af=SJ+^t;&OQZ-tB;AMf&& z<)>rpS(3T)4djh@exH;W-ir~m^&){+PQTBjVqGv%koCH_^lvoBGn2Iqo z6~xq33<))4f*I~1$rN+T6o@09lQNKog5_`9t2j<6ITH0TKy8gF4VYzu8-(LSI;5$o z14Q6GRi+=(Sg20>ib?FJz_uk~)QQYY1iYy(#dN=0tdJ!&&B>O&`oWtPvLOqdx!b-C zGh|?Tf9SFZ+!jHPxl~XOVWcX@hjg8-0FtsCWz9#ElTn79T)8O#e`&DP)ylLTN`O$6 zlIfubd6MRB7qxi`%uLLi@#R4}(AI{*q@nl$$0f8&7WL)A!3ZsDYHeq1^UWDG>4~fG z7RDNH8Z!{})5vU<4^oxCxq{ae&a)}9-aN?df2qX_pD1{?&SKk0_4b37oli?7o#{~+ z#%hL#wFg8LOIxeX3$kwq5kxMX%@e-qQBw13^WPF$0nL<}X$wI@hBM}4yL!SUm zn$>~oVh4Gdst>%;)L8;(NemPUu-cA79l3FvvLlYPJS5QX z9+=JsceIujC`j%`bP1~6)C$)U;1!9Dos>{5LI~g)*tez^j{3z;8`1QZ31T-@9!Ox~ z8Lo>LB%@gsVoL18SXAcjT-{yQx9~tc`--6NjNY0x|HQ&sz{N5P^6AS77u|P3=uP9Th$YeVMGkSW%Z0+-l#RHf6YJAF}v<+EbzH-z znyT08)v9iMVu`f&?>hfBQazWenh~{{lg>duYZI)0%b4maC4{RGv~ZR%dYV%aslM#b9J6Ea9HN4HG2VQgyeMiKNP;QCiRX3hQxwF1 z7S!2umyQ3+n`w$X&~ldvNPJ0OI3qc5C~_uP-QLw16ZLA(#aCDrm~np&fn_;aNn2HB zhiN9dQ5%p)pB)c75fQnlb$2ffN&a=qvZ?&|t!{y8CL5~D_hOOg+YPRP>iv1||3Kji z>`fgthT*HbcD(ut6kIqfXzcAB7-|nXd%saMkB| zQIR%oJoLp|x(#tl72+A(&)b;_9UhwrJ;; zK8+irng-=%8>i#tHiU!h<4k7S<9q}mLnw%#y;)HWX}58&;>DUmV@9SOPc@k|vfP|( z6Xxf?Lx#)oMLlmJY)D>|5OMwB^;@y#DEt&My*D9WUh@|1(VcBwjbzwXZVI=f=FyZ) zSjh&a1O{R1OpU9tDW6+BKoH!{?79kwaJmh5gt~Io4&5g&-G1s^@@AVn{#yKMLXJ2z z@{E2;743RY3!p#qIAa9hPDCwLmO9CdwvCUs%znM5Afr>~wM)~!y85&%+xLYn!Ob^v zSXA|nvi%!vaoT+^OH+p*OZLKIUu>E<5ML~9E55E(wC7pc`1*3Wey?w<%Ku4SlYboS zYcAb>2V)>H?02|AJ?fOXaOL>!vg@(SbEw|8Gpn^9_wAdvCu;pE_pc6|FZPe13aV(W zku45?EcDx_sJJ)&|DQYQf8tI1FMJeeN~r_WsFIaJuUX;ZpbMZG1p~4X^T9JjUEF8& zDI6OR2MUtpKqg8g2qE`@gm@B|Ol}2fi6S5xh5@P}AGei~@w|Dcyf})vQd+Sg|2H~> z4i$Ss3+e^g`B@=f;D;wnjbaskAOMrYsBl9ZZSDpOC$)1=1&o#g7_!06{=lK5X}2RD zI#vNf;>Qohbq7ex|_h!mIOU9(ie+`^~GQabWcK8fE8s zy|!jEM*E*6CfeOu!HM`@xHTGwNkn}%Jp$JnMD`h#b8Maw$TSb^uR>xaugh0fcq#vZ zLPYG_Jvw@ZuSN+NN}2lafC%GRR?LL54U?H9wdGwPFJY@LO_H{?bjH;JEu_*Q$Nj6O z1us3h6_QK0@QD@^HUHs6;_ zE6l1*OMU^*K9~xZxHDC;B zw9690Ab|v7l5PUy#ZU7f0RF)6zGi#I1%^jO^nbmq!&FY68krvtKuzdcpS=b4Hd2X`%JU_zQ82S1JRFi#5;wEcnJJCeG7hJ|Gvx9#Vq znvS7V)AMpwmT4R``9X8a@f1dy%sN7o&wHms2x07N(4E}AEr4t6ktJ&AL;6oXd?JnE zv{ZwB+fi?f`qGhNn^3`%7H^?jv+Jy>9sK>80U>lOT@qiXG&&d@BmlKnJmSJID`LYV zq0BtJH#?^zJ`7AW1En{9$J zW!c6d>V`pUlMy%SpHQg#yZm=X0JOp%flp(YRnwOoWmJh@!FYT)s7{Or&#RZ>oYUsP zaq<@shHnN{NT)$g{Gu4$27!Y#E&@3ss}MvkJBOABf6#sKrfC2^!CXL&*($X~3WMF@ zii3P;x~!0%VHkaNJQJ}r{+_yK=@D_>7W)~^=E4{({m4OnJz60BoIh{a;qsIM;grGg zG`?3uVPLk7SMUDtp4Jct&^u-ES2^MQn?mVwN3xt>)O~p|**8H0S?aW}FV9H;1e-HM zDvUaGNW+^M_jSWf_vWp1FVOKkT#6xwGIg2odR5E8|3JY%_U$8T^a&KSht$IGk){Q|NE7R*yHcI>)Yl1&@?4R6ErTXzy@#kZlXABF(E`A%md&nD1 zldVd<6vqOciqU|w$3#&vW<~S7NXAkJl8CgBxH|F_Q{d0EYe1CK5fq9+pQaj*(|fu~ z+E5;`g~2R?6Da&E2@nBwnwY9@t^8R^r!OX*0YQRXKqfUbwTBdopr3vyE_9@>GjkmW z$^p87>*Jxp>uYiDV4Z2)g>BEKG@VjzGvji2+SlerE+JJAJjG$p$j5bNE(ZBISAF+dTAYx!cs8W!C1y%J(o^#SZ!)oahYq?}Ff+_a<>Yj{ z6yCU2-g4Q$OFM*sxNCl{5(w(9jMUyU8u_W#^{LaMeYpJb`mN@4`P~Gww7FCDH@v6b zdaggyzWE{Bk?l+P*C5%)jjfjwLb;p^@U|BUUUT1fdGaYH_{+UT#h(-VL-AJsgu=ft zrT*{N6_g|ofGu%Bs!x5=WH@3X!6vYvM4A4)PjD) zo?s*J1Y{zMKmaE>h#d(_OGyABwpi#EPHzDA+2jj1KAaHn1fK&p8*fiRK<2Ss)u$x5 z4o6Y!iVrsApurzW;Pw4ljB!@#&1#6`${PVDI~&JP-`Qan)w{(-&hMhQ6Hm~>Y*#l%w$kD{>7>s z@XmNs_l35t^`@%LrQ`D3MBb2=5v}i|h)l5o+R}QVQ27Fy!tam%Kp_hDzM2lj@Cldx zPQ6V1*KU(r0(;(S)&z?8aotRmlC_$!f-O*RrEuFh^Nj5wr@yj~NiGSlI4`;dtthAt^2z#8a7y^NiAE(tiqgS&s!ucYj-X^m zC@VPm<4{2&E#`Z!wZ%L72TskFLMAC6r7GBm-|^afkzGNy=9-+M%*=+ZS(f)HYF9CQ z=TO1Qr#7Wm|Gd4`8FKp>x!5`24qgq8d!7|~5c(-HxMsx1i{ZAySzAPdX96TgG}Bq?0B2=Z(O zQx$_aT`VelqnivUksEEtNh;(Ij5MM?`kxEk&<3=*rZfd2`llth6QP)uZURx*8zX0m zQT7?spkp^SstP&B6lKT+?nKH->eKg81hONqZY<_gd4)zp;RO0M$&rit`92@_ORbbt zn1Ac#6etYU*w?feH6z(##C19dC&Ifr5SPek9F_QqY?)qMRrN*ALBj zl+y8{De=JT5-7oKKWo*dFBfhdeo&QuHh<>eGrb+(gHa42ZO?1R)-SSh{E^8Sj{{SA z&x*&{rUGoMPxOi04*DUhPh;&{mz_voTYEyOab;VF=eNd|Dkiw}7`VeGyl!|^ukV>v zF8?l?Xu@5p`+2z3rx#7~a^~rI#Q5>jqqg8$zI|GOVTP4^G^2`pSI-@cKS!Q=ao_1l z%k8`E6F)E&E2MVCPCr}t4tWU?P9Ddy3|9QKq)elu$ewTvSptY7i&7nv!{kqb+VErY z6`+#*0+1jFKuyW=*eod3WE|9T6$^l5MmoY;#RpSSb#o<)Wf1EmLoO;Suzui`*JxDVd;6#<*4ZpYb@Jec2lYP&F zOjbqho#>n9`px{or~In;oa|CEL%Qq3t}4Qrc0R3iAo65mf|^eY)(K@C+D3YXy>;rx zO{}(C(Opoye6gPvSS{OvnBMmGdqH@6>6u3!N7o#U>9;$pPn)#;>s!dIzhd?OLioiR z<&_6n-0n}_^MB8)xuY1+gs{SO+9KZV`9crA^H>}C8N4<3e`%)*x@{KaJ>t^4G5dZe zw2EVP{;>RFhy26S&nJEB-oNTyQvBezk!(XLDvMP`%@<3RuD@+MUOSxoClvnooBsb_ z`bMA@DF^f(3Q)*YuEX*7&w?rt2uP3j19{1jxLU+ExQ}N8S@1t(Ac|OQ`uqHhFN|ny z;3=^mzz<$*e-6fv23gr+-xLyPh4h)o>Sl2+FPa?N@p227VqxSQYjsE7iAZBK1YyoB z;>oZWGfpcN*p}wi5Zp<_o#@8d6iN=uk4yld%k&h6*-JvHioFe!<)&AY$J!dORp(0F zT7D?Fa9s-!ER}dn7v?fp8zr&cM$c=C8rO)@P%3aeZV|ifl=E0dkWEE^^Kc_uuDpNK zP}%aQy(RDDg4iD@_`%+6)BSVG$ca+$+KF>0&ONN!@PAcSQ&}si?k# zx%SI{g$84MH8)Pff344fy0z?WW&YaO4}))hLD4-A?w$#Ibm>^gt|tGZvu|?hTK@Ww zhO~v<%jU3z-%SsSdmi3PAK~c>@+o~E?s$X!OX`i6Tv2?Hxvtz^*yYw(`F=g^cc(_K zz8x^XD2K%nwy~F?<98f?J}smog%>Do+{Q8kK?NA%bL{7;Icx%%g5|`QVd;tOSb*SL zASa+&U`6yQKx}YAAu|B9LcoEnGOvQ{*^?j$I{5^s#4s&pLK2v7-a{tFQaXDWi2&4a zTocOz9lXm+f-(G^fKTZ!atY7WuTug|KI zExKP%n^n_X8KMYevYHmKU^q2?q%a-SXbH#)b0eqIm zZ~H9=wImjv1}GgG`WR(EsfBLo^N$~*r^WL+VmYP!V&7oZb5^Q5saUqHtBP27AM~1# zkkBTF!jCoDwBN>8${35MFI|)of9I76aZ;>)zs^FnJbleGn0oC_gDyw$=Ji|kml=y| zI@Sjw+pG}{)g?`5l`iZX@el15p1SvdqS*FO(k9+U&;F`w#98{Vb>Es*sqRycYcuz> zBZd2}x4g3R{;I4{kjcZd!Z1uz@wZa=Z?ph-g=7ZKXkJzm7o3-|rF4SHzyzp8nN5FIk;ly`~ z9=1Gis}`*ZK(tzo(v^fy*?KO#@ochu;~beVNDI8XycCkms_BEXovotRsk(GNbh}!{ z_*;EotU2G=hAni#%&UHnofo79ADu1LBx6RwE?mxcBlE+$njPMti2d5R0t|Qcg9VsW zl4&&WA1Fk`zVD<%p2QT==P4&pcnb=I*!`syZ#d9lGLFi)TsR%XEzG|3KnO78X?as? zIPYgU3S$yd=3H}h{JQPG%ow|Feiniibqg+#*={WHHy%D8DcOef-zxI)97=;64gv3< z_&=HF{v~t6NNO&N@UX#j>*i+cK7P$))VI5^%|=ZL=3rLR+Y{*!J?36>N%G0&vddc3 zjU_j$ATmW8YCE6{Wc@avsvJoH7I}3+(6}14NUL)J%+@(mKr2iYE>W#7lRK85T zmYN_Bc>x6p`p%6pA+~V{v~}B546WTL0KLUl+E3){f0edEA;8&6u@8l*GZ1&PO9>q@ zUHlc)_ad?AcUzFt39*faC^~ki%v-=z_6TQg%set7^l?(@ny&lYi|SMl#-^e zT$$W3OpUbB9Uac84E$~v-XfP_mPdMJTk_W~W{Ye2upCdPf2)|q#3*I9z51K&8PAZC zA;{0d&X&ZOw?>|w$xv4dnwy(;56)|`0dq^N$fsNvvx+NuTh=tZSn;*JMk!P`Mn0Ie z&$DkVF3kref72MauCHc%*>t2wKe&sRVs%ek8@yt2%d9W*;++i@m-2rtGdMoh8{-3Hl3Y^?tElkFhmUjqKVdU$!kWG2zfEq4^`*Stjh6Ea4?Kpk>^+$ zvR<=Ne*3K4^y9zx>4x0m>ihhqNPgSldv1j{D6&7V{5txz>`zD@PotVNH$3x#lo@fi zAT5eKjXn*U8={CBBnVeQt^0a`1HP|-YC{bxxDf}Cn!uI;a~uLN2YJZUAR2&!2(mOt z4ZkW2dVst%2CvZ+^0Cnf6O1ONm7dIB*WiW|6M@O)3SpImi(MoU)RI4FG4O;C4o9-) zSIO&X_i@~N8yoV><3vHtIE8{AWs~Gsd@hZR$=JFJedhCE={%y~?@ZYeRE)rHBOHRh zO5UBTGtXl2O}>A{``K@;jyG~9_41+@D`Y2M+(kdigDjQS6(Swkj0w ziz6QCwmBE%TF`_DcOSz-{LRjy`%VdC-<$+lW%g!_SETnONAAf=uqK9zejjqV##~2Y zO)rrOz)XExEZMbld+_2+xx_t>Yq}1*^Z|8)kg~m&eTORKta3S-{#brV&sJ=b>I-== z)JU60>ze6>>#Wyux!Pu0xvM^}z~V{4*dX6Br!uM7K~D#f}mTz*GpPqi9j|huYnHX2u|27@Up#w zp_SE|LD3`Rm|SaIgT3iJkl|W1J-ISjJ|C(yWbOU>NZq}7Btj^;N_5tF1) z;@5Rhw*nVD;jRM{I`8!3@ao%~D^^Umu_*~%TS}hj#dp?elWxH`kb+jJsf(N4Iv(M| zSDW3pXx;xLG`hg{qfY{jUyb53PPQa}xrsD5Sz(hStR{qD$mvU?T87U|GGy_XN5Z`u za@MDWRP=8B72i1kDPk>d&x1Wae)#m8?Um+Y8eQ614j=DglzliIq^IuO&V$i*2SM2H z^F!lb+=YhBiy%!8bq7jz`pFT z3Y%4DleE~4Mx#faxy!Fix8Prlc?fH7E5AHuB3wL4`w>YUbUyg8NuW;PCD1{B5txW_ z1X<{~<50nE!Ut#?K^3A!aD#{tv`O@Yc9e`Gf}}ve0&*At`xK~#Zk*lVlVz6|zeTub z%CLOjY>tSHGQSp}4qiVZsZ(Ax5Ow0-26j;aZilBCp^g^0!?|)A+m=-44Kw1IPy_QU z`xKFnpX8Qaml8f;nQ~Vz3B~l3m`-B05uQKF3pw$ds+{lUfqko^X4uME^S-g5SRbmn z^wd|nd9jgvf&3$d5AV`w3g4QG($(P4e2CNA*nDfc?6H+w)paNU539bPar&w_tB&C< zzd7~n;)$6^XY*U|!S%i|A^7ucI|gd6&0olGD{WRc%dh1WRCe1~eaZdQ zUGUlE*NCh~_T?v^sap28gC0GM2>N>ej-g)L%mY7$epca8`dPdAd%xd2y*X4O92PW&R+@J!5(e0FB?hQG7;_+Lw3<*K z3^VtR{R|@~Lo0NZIR{`l6%1hL1^_`%XMmHAG)Xsz&qBg*o&3rhvM|I5w0aw&I6Me_ zgYQDH0&Wc4Zgw?TX+6mvwolJSCia*2dzXLoek~=VAqoYN?|qWc-RMvhA}ZMIY1npAK-O zy?42|C5MfrK(fY9gkN8U0d;hf$0pZyd_HN zS=F)B*xmR&CJMWh^fLxLf_fA<3YS*BxL+l6 z7Agx8@!vst;tI&9Apu7I^-lI%sSF`fwn-RlP*6^Us*=rdA=LD=0NyOQ1ov2@2C1qs zn+WJ6+=7<_K=()_f*q#Kxbc}Tb(GNbqum&oR6#xR8-Wbb_vW4^v*8|)k0-leXJ)uEL+@Jrcc)kcjYcoTOcT$;KHd` zWa%94fitrx@h?yl<_r)|u|s3vC{Tzh3#64}6=!5Jiw$5ZBYvQTrI3-7afXvbdJzsN zTG;VyrxLIAeJqKHcNZ6ChHvaTeDVQKs~nN(@M$01*mzXh#s&vHKhco##@e20)PjKs zj?P=~L{7zvFit*f7PZlcZIYl1@mg}UX~%dq+U@Ye7R5!rzPlO+Dm%K@^$sJM7=VUR zCnpGTl4ByJ%FIAM%WPFFep>&%cNPHYXLpnH$14T%Hm*1hh{XF3>Z%DBH;MtoWd{EV z6s+K}dyp9Hj(-WchC0=6ILBA8^+D()J$xne<3^Lh;k9;V;2bV}(;~}nPK>U*C)-*O zz^|mb<*t2GC|L1Lb8fnLJxncqGv=AWvwNB2H<}C%ncEwc>5h!W?(xmi&2jX-k1i6l zF-xo1UofM!T6o;6a6L7Q?tQBvS^1w(_|IwZ|G)|roXs%-z7u_^RnR2{`qU9a;wRjK zUjbeFYhK7WUvoxZE&EE%cT7pq5L99-C2QA+ZEPSLDQ1 zbsFLxF-)iAve){)ELk^>`QXXERS?GJVWFA91L6K=zL56Tu}a<;#uqWq2J<= z3l>`ZG(>mh>C!yAvXIOm zSObaxuVtV*;y8AI9b_dbft)8n2O1y>q+A`_9-(7VF*=>UNqZEHc*UqKki-l!dP)*|Vq%{m4%9udaPL}xR3voUG<;<1o> zdB1fAkWb6X)*U1h(=;fLOnfVw#Jr#6dqQ7oz1H6r=#QV6d~JOtLS`cJ40lO)iK2S# z)yL$#PbPP6=NC`}`(F!}5j(TX6zaDBK*9arm4Z>c7x@L`*Zz)fNNLaQ$g(O%X`31= z)ZLuWdt8(=EvQH_W;Dm0n^lv*$_#zRy1$Y&W)XxUf45f`SEPRJrGf9xM|zzooGJ6YjbR%6l1ztxzEyYJw`Rq=&^OC z{_ky(k46pEo0k_VIbxganIv2aPKnGGo0FW9GKWRUMb3t8DVU?B<{48_(jSOh0BNJF#$Wr^274Bj0y(q;x@fIJXM#!9_84>I&WR5?28 zC$g{^GE;XGqeHlL`zH&MBCi3aP4SZmUM+3Z#?*>?G7tFlY>*J{L3)b2=`C*5`}x+q3iYRYr!xbRy#DT@D)ZeXiv-4(FHb8>l^t^{G7Lheq229<6Fyf2%f&UI|s5$ z3fD_PsNaNN6R&GSZ6p7R*=Sg4O|@sb)QDCam$@sDmo!(Wqo9IXLllb@c)1tSQTL5X zWG=Wx-3q9_zCLG)Ccbexof8^f0@@wDyhMLt=#2ZmaF?G6#msI^MCpN zU;yMbxIR>^me5roBlOePtDa_T4$t#JhxlT|Nk#T`sPbqZX;e1ZVsGQEniT9Y22 z55xjuiV`CglKM}w#-STns8#YsLnL_?mz<*l!pE8LB4ii)G+B)(C|{BXe0!3hFJ!CbKwq-D8Ta!c_XovWM~-Y{qR{+nov^l zN{2K8N|RQvh5n6VE({dNk>}AJxXks(e`D=7eEYG|LBUIu+qeEo3f_SRQM)U5d03yYVXq+H_|xVW$`7DGYUvWvzXuics`@SB3sSAqI9J zMF(a0;Xd(Jo%h80Q1->(z9Fo3uSz|*AE=6~%z|GpO(xYSV5T6E)ENj}|7DkFF4oe?AL~tbW4FkGt+teFE+pwox2*7k70YP&2^D^o{ z1t0?!oK4L2(5eRxNm!}C5;hpyY8_A@24KC^IQd!PsI^~6PLVWsE8;O&A=gRM5v+aT zdFNT&r<5m&Z{r~MKM{@CH2wK}cS{-y+xd5c3Xlji=NkqCb8_}y`JVhviHIbaw)9|XrK5PuL;r^tL0wti+8jg z5iVhJOq~l`Oud&8_Ub9)btfB8)j@}_AT0&T-8av#0q;$REnG!^eVHFLq{#A>3D zYO|4k!JK~fW-u$TWviz5@O$jLdksGq*S^j@TfKRhmvJfK(c-0N+J4=P(rISnGVAAq zd;7vqc7<;=m;4h7|MeO3f7hO%{>lEqIK^A7BJ;G2Eq)Hn0E|Invf4?=t3gI-P#1R& zI0oe)(ctwEeqm!@GD8g`+8r1d1k!k@4YSO&H#KaN%Po zvWS3r|LX!?1r84*5@{%-jS~ALIV>UT7sjmpwZ1Tdgap!_D7Dd_wpDLMKco^-Yc+In z^63a1X=@Tw`ouBmX@#ZWS3Sm|8Y)iCewNi9S@7YM3gwRG9IRY@K5q`AqL0PH+sssw z8mCQJ0ytDv&Pg37!IIPKtp-DY2<}LW>%>e!y}J1uI@yAL_n$w;gsW1LO z;Uss7n-0$K)iZvNauQQ;!;uYx-ll{Y>7Nz5UcC#d&FtFI#D*#c#xWokOJ}a4q0J(F z8us3y{&pCmcaYahV#seb1zp4=s+F0E`uPoLhLcmU%MFwwO z&SaU{T2j@oJ+o=Q6#F_(_DN&?rLa&gi;VNOTDP_tY-BE7kGz)3(}(!vTinXVLbyaS zcD#h-jMAJvbm4_Z5k8XU36YR)f@7SHV?DPFVK+9KU{1PEh$89}EFr3dg)|*UT}UKB zfM|#S+H9f0P%N7!?IJY56h69Kl0g09?rkvM5fXbEGR~+d(}EG9vUL$Guq+LmK`LF^ z?jxDfjE!hf9=C9Z7&a^Nl5(PX0aA4JHnruYi-Cn!PZ9&+kmN!$aqEj!n@}BoszvG$S$&P9B zu^#3TzY}d{j0d!2Mv^*D%qa5reYjlws_Th)cZVA$`#<&=&tq|^R(W2a=@nsFJPA}X z_dHXyUhfD`W%oMCb*k{UDR1Maj?CK8V&x2Tn75tmu%KddD%1t>4c|Cs98GAm$Lj>> zc1rd_QxjcO?-XbJ<@QkeNoXuI>rxh>p&*LxE$hT6Y8@5$fk((^!TiUp6k?hj#>h5?I08G*JRT_-W-<`3-&GK0Qt=X`jG(LL>)SjM78hy!PJmXF=H8xgN~HNUccWDZDrh7@AMK(WOD_;3qB%5x@6Qbv2LXCeR!bH*k%Mq; z%ST*S$D65YX$MbSCW3mWIXRR6&1J&xHTmx@6EwTNVMVUBHQC+O}pXWra;SWz;*VwQA_A`q6K|dE@8_!2N0^IWchQj|C3jacnljX-PP%{2K?)@x;WTgNn z;YPlbe_n|I+318oYV~s`JP`*K@igFRVlIdp#;`*-bRZmlXn=))NGR}|IucxZ1dg66jSn?9R{`+J{1Z_V`fRqz3iRl+ zZSU1Z4=z+6wHr_sFRx}bcbce$WHZ$b(u`Z(Cut{bi}IWe8d|As=S@6wdF|;RDA>aG z!cKM{PGSln|A;9l$u*}juQ0ag^Gd!hAIKMZTweCU-OpMqrXnXeXdYvQ*m_MqeD#%O=K*B070Kix_xE}e1qD$oxuHB&46A%gi){Pd4yr_L7f zUdk8xwUhhgk3jxv)90*MKcd{_oNa8{Gw8+j6&|yAi>7v(HPl%zXUu&&!}9)G#@iPE ztjmETHk6BHF&0Nvg|Qmqq_(`Vz@$1h3h615hUf+(kq|ISI$jZy zXbwyf%c(~)liSII{+HUXmL@rgAhZw|D1vV;;ai-f=b9CvqS`e;qDaI5Mx}$v(IF?i z0A?J#5!58N`j~$8qS@P6Xj-|@jr@l#pd)qDm11iew3(?!F!RS{syE$6vQscEa?Ix`thxl>in(Z zyp)(HanaWUbPLQJ&A!rGsoAvs@uOUyZ1487n3INGPuuo#syN%aS;m3bQ6N#@wferO zOAKzGW}xZ2`fytO;kD}wUxU^~Z%D53bT{73>9UuKW@?x#jx3m&9r`N$B!$skeD&g5 zS>L{Ro6_5eR~Jp*uf{fA?F9SMerP{FV2CWet|L?AfnDyYUdY~)4(K)bwI(lAq47^B z{4XCP_)UTR zFo^52B`O{2UpC5u|I>K0@(H1IY0XC*t3Kaay(nl=c(I|zH0Do2;|TQ zm#Uv^N%n5uA@4w&>?XJM8C8DSIdn3zZ{F&%RR1|)Pqt0lU$-bHshMB%6gcyMzx~9G z^YUj(O@{eOP0wHHAE#_jw-kkuSEFgmi?mW_WK?n$vy9Ru4J`cSXY=lMiH}SMcfcYu z`@d4X{4AxGZJYdHy(fJB^3R9J8Ai&%>!#na9@7L0^pRstA`o4npX<^VTjR(KsUt*_ z(g+vfs*V|V_Xvy7cLZUg5+ROcNf3tw5vI_~j@qPh!fC*V;2}lG0$pmKMLY#D91Yt^ z1dGl9P-OH1Ns}JHK~tRBSj3eHIHMA1cOFhF$+eB0f zf#EO{R8U{XG0Ox#B2eyGJzS(0KhF{WeMo_p%f~%PnAes%a;a)sFrKby$k~iVnd4!= zm-U^go7b*cZy_2qLNE8B3uXm1-0$6`Eck}C^)}N`HVel?e~Q#b%3H=^G$O*R<|lcL zOgb*XNBM9^#Pp|u70Jl)frs~Ys4j?)?@DV9IkpzPu!P{Fwq`{QNBzvbVDv%~8Nqzz z5k}ANU}AsjZo>(+s&=tVUdj_LC21GO?L9E>s!Du3x1I{*4wByv`aYRuXdn4rWb2UQ z8GE_7F)&E?L%gR#Z3ps;%=5MDQZDWFovNQ7eW_{-mSPM1Mqem@q*&rwIM?@gLgW99 z3IKKSDKOf)C|oSJiyFXU&G0Qo1fYp=f|4>9dCiiBp?V}Knx)KC(ezi@L%CDCF9TEY zx&$9i`hqdV+tHlR7;8FPa^*1sEvd1G#X|}Vor^KT&=?jW-du7vaVmSCg;8$N#Zvd3 z=h*D=a`I`aHac5QrbGeZN0Nsyh`5sV?T6@xzx*niwuXx88sTZ-&gS~M;Ydhg-H0v% z4O;UlV)TMp1#fKmZi%Mey81C@T&XeTW1As4*+TWE8Vd%UNi*#Y#gseg{oKA8Ppw!# zt>pY<=HRTo^99Rbc3XbY|NnZJ^ zw@hJq(v9VWsA>W}n$-_C0gw z&OQ5=SDCevS4p0HKF{|ldr-ZIX%l?Fn#i0Ks?$!0Bc>=jsOGDR9>p>5%H^Yc%u5p8 zCcD&p~O^VelR_W9^`Z%0yo764R)2&!RNB+@_NCfVpUdX_vM>uF5RNe{);Mkft;mp@PfRX` zRLp<&kvT(jig}ehIM>qvZ8P%&D5_!cvllM}x+)0YJE@ zXBJ7q(gDG0&eFWIuJ9uOX!9jJi)dAhhjhGpVK#hjFR^qS>I zOzGKHi`#SP>8|@tv~Jb4FFsip9D{80cRnmU%E-QSw0(YT(_+`mXTMb|$?~Dqfz@oa z%~+SYoHMEQZl<14#eA%gT;alZTXLLUnX-KZhT;0M|555aOeos_oXqsp6 z?5yN9l|MOeUfq37mTLXCLE%66b^I5)1@iY;fK>@Xx*FG(6&WdZV3@u&C zmzulB(1rIH(obSOSqO^Q?Ok9k?N^4_&?ta74Wy^32?Gyk0-S^~_hwqD{PAKXM%bs$ zep9q4%cu^J+yE(v8!AOl+T;?KOM;dkpoKcOB8~ zP*-*ISVgr$!t=7Zcf0+AiE-l5k5|Rvw{r&@yNtcj-M^i&#P){serXD36-B2I7%oib zzhYZ2P^g z!^P<72?`LS9(SJHUJ&X8v+6EhyWiyQ<4$OBZsgYaZ?TDUO~|nl0+}fvBoWdFTtR%U16ny0psRy zvVPLxe)^qB9!g~n=EcPzz$9f|cgm~HQ?^XhyQCbb_p@yv6?4}KBd@aM#sViu! zxq&OW@+B=v4&i)X^1ICuJo#>0i3JZznhHqBOPr0{FcbHBS82s};a8h!2|>meyzx7_ zye;IBzU?o85-f6~{w)nroJCOx(yQ-3-s?T>P{@Y7d=?g=>smZ;rCo6EL9T^s?oXg0 zyyBsZm6q*qf|_-TpIU3y^-@&QGSgVwcz?Lt3V(o``uJygq%$NVJ&*5MjD zA48T)K31-&c>kka`hT`_{4d@G9*gw^*^TXRv}kpZ5!w&JfHja2&kgd%8i1n~GGI`w zIGshvq+2ZGz$3Japk3T8Fp8E0G6UQS)FHqJN>ahP^9r6j{ynx3e>q^o)+y6Hi+`0C z*K=W&faZl1J)vwH_VWToer`sPEGv5fbQeo~ofG^?O&B&+hvEoI|6&?%`i3RGz%Z9h zmdJ30T$v-g>RaetxSh!z!pC;*WzT5JCo`6gu!0c5a1zhx{R_2!Cj}SE2UR9IrGT>x z`wI$N@1G=DXyHai*a&Hj->!%I2KgonC*AsJSrZ!e-DWYPE51 zQBt|$>Fu}o%-jOk!^g-gE`un(ZL5vJzR)}IriwY?wv2oFbz<+jt_{15dPffv zujmVxM*T+qJd-wjp{C*8b25|_Lhe^MRrl=u@O3GSbnI0mj^qF>Al*Z1B)@XdcpZO= zG_aCilPM*x)=Jh^R)ukh0HL)APa-OEmlw?fI-MaZRt94^zoY>oNuqj6!ycy5y>%$f zg7eU}zO+aIsfae|Y19{&$bj9X%HRl^OO?lNfoNxef%;Txef%fBkG>Q!4;!X@aEMQ_u*_*-J%g28LL~WT?JD9=<$>H z7L%V`x|SvvJ)fS?5D8;`Ds^?4B)Ro+hJ(>Nd>V8RUVE(JO_&afk-N#+EOe}+-f!UG zT7>es6?CM?_t2oNY>kHX{`p2Nl@ zPdZOs+OI~laFtFRyUm=VCVum$e~$P|Z1ToheQ=-aVKf-OACe!QBOsJWci=dS+G!sd zxRPg;#ZwnDbBg=iflms=F(-1WMda9?tkMffZsVtaLE$`QJLX@MLj1CRDP7R`sjwa* zXc6}~zA0k2#i7>9qVCUG21u7h|5wyPEmD7#IS+#3AP9jB%ETbvvG|}#NSDlICiN*= zu^hms!G$-(`!g$xma5A^iJzYQi9ra2xi{l`HhfAe{z#?Xl1_1|;-H{m)E#Mmq7*Ar zLim=YiiJ!#L0-;+VLh|DM{Mllq)Bg|zEG2k$sZ)#lBiFfp_l=w>f@MH6|H4yL7wvf zweABkb)*D@Y@VA`Jr$tL&2Kg3;V65Ap}71xGVyuGc}<#0uK1)`+yVy!VZyc6gBGUI zxCfS+cC1Z_S2*fk?UpQGatY{%AP4rY$xxbh^4?r-H2H;~$Fm9yX2;!~c`t9D0ehn_ zUn+#C?h>nwTi=^@wOBdnmi*Fqv?Xme`uRBwV+g0pTEHn;rzJCA9i{u?ZFd{mI&YZe zX}H)9YdMVw9|%!?!@Fk%*k0*n$c#9rX=lCZI!d|s@FM(Ai!R~y*gv4~??3^xrYEcP z=)35;W{4}w<4fq8#1o()%?>;f%Yz#m76kv0&Vd*R6a;&m!J|MA=rM2yyg|ATve6Vk z3>QB#LCX-?ziT5j=J>!4gG)SmB6isnYYxRCQdo&ti2L(q+9$WEYycEH%^KS3lbC2k za}zE3#*`SblM2Y9Jc)PZ1hwyu#`WxJ)5{CUeU|+S1{4Z)`aDJk_27xrw>K4dL`Qgw z{@}NBpMq^h#!VA$S^e}Qm9=gKlCRd~hMItpN8(c^joDeaKFPnPqw-w}5!+NiTzS{sRJwZboCh3U2D zQdH~r-7zCD>-s&H2ZRrwmJXW+DePYP)zSg28th)`OrgbWdn_Bluz_C$mh@Yh_AzcX|fHhDUOvseI2(B zFU1nP_|PK1Dth8NsFrRdyVXY6RevRE;)BDo%a`RB?LH`TeVy(&?sPoJ!RvBdm`RN; z*GIdvwU;tn@9gq&$?T`4zizS8QBi*#u3^;v4=DT#6hN6+PVmt{o*u2+ThX+S1Ej?2 zg4#Vt!6W2c&^sFh74`Q(QNRJTC1rrxv|#W)EE2~{^P*p4Zs2~Lt^m*mw>1)Fl7c$3!keL{SHolYnKK!$J)ZW4azyx|eLf|%(nOMO zK6;U6ZUn8U&ZQ@dE0Zhz1J$@7#wJBU*=}dbTQ<1Y!eN}GuHp0UJ+_t1Qh8!9UXPS7 zt5*{ZrMGR}aLpQCmo_nfLE$p&Q#a~2`_~}W#=k^k05;m8bepd1l?ojb*~I zpPhkMH(zy&)AEiKfl$P3W#>`Hm}jV4+|+NMzeo!Px4k|kEbb(BidKJ(@sElRlGYr(lp5Or_{neG;Pi?HZ`Nyi5GN z&xS~1BOul^=A!S0n+Uk$aI=GAy~k|pIgta-gx_R6xWJ3JZ8MG)`P8^lHWqyIp&#b* zPi5a5R(*pU;JlQTIq2{>yy!jL-B;p_Xq=m}dQ2Yk;-4)8^<`g7hhp!?&_&{E zYO*KI;{q0|<_}F!AD2_=+*2>j7`VM?AF*>Uu#1Y-yQt!^DRxb2vrKm^@N@cvWLQY# zivxe-{`r>@uIW;i0fgnMJ6Fxl(PJFub!2}LtT&8W?%FmEjT2NeF@r0{=o0Tj_E(oH(PO4VH~pu53yx<3;hcU ze`N}cbnTL_arj?O!F#vnM^1Q8FVD{Rz)bN{SD}X!lJYI%-QvbMMGp>OaXZt4%W-@H z3-@Gr5_kd_NN=w#oMWz0x7~)B3p#05)VY8EA>j3^U}1UmlFZtRZfi)s~(*=LW? zX~tcr8@5jjSCGLDrP$qV&TxNV-5dr)wQ4iktuS6F`JnPfD8NO4B|x zK2{b*&{oqXVVxDf>UrqLDh*9!-FPyqanGcWrd}D0Q8tT#R~i`fP`~Yov*+8%@yD@w z8l}uEL+pt}(UZ36d1l`>x1!0rc3hvEhc*&6aE%I$6*u`mv;>Ze9S=U(cQ$D|*Lgj~ zM9@aqVL;02i}lV?P|jB`oo}Sdz1i;Cc^m& z#rKU9`-a}Ub_1a(fIEuL(p8G3SMULR9B21z}b+eKoflwJvKZCEQEVrcs{Hw&S;1% z69;v8DFE1x^RV9+$*coqpoRb%f(DpK{&%Uz$smTw&dh=U@A;;|_kthNhj$~QF$prH z5^)H7OhWupT6LO6^`gh*t(J*hluObd4Wv4~4d!_?B(TbM9*G&@1xy>el>m$YHdj1- zZ$(aiUrxe6By)tZO=~CtT5@T((6ZTI{PxY!O2x3^t}gxbScQ6i`xz`QeAC=>#l2^_ zF6c<0c z2i`+pFK4L6Ozh=;G`gR9M_u~l%ZI`4>Y?fHOh+H-EHzqAm>o_v60DXx>I16suZes! z;S-4WyA+a|vivNY_M_-w_N@^|V+tisaMb0@o6r8BALI!*K47YQS&gcQ?;QoN#j1fI zy?lekKn3TUkpe!^?*mnPV4x!H2M8ktgB27_@DGg$@&jBT9FLSCxezhPtHc?gmKoqV zC;JyHqC-1IQbAxJ8=ETYpt5Pij4*o<2+oOr@uBs`;FWAl{T6~aUuw0~OiXW?>=B@V znEx%?GRjN-H{1Xw=rSfEC7j+06Y1Z&A0}m9v#{{Poe11z2puRZi)BiNv!PyGF-O(% z(@iNQy3y{QcdZIq=ChXGXO;GFOk(;~4fpPi=iKfwn^YgOYe+fL!NaFM|2$@5q>kV7 zY2)j>!U_W6Y`yml<4+f3VaJz-4;{EF*u58IjvXI4SzKDSWaN`|-ov-#cxjH>^6T9E zDWUgwcwKX~pI;E2HEUo?V>_99>3x}7ihcQ)*4$txf(lip!Q=F|Gwp@Sb7UE>%s=-| zM;<&rGQRhY(ty8jJ@+Hyx1gJvNa4r@vpBW1JmwEma~)xqLemr)Up@GCUsvnIKRSi~ zU@ib1dziri=vmzhb6JYYbOke+mI~s5G*Fvf1LK2w1P;&+K?to5)Qsf^1!*(%5qT9v z;NNlpSJl}u%zV`6KE*$|6l1pVJxYYNUE~A5M^I$yabebvOolKoVTCYKUqKnXSxVS@ zg7{vOSA`d$Bb{9UxDM>xu)J`~ufl3!STH8YuLxwR8u7=T#eT#!$TZhg|Mwo4xjR;5 z{H2*P>x(ymXI=YY^)TJre~#QRiGCz$X*vFvX#9vnSD%d7iQ_JLwTA7s9&33|;U?>h{G(aW7%&4L>s#oSr1L1^@I7E0U<8`sH9#9usUnx*Z=57) zlg=%Af!;2XVpjTX>;delX8{5hKnWrUaTX>^WUR*U83dxvmpyi%lMQM@wr3#N`x*nG zy6tEyB5}y?(-AfXzDqD>R^j#-CyN7wpcTB_&kx81Ms``EH|`_H-MN?FUXOB^GZB0G zM5@MyT%jw}Bq4!^KpxvtlaS97Q|{Z&*$ESfh4w`Y(l~>y^B$V+>md$1N9|$Krh>K` zq}titrp8t*N=ji`J~v-LuU&eWlz}yC>0(PeVj$r*M7@pE|7|3%5#{N<8SrvL$>PO+ zi)?p!CGFbTdSxf3;WL(KKi-4UBjB`dxq_4 zL!WaOzAxdZ5zDSSDOrD;VEEI_o;m&O)NwT5TFP=c!+BYBwvF+A)=gdc6H>l!8pGf6 z)Y%Iy3^Y=IeI48`d`w(A|8U&wV%2}m^#N3*H#&90ZS>fK3>1~g9$+l(7id6leo;0s z1K*O7MSTB`f_i@-2~zK}Z6Y9C zA^D}~eU(Wqxp#{Ak=ifTyL#hvZ^KMyxGTXlwCtqhqoY!tC(t!QaApg+%9O@Z(*h?) z1v1qz5)(NHx%JS8NE{8Zo9~U|J(zQI`_n46yFECbo+&rLj6zAK1@I0_6!kDEd14bR?A>g z_KDXIm*VKXo*V9PQyhq(SHMtA1hvK7tv#M%1!+$Cfns=fC0mEo!?80 z$_o*faYc8o+mRg-5mK;Gv?yyNs}X4^=oJXEsvvo#7=^#Yh%uxVh}pZia>fu)vhSm` zS^b1wK?lSy_9Zk@HK!VCGew*8HiFGVoh#BCMi4e};Rzdx7ZKwf{)Z`VXHm(E*8`9a zEBPFM2L&g}hgVGW!w0i5&7M;IKY`Io=(NJUtIljfsa(&$H#hf+Omz{R!6&s1e)Zys zY5||7j+{PzXUNM;eEau%@YuPiK)k{$?t)VOz41#t*PRNrE-*oq6&zOKB5L(Ns*PA4 zeDolFt=n=mO}AO`m$(#upc($U%eeFA-grhz(B6wdbCr{Au9pQ^5AWZu&~U#ROAfd2 zoi%y;aE$b&|N8PNT}AC>buFn^mQLf91rO0T2fGIJ7WlT+zK@>mUiL)%F3KlI5{cw* zM0=Ja9!>}5#72feVu|n|9MB{h$VoC|s)?%N)y&K0?uEcQss~LpZ|@gz7K0pcV*m<} z!wW9KGHqbe^_Ng=(pYAdNfIN21ne>b2e_+NRe9*?Hnco}Z(chdIFLRKU zDazx81#h>9(@wj(Ja^zae&;><^{9W)ur7tMs@$PqaWZMe@QYnhrxsbk`yeV-;7WX4dWeaLK<4S-bkA|vh@kC{6+IMB}=be;F}g+E9Fd4 zG@wpVHT=rE;q+^JDG!-T>9svsf^^Nv@k+~C@|eM$Lq&wa9^xot{S zsPP!LEF9BeiKBMsai<|t^zPU@!g7Xs`PvW)m-|b;uGuvCrEZ*pYJR)+aFEc4$)Kvu z_QluP34cL>-Y$#yD`+$ul-IvSPgAH3;9nfAhwLoADnjn2EPd-i&;96pZxgflDk^g) z{+y%jwrlY%)q}PdHxFzhzRTP$avkvuiVa)3F;`{I=F~ReF|Ku@Jui23UDo=BNObpJ zkU`{b?{4ZRtDQIK4<505slMVKH=54S*8?5nLB}&p>y~}Chsqcg>> zf%mCM(z>E2jl=btI1ZQ%mY5$zNu0~xTt=^#$qf40*gCgn?M5O?#oE-&^s_=D^5&Lz zKXT{ajK{JIX2*~XIz%HQ%dr6mm5!4p>}6S&oD4=ydYAHR&x&@MlZ3a_o*L1n-RZ`Y z<;BYvWsH+g$%Q1H+euw(ue(~po?F@Y%lVaM&-g=_N8_EFD83!LH;cD21%7qUZqB%T zbBXh6iCOx?^K4e(%0E2g|KJ%xmsmq^u+LQ2T@0$I+|vP)NKZgb+C5M@_6OKK{vGs& zoCP^(0-z491mvP`6z&NOAQj&SqDUYp#{=Ry73E%Pb919u{`SC#JXXs@dyCQB6G+Hd z94?R~47|Vzj&gFP`3d*Ij6HqUnv_ZA0`RkSfdU={H9Ylb7@8z`ly7-iekkfC5gEh4 zVb!E`3cS~6+BaLP?-}wYKoV=i;V?7>_K>#tmuLJ4Mn)JY?#)kX;A;mquI8+)Hs6X!jFN@T2XOyBr|xbCV-q$L8lRZB zzc;UC0IFOPE9HU64eEQ}P&pTgk*cs8JbjmWTd62`V{J%uNm2fF`a(vdPNT<+LxZE2 z7V%~6HHqP44`E)7`L`bn1T@`Jn>wYSK-1`HdRP}!cjFv#tJ7ls1y_^e=;l1FM~z+t zg9YF}EfEifF@RK~s6D(EP+|~g@DzD(Y{>b7feV_-!zIeMf8<0TeU(`q@WhZNXy4RD zaF1?kRO-SQ8tVOM18#4ykO1E0ULtpIh10yPf}s>L#qACLA&5!zepH?hv=esqdgCgSnxG4>4UY#7og zL=A1Y&o6ahEvQO5mFgYuhw4vxxvfbWMOO)|WxA21bhVG0m57VP4P^i5nAj~q4Cshi z2$-Zi+3;Q+ve6!BV#f@w>xrx+9d=D~0s(dlj&{F{v@DWSa-rMy8$StrU4;$rqmRo> z3v*yuzQ_@7kjF0lK0~N~<|qss^e}XY<8`$&jCFvXE-spoJ@st4ckOj>-^@%W?u2^t zQk~dl_?HCB_MkgX((eAIikWt5Qe4fitSwH~kUnL!eAGYc9pdxZdr-^!L)(Ck_lLgV zs}a0>|Ev%HeN+Hd=^}*IJ_%iEk>iSd`aR%f(mgt(&<5(oj^NIZmV)DuLhyL3480lh zF33kK1y~n}EU}GJkR&A56h(D?Qg~GcBLrzwe$XT4=0=lW3Cw-at515hoNEf&`H6#a zVM;%#5XiZ#%c!_AL$l~%kW9EDf3}FWVo~{H;7H8Z$IQixBCO26tkj9@B86{wU*L1B z1Ex%jU7(NePbt%DU>f39ZqLQ^%(>FAs3v*8|2ZyznOywTIM5I1*|dFG<kK+k%#joJ51u(db7Oo~m^^5UP@?R!@`Wm5y zE6!_pnR@Xw5JCC zmR1SdmEw?2*1f0^pU9F#a)GswRT-C&{C&)KmBiR-@IJ^}AOdIx!~id78{llzhD$Jn zkaE{UM+MkS<~WF0dbjiwrt+@`S&OXA8s;Y~q)DGucn z%||F3=LjwCYE$vso*$@Xkq28R$W^CZ0$jp>m!IZI%QJg?&-`L&ucQ zKY)Ap$In>jMNYjnzvCQuH1(+Bt^K>{*6a7S`z{FRs6>y|N(TqMX)}1)C7-j}jU)Zo z(#mw?{3l}Ne_9{@(@#OPzB#Bna9VXmJpx=en5IX!9?Fo$(M+Gxm07-D?}crUW|%Ok zoH;-(JcmKtW*-S6r+~W-BLOh5U-_p6lA#dV z5T8)NkDPp=LJ!*Yy%%Z3*n9jbA^wOvNB>oGJd^WXg{f8wbMK0Kx9dGW8lLx;$e0Op zUg+;hq%osR19t4Ir}f9a;TU3eix7zqGukhYBF^dbGV!=g; z(>l3_LA`b!->{JlS$w2xbM*39NhQNZnyzdS^O;FjNK3qMWy;!R*|L}26%S~) z=h;WLrM|dSy+C&coBj5;{dpsTb?Qy=@c9dNY^_fZYCd-;_Bw8T;fp(Z)1;>B#3M!2 z@~A}6Hm)eTJ=pA6OXzO)PH@J|DuKE5>?j-;m>R8zKtV_kQ-NijQ79ULLSUUzRa<|e zgo#$EjHF{I6j3Y{X@ec*711Ufosb|vmk}@k#shHEoEgR85{9a|kJpi5!1ww!MQ6x$ zqjz;MZp7;(q`GqC1add+wzfW=|2`s)<}5H!ae`kYLIzq=ZHP}|@R$*(i+wJ|9Oioq zLdhg*=9jO?aewOF%DjQLxB69()t4^jKEB?{R&_Sn)a}7LgWsxah*^|i#Ero;6OGw5 zuM|)UiDn{Fif#(Nj<*&eY8x&hsuOg+=paXR`lG(Vle#%m zj9cBf!aDPwndjkI7Bcp7a8z^YUr-2yZEpSr1z!_*&)-R**>SY)HUsVTt(N412J66s z0~1}B)r<}l;mM`%&Vb1#At}SMtyJf3zx@f^G zA|-= zm#oq&@Ayn0CB1EL7hxGU*T*jrLVcZX3JtTllVt(3}wHXTjsDIgF+O$eynlcPYU zKLH@>qJXUFR3KD`5wDMiAt0n`J;DihMxqEm(m{ykJF!4Iugv1?p2_AeDtZpPOe8|< zN1TYw4naV&kf^j8HS{RDIJpLKS=)zHJnD6Rn4u~>$ zVRc-eQlMyh=9Ic5XM()PzNuqn?VIb~+0D((J`MU=k9&cA8 zttCH=`Yji@I|^B$f;Ed}D^(U`@&~R3iDQzG@+VOAr}C|OFWQN0ag|ygBO}(6`?P+N z&qilxFHqC;^mcZN!$^AfUr@M6*{(+Yq=Q2IkAH!}y)%`pvLB!N6BZk?wIckI7^!HK3Z7W%Fs4o zkM*hLHCz6-R2h6Q)fd}&v=+(1FJ0<@F(ye;#ffqlNqjE#OXVUpk)%Oo1ybnZu6r0X z&6leD21&KWdr^^C0SuZYHLmYgOI-Oq45y!rlk^eHEJqc7SDcNTgv_cktfQAr7nEXq zI4)0fN(u2a#7_{BP=Bdh`Y7fdMY0sTq76c8Inw*k&6oG4KrWg4GO6qlY_f~aAjW$+5fazW3GPjah!6ZvZ1|9s_{_;Bm< z(55wwt)Lorsk@(QUW#@2+txR7J(M-MpqBlyr8ZYoLJh9_CZ*H>c=npPo=2M8)9zV$(q_5{(x& zIutCSJOE?59LgO5iR8D3ZXxZFSXU(`IgTkPoWUL<4zUM@5Qe}Dwchr{p54!-_F$<2 zj#*dnZamIN0>a=UNvS>}Ws;GzE=wsTvg#)yxvZ|!b9GKQ07wXV$^_a^^hK)D{V!uk zpvR+L)nKOps)X@kI@TveM2N7t!(oKnTKahu3i&n$2?4}nB-L_QGUY@uc8p1ouuBp) ze*K^&Y<1T_k(vsa%4(n{qA&U%tj`GbPM}L+TW<-pT@r}ADvjN}=Mc|1vOOndf!{L` z{xsp%%_i|7jvmt_cP=amDuk-pcnF~eBe(+t6)A`l64`TR9f1X>^={^Of7 zw6?V(DU-C-ddjt~Bb~!^JP7R!OFr>o5tkl#`K5mv+8z=KH7gML9oFV|ddspRMs16s7>>L)1^6-z4_Kfj7Q-6M(uAJ=Pov z7$5`7^jp8HPA450IBDAZB^yK{mpWL+s; z%&sGjWObm(OWT>oj-6O?oFvtpmudj5>J}DAN+N0LfQj4)Km1P#Y;ZclR?y2a!}Zm|QfGrAsI3M0kW;$jN3bFvz-FUQab3q7`MZ;8$q(!1E%If3U7bf1Uf!WCa|FQf z6QQbNfIX&@gqNZ+FaR6nh4kZ97(VPW%d1iJFJmHi`MHsg5n@X3xCt``DHyBMk1upx zP}qF+?!c4v&)-L-Mht-wGSAtbUzUtP0&>hJ^PBidG_s+T6p~#&5q~7}*58*YU-$Xh z)xawR0W8c^Pnnz7SoA+FA7RP$JpXT?@Sh&3|37*IXilEPnI(4OzQ*3x&CgxOwGOO; zcl2SPUn~d6*s}sgkc_|!aA8H&_+n5O9}Xh*(w4 zCb0$MS0VJ$IMp+mB#4=$Mi=R zUwrI;cP<+%1}E@&!oR6;F^3LDtR!SjomMi(Mf0>Vp*z4=s){X-!DZu$dgC3O4GRUe z8wKt`0Z@X<1!%-GWed#2Z&0Gms3&4UDY#=Th9!YV(%G{V)<;7aF+te~AR27uo{Mg) zW+cc!SSYCoMgvY;{#wn_p6+n%P%mDzj>g;~Q64s#!;q6}6X!Fa5e}4o9`_Tai9wNL zyWCfg-fiAPV|sHg6j&L!puyc4rmv(cx>?@SQm&;@8Uz z#1gXe8x8%K1Ux(TZ*2HKF)52h9{JhgBHa&!txoMt;O>iapqYVZV=B%R7&xm>o*&+9 zqJK-&e?2){e0P@CUwuLDRy&Xff%K~7w4Mw%F+d8i(d>RI-In4u?ks8YzXvj-J@j%r zBM^+x2kjcc3tL32plQv+T+ZhSlzUr!MSuWc3SDQo9G#^xCSN;mN)RSwYUYRs2UF;l*BdNasdbX%b*0tX2XWIY& zK;eIbMW8<9CaBkUh;w3eC?5%?|eQh$t6X#W-PBCQZ) zgRJnvGNpivBq5+BHU`F@wg=saUAyR@pnt;|FTvm7C2Y#V4)t#)0&HGrlsYFhK8kwv zSUga{Pf~&bq03SRK81%2w@JUdw702|KCu8oQUs&$S*h1w;u1Sw2dTTfv!M+q&Y7Ii@D& z+;RF5E%#1N>Hg(99ZS&naB2IYlHp8w#0@voE~&CAMZ~kbIefi>;a@@H4cNXS6C3+i z>v3Cs5&Dtj%A9A|FOHku&0qWGMyWJZy`xi=3hq?Y4UIeLP0i#nC8owG1Cgb(H$FWT zt(_K~Xc*m8O-kYsdHdV$F01XSr>EPzIxHTIUwLC=jv%w9~c@`>Eo^@LV!;oK&ER65WTi`BT)h2nLa z;(QyzVBD1RC~(z$Fuh~@DRf!CAiYX8W&^3AJZjgQuHKCiXS2E@e7U-G!t5S?>&sqk zQ>mfxlKfZL8*%Xr<)pTN?jQ_SX7Qcs=R8OsbK%jj^J3mM9-=3mcn;IWap-dcO+V7L zk=4_>N>7)|I+DL_=I^&6Fwu9uZq_Ge!Wu*}LWcAO*T=3E=4B&j@?XP8Q2flP_{VZ@ zOWUn04iX*@#5%_Zc^U>rYb4Db%1maJQaN7+yE#Rw4&ErLFf*#pw0E3VA7ZY5`dR1y z4omIN~plCu6XPOG1c8?ik`6)Jff`$TB9b|O<`M31GFhbYL;i-e@gmq|of{wpQR4PCU z90KVe@K6D|!c;rXlp`8op!F#^0Uejnjs@sKKwU{@a_u}fAF5ns6b{6SU^Cf;&eA2f z5blR3Tcn5vwF**!St#!PDF#nw1Ck>5v2|+6rCd++}9m9th7?WMaK>E*nijWWIMRSqPV4^i>J%3Y%clvBg|9dx(x_ zWiWsHeS!Q0IzXDw?LLQzlz}F<-0b_h>Isz%5PsE`#mynxz4t7)joTsE?nC%I!?KZR zjv~v=IU?%5%@sE=n$dud;#7Sj*zOjy^2aOmIs$QkNOU8I`#L1XT$|G9@brOUi63GE z=uHomMCOEM;!5lTA}8|$k4LCiL?y@;17g+y+MEb&mb&cGS$?h5&8zgAH(rwsUf}N_ zt0dR1bq``m&2-?z{bWEeCOF+6Bryy^DUzbF_zgTdPD(hETyF4*R2@PUVlCM7CIjzu z=>$eR0VYtu63$*k)Q2jDLX>mx3do)1@X@&zA)hEX) zc2mNWP1)|nF{O{sZZsWRi~OS6=(a{KUkhyx&;R)4M_hE|^32KB*292McgKCv=r=C| z9|3Sk!kzgMr&na^gYO65+K=O^g=;3IohGA5BzzuN|GANgn?Wb0;?w0?APF`y*D}b8 zRlV`$;)5b7hZO0yRFhx)99`V^b8l1-SFIe!+_H~FL{O{K16D&gn0@vXLV}af7sg+H z5yY@P_^@re4}Lav&qJk7*gj0QgCKDmF}&zG6cQq2meWS^F zB&y1=%os%&B-(l<)tas4jlz+HVKse#%QspdyE)8^7}VmB$r9m75VFEy(PK2#pxg~1 z>Ia6BCz3RoT2rkhpEFHY6{Am8Y;CUPLWu)etffy*{WtR7E2zoF{T6*w2_ZmeAyh+^ z?i&b56B3$~0HGIKsM170K@ij=R557i0b4*ox*(_^mV_=v0YMQPh+sugu(uPxvuFN$ z_UxJezBm{A`<=^VGPy~z@;qy;XRRxc(vJOS-u=9GJBw9m-Qgd^DZaFlzNtUU9+KXp znX6m8ng*Y-J#4L`mgsn(Y(Y?Ty#Hpq%3J4RdS1%(I!9T&I3#zdY%ak5>()!&8L6kg zi6nH9Mc=2b^%*$X86W*McDR`Nl6~ON$HQNqUsbfesqpW!DS%`F7bIq`nB){FS!;ZCB!c$OK@Uhbs7=WNOJSCvg|N?w z0Su807y>X8umurMis;>UxA$f zrAr2>a1y~yVt5RPq!Pv000hBMo8XLm#SatOgP!E$7Z_EAr;jEw2v)RC2{D!VdFo7? zbCe!ltnyTgg8&}FfxM&}>d}ry`^pfs2RM1|-OuQ)aGdzy@fsrSmj3+NWl`A>mQta? z*_>gRGPU5ag|d6}`HUY~q0U6y)wfW$%IDDoiSBn zS30PCy<^~;F{VfV5^vm;lu1W?h?V@Kja{a@nFQaA2js8{;)ADIRe438;^yh6eo^mf zQOA{Bt>0Ni!t?w4%*8ALWB-7y2gl2nHSpuHzh(b|!g<*GK~dqP;CZ`|5<(Gf4{!Qi zG%Pu{HiPFDhaL`%qE$*oy*sV&ex=#udM&N)Yw?*(q9sQEBj_ww?7QT$AF4^rdD?W4 zcIQ@hi;HATLZjTT?J0@33tgpuA3l6j$IF7M@(YOLk05>dMC{Aq4;0$a_Ag{Ip_^fe zSztUzxa3O9t1)Ac3(VW5QrYh;b(t|J2y+Y}#Y%zjgp?qF7l{N?Pv=MlLY8I4wUaZ2 zrfhA10SSZmpQTRE3-1oYIiN931)4W#yv-@_C=w3UHiy`O1Z5}}gRAiV%7X8Qn3m6p zBazy>>v#b2Jb+Jq=8Guw433gT<0Yu@d&i!MrdUl(B$7}=YFbQbRAG{6W%w>d=|fcQ z?Xqt#xb~gb(hJ{>VM6bO7Ya%^(8>{X7i&q!y{*@s7oFF1zN|BYv0eR_@;TCdpH(NU zsi({I!|+K?m##_JCU3u2A@d0fq@TC~&kmj) zN#J>WdNgpP!dDOID64fmg6h`MNZj}8+37}SWE*YiYL?%B&ZHnrVWxsAeXl@!X*WwV zb2p+!W*O*4aRXHtTR};L0w@De!C1jQla*c%Fo}!=RapMQ!v>Nf;A;T9VoEE894kYF zuxh`RRJAktfh4Fb*st2nV2*f70gLLqmritoLnIXw&7;w|1eEwzXlEm605`?v6Cc^& zfZ+XB(pnfytB07!lg&xw0j*vZrNq%C31u&DtTWCQL%54ziX%$Q+7^5z2`YodE{E*u z(X)zyj7um99P3A!{TozB*DPN7@`o;UP!ISZ?e|H;fuZp-#dLLtIyresf*Y84#T|a{ zsm}+6p-H!Wo)3=onnuLnPwh(%%RWj|-O}zcOTB2iVs-CmQ;57~+;7N8gf2Tez-}+b zH?@(Z?DDArxph->bxw=TdHtQ(VrkU7h~2*b6iHTQt{oKl2NWU&Rg^yosXpT;z9A10 z^Cj-_B*tSH#0=3J=@FiMM!fP>i=J%qs}{mL+1X3gZSJlE>H8Pxt}7pJs(h~%eo}Ynw-N(JBWpJu0aePsjHGdvM z82aso{WD(8d010T&42^_Z>6cPj?wrWdn#E0Gbh@D*$m6-t8r$#Gf4bt01YYW{Rxb> zJFE)Wo5lb#p9UEwqe_gZauON+HR4l~ZoSonmtBBU+~JBzc#Zuci2+x;HBWF}Fgs_5 zcwp`QsK#g$DemnxiTw!zO8vyD@=JnR2%ZDxVaM+AM`Ul+W|@YFH`5x$m5IeP&19+l z&IJCLW{7q;e}Mk|AfhNlw%Hqb+Yd)}R>-;#-A4_EKUb`BW3R_BP;A^&z8v4A&iFz=cdHx*E-*F$rziW zm3t&m9D^o*rEuh|QdAZB?;}6OG3+G*es4R9#~?dGwr9qUV$i7F?KeCg$Japt(yyIw zlfNj+SUoI?XK*AIC|^EY@vG^+|7>wt$=G_ac?MS%5Va`Sgyw1tn;7`pbBmj90K))`G3GqzAC`rC!!7d zW#F{IN$Mb=CVQ9Tn@(&@G<~b!Jv42H<_a|=dl|_p6FIw!zl9KDHX`h-<$xiqhY~rl zQFsYFH(9r5G{IS#4xu*>GaI&ZGCh9P(Eu!!gAic`h_1Bx0YfnF%zO7EYWmb8)dL@dCzw_`0nr@#D_D#bNUaT!U-?+PTW%?U*>&4lCv7d7eq{_1eP4&|Io4%A@bl{>Ni#OLC-G@E9 zye+<=$zpG*)@!{5&y-f_OLD1d{(FVD&@6BhV~@!hcB3u9PlQ+?@E88jwh2$t5<$;? zEznaKfam3KgZO@cA`HbVGfuoC9mJMEIN2}4{+I-K^0K~0@6bk+Ft#Tf=Wj9Zmr{h_ z^Xgf0aEv5WFxKF3kIqAd(v0b#_RezvdC{zht^@8Wf35FC*RczEt$JFb;~ubq2DTRt zQnCP9h%D^t(MUR6gyZDke2@3qn^wrWXsm?0$Dc3&aCs2awE?JXk)JG*Z-$`6v1}$W47n+MPFm#*2I&hQ1HBM<6EoVbiy3k20u1EWAu_Idww}D-&wlW-pB&4$Kkcb) zYP4)!XLtEcy7fyHZPoF(Z8v9B!y6CY3yA0IHhznldGt6N+NZnntP+Ek8uk^ld;&#-mSiz> zDLT`!G2PUVReyizrKoFk0h!-hTZo?3pGS$S!^soLahghO#G8xR*+tShV&XADa69!{ z8kH=4f_Ndqf`EDCL*N^C!5wQa?p(0GN41w8$jp7WXP!~${9qqr$wX_ZOv~k&@3i#H zj}j|7BbO?z_2$}cKH}VyP4q{?H1G{&85^(hren0P`+K!h zdCsjii^t-_zrNSOFpADIqA?6%Eb?_Tgo-l!mzxhp$1zhv^`o`E_TW{s@W=5Ino(ktK@yfGgy;= zIpKFn>al2KSiHxVgTWZ!ykFaOZyN&_^OfHuefW;~MRn=duC0pc-sgUMp!=MBe1 z+8QxXGK5Kni3*$bg5WV>bf{uPbbS~nh3<^q!KqJ*BC>3wb0MOwC>Z+`KoNwT+$(5+ zFj)(tc~xpm`cV)?maYi=!}S+4$^Gpm1IFp2n_iOdHsia3Sukmj*PI(_3=KPjZWvX| z`3KE~UE$b8@ufOQcuFt(89>BDF2LmVw4W77$qX!_Zbxvch3)d-N?+8oki7-chI)Ds z*U8x-Z~8i!+5Sotat`er8GukKl*_%sH(c+-6_>dDhiqTfm$(ofHu5*Ft&ov0v&G=+V#Fe z@b+SrKf5`@`U+L;b1B~07<-AyA4%HifR9_gJgEusIfmbU#xG*xL5s_8R~=|0$@bqF zrvS=Rcz4k}6dXiN`*O(GrQHFH+;+lq1Xjo=^5IhlE7 z9CRPRkpeFg&c&$BfL3CQFb+`@aD2AN%@QH#HkCs_Wd|xauiOjwiTrarOJ7=qbv6f% z$O70<15=UN5_C?>K@D+yszXR{FY$8ggKSp44IL`gCQIk3`BEP}7b=m@i<7gEd9S@T zC8MkS6TBE1?T7NR_cmnSrfW&NmXAF4Eh9?nMAdrMN9q-keI7=zJ<8Ac9$((5;abx0 zyu4q`O!-pQ{W~dqvR$^me{=D@uwDi$%=db*ar0v;auZ5o)L_BTmjLNAejntnd`(X~ zRsQ6|Y~KlRRoiM8*Nk*RRd@4T*J#}aX|+E0mXx<8cH&Ou2k(C>M8Mqjw%*@YD9ztd zG1zTTeP|4diuaMXqTU(E`U?uRu(f4zl#pl~Z28+RyYh-!Hs)s4&QgQPWwcUVWC&d3 zi#yvN=4imW!DCW8w>nc|?KXegy@?`&uelPbJ}(9Yk7vC2HL5Ps@FOsg7v?}l2;2(N zf~`958&40mVu13#mbqCjlz##bs(q_?il(1^zU>hAIprqaX1Jb7#xk7KQJ z;24t6(J{w`=o#2Mg<>dzH)=nU(dVkwSm~msHCJ%j9v@C)dFqYFur^*Pfzjs&>B?`0 z9ym~xsl8Ce{jWx=RA{gy{or$ik8y1Zx+Lsnt=)R96)c>X(}MZQvB%G(lw~*Bj@}!9 zE7DQC>Te>Z(m~5kmbbLcS{@z1kXshhgO5xaSG^$JtLeEsqNlfO<4DS$%&m&`QyN!4 zMi5o>aGh6fTp&iDvvZL$J@n@`Nr&{BbfjuTS7p>jt==+;_!zZE-o_H?0b zHbeIF`_~A9sNVtO%DoDDhnh6if5iNUObY)eyN|HAAzHW)gc8H2QMSzcy=DXQ`&5Av z@CT#=nUzJ{3H3qkzhEvOY%e)6333%=#At4y@c$`FJ(CtSaEeYfU`+Qu5)zM&>1=37 z_6MSZIzw<^hx+1CGQ)1)ZV}OmPyyM5ttXcb3kqS;A>(2N-Xzm=J z_k0q?n#;3qlPjO+v(}<8xHo!NEd4}|qw=-o-pP^myGyy)C(4|7mu-<~KdEV52C!*K z^Nc~W(`F4m$Imge1t+oXVx-=eDVtXlXiuAfj?afNa-#5%fRjZ}E0q;xp;gO&6k8`5 zEC+Jq&IPlV(ClW_FWV%wBBey#lsZ0Ky>-J?BJyV0^K(3K0oGLVu;4E!SQVYv8lK>!jP3u={`#^7m!mh zwMB>apK{DSd8nt5F0Qxt!xLW?W8?2#SywRL?mc%x&iM5++{2U})g(+m;DvdgnBLL4 z>EY9z&kBr=n#Ns}rC$WYz%$vISB? zC%I07gNqc$1}%s1BXckuacy8;#R(ZDBpl6wL7)w`3>)5=qd6-RnJg9Qn8}|vZO9jQ zau3dVkU0$5m8mw2--*r4k*6X}a_xkbeL#aUEzn64vTYH?H+!Ml6W5Ey4Axk8Z~9~b zx}KP4@JB*EZGiG!$z7=5aA{bX6hUh4OsyVsk=br+ZyO|0KPe9*C>I&44pL|}BEZH1?iZ0*+b?r@-VW9|$(6C&tv&*%0L!Qd9-Tn-_ zNqp#M6K=G&oJ`s#!PRYC6X@Ib_6Eka}c)}U*&OiI2{=zRscc6>^Og! z@{GY<>vU2iN3)=H-`Xnz9f~~-g8BHi=ro!pe6=4Vt-Xy2oU34L%_LJ~+|T%Xm8hL? ztOD|p-}M4TIkLIujg2;YhrlP9QjBLKJ$6mrehly`zLzg@*y**m)?_*PP2yUm0iYg* z1x3Z%4Xkc$224#hK^G1_DUPE%EAK9$Kfaq^KRnMRzaQB&%JYFUTp@;Mh7R(2&!xf+ zPknL?<-q+OS2h?o4=RWV{F1ucIb?G3??IbCp^f2v$hjk3k$#ev9~I;F*b{ihY|7^i z`5*Zx!!B#f^PQid%$C32rK-#|*8e*xoD}c`zhig@TQ~T9R+Q>mpO)8gW#qgOcm6Ok z3e|>QI_MfJMWMN2u6$IT!ZjRlH4Iy4@i(hqzh-DMP&Cy#zU@&x4?R?4oAinf46FYd z@|GQmxRCM7&3ne9hY%~b2I??HL6qPkY4E)FSCj$Aj zGcgF39>cDmoU+{j0-AFd)n-u9Vq4zoA#O?7`95e&W+-A?$uVCEbyIzrvKMPd!h9Nz zGFmSM9Ms%ZJZ%}WrFB(zj&}wY_~^XvMjgdZApere@fQWISOB?e)U3!AqZh;dfqb4Cx$3RbIRALpG)$V)UiWQJx= zh%00Qg$Ma8$SH@HIiHDk36ahL1Cw%t`XmWa3%B{FiGqM!u%Nu>N@!Bvv z=O@Ktd|9fM_Pkn*F}i->F&OaVyP`0rscod+)7ekctnPfX_tVpVTqY;fU!U9m>Ibew zjdS__x5_p7x2dnBHeNot&(+vnML%LL@^citLtxPAwSIe8-+sk2I||~OuRjoHX0B)K z3{PvifO|S6Y$H%eHvVl{hw?5bU(dYYOAL7wsM>$IbW#ML9WeS(`hkSb^xr|@JZ!B} z*ctc5^Z0;(F60?s>F_o+`oU=`MR${GtEE~TtNeOaLEezX^%3`-3tMdZYZl5iFky;|7!8}OdQ($iew=oG1(#31m zUi}Ch+#=a8xQE0Gp*oNupzRdo@hvKhD70yPvq2n)nV zoH`zXMONL$9JG;8FTnZq@~^o(0<-YiP^uI}{0O2ivjYm5Bv9Bj3DWHOY;4($Ql(*M zGv69X(=@FJT9#xy((+DRIZrxh=@WfJK}=c{q0(siGtjw^++bM z;J6$fQe(C8dbC7!?Sk~!lS3PWG?{ z^vIXDBll9-ESTNQ3#+%Qjc9D=_4j6Ybrnq!93^LoJAJfNEcoH**unRB^Q7*ITko#) z$-;MfuB2_LDB6lOSoaxZc{jgy0&#lDX^!5}goT zTJ|O-*cEi?AFAHvDNfBch?@anDiK)79hD(e&4Zmifd`(RLmj{yoDdg#poWbfm z;(i;0g=_(yrsm7%p(aD=!)<;Zgs2PT-iA{f$@Pwy*}zM+2+8pgmy~Q|d9(E#o~C2# z?{u%^XJ;eMm!T;91)He1U4AED4$`znG*u!izDgv)6#G6sX@s+k*|B!zD*jc$e52m4rMon3U<<$wcJ7}mNAl4K$}@!TfDsnu);(npE!3J!>NC`?ko=TMkj+byg2it6qA zK)MPHh9zjj?4dLg+V5>vD!Vh*s|NfGlySQ(Ml2{I*ZG6f1m61r8 zfDNh-&Rnd8o#C^F_2Fn>ootzj;F9Sj$ zoY9N;9W^dhbP`IPOBKUop%s>ID%NGVXc&`HO;En6E*xe>;Jr*lD#h4!84IaP=fZgQ zf7Db(?`H86fJv+`PgRQfrtwV(@{&@Qc|vmO4$D9>LcaE%k!qE@K`q>b2FIpwoOnY7 zQz1!O%B6w8%_rhvGBfyV1#50&x7}32ErV;0mix->JhOeI$xmg2qHjivgIt}BuSH<$ z$fIScH9!HSG;`R!V^u0_{MyMYk3cW(p$FNqF*+f@TH2T5m?-MO<&UmE-O#+6zSdfs zE1G)Z)`4HPB`~Yl(7NjDW89spr$#D&I{yWQQ?L(Ce?cL3uty+lf_e27F7f8!uc2x8 z16$*UdS=QTaKCoGYczq+1l$V|6>k!2o*qz@5q*8Z$qzroHlE zlkBBmf@=LP+Z~Tz_E6J}@3gO9iT`j0uf$8lYmvpcdpWfm^wJ%xhj>2G za9>_t*T;Hsd(39FY{uXdrGyQ3YRLOzCYzHH+JS1{acA|nEVV#bSiFf>k6e7m2d}U_ z_?3ZhFSOKfmH6ZAAC7(%_>B~isvf^3aqJ|Q>iTe7%F_IR$2ojD*!D&|$*l<=`M?35 ziR7=X#kK#`JE2W~Lb87I2wP;-KOmxu)5%tbL3bu!awgTDx%sfVIzANi(3VU2bVaHT z{X@PFgQA=eJ4C$Mtp?O)OuV1Su*s_N<-WCz*Ys2FSr|`B%805w>07=SRHD{ob*|lI zhvQbpM)96btNmg}V!Xmo@Di)u0Yle|^<91*XBDsiJ3&F%-}nLqm}nEPr&~?wH=Dr( z*b1mBV1rt~7w{Wj1;q28gY>~HV_&CFpg(yE+|1gAfDLLw>hmBSPy^dAdFu^pkbD`V z-bFZI{15@0a}4X4W=hSw?7*T19bl2@Y^NMq%7em8K#;Y7=Y?Op#jp<;K1XC~u4UAC zhl#Q}0;pBAkf)3+%EuuPZ%x9NqhL@z%cfuICDf@xRbLd+)~j_bo4j3kDvsLu##NCf z(af?Z@Ij;zNz!?~KLX4;D*@LwxTR@Fxt%?9Sc`N#h;(jwk4+AA^xX|+;?@b1H(P!` zo^S|=S!Y`Df_pWq17~3yN6MlE*Dyh__hM~9tiz*=cw>p1to$c0c6xrnz5~FH#G5;+ zIT9$3TWz&_)H7?G%B)%s#5>q6^s#NHMlDEc&qU?ZJ>E&vvZ;a(7d*Yz|AInI=6b8R zupY{Du!uqsg2Fdc@VzC!j?}wt=1oWKHAkvYm-=sNrfe=$+vrvGVl3`>am`_q5?^+v z!zHfjfcqQ_9vGaluY!v+;$H}JJd4b;Hr6XQS_Q2|t*%B*1=m)uj^&1wyrH?vgxN#)n>IGqDNh=og8m08iAf_ z*VcPp5lo~jzU>5)o#!S@$?tdd;a)FEg_Q&~&v{7~bP zxeu+#nk|Qh&+}G#Bloa;EJqv4=!=V2DH+ZfpGecoW?M51}$1mB5c(tu^@|sxzXkn0Jf~jc5ZGNVS>$Vrf$<0@&K8{(xCB|(P6G9zq@F^6m_T# zm%%+r4wN>~{TBJYcNk@|B?Oc4ay7E`?e43S>(;w0cHMM~YxdbZb5QT4?AVT|);|T0 zQTIi@ENNEBvyIN!7hE#%UEcwMfT7T6+D7Xlc2J9uD0*!!F zkdpb_I3DgPd@j#KnQbyl05cRonlL1(Z!>8gmE>G(M^FhxIqp;6>$91aB3pN^%7RT# zpvf7_4Vk2B0W2f|a*p@076R0zbLy<%(d(}Vn(;WSqOw+zD8F#NTNWp)Zmn(nQ%>YT z6N4AV&dDfRCC6F@2a0KB;cRQJGCh9L^t&i`u{%<99{X(4kRUUc65tJ@$RgQ^$O~FK zA{%$tNSxFto3eRE=u?63HfVB!CgZ#Q<*@=Mql~Tb%X*;vk8C7SzbR4${fiAl*LCm~HMOZ0A&y0KX2-ireDb(gTN*fL%(@qUWS>H;yMi#}NL1*)4 z>q#OeUSf(ir<@<(>Ht_W_IA%G8?S$Y7Bq2Cly8N_B2b2Oq|+U;?pC8$(R2LB%!O=wc;yko&K<`wl}^#I@r5fO@x_-4tLrzy$e?|nQb%cFjZ0I; zVDz3soMXpvC-qu#5hFnHox&=|=b}N<_}jmrz=5q^{AYbQ9{bPwu&N+^d@?xig*gIx z@R|JESShuQPbC(mIVEU*mwQ-{#|W_V+oRQHKgjk?$=gk8wGeE#<`I)>iVS_`%)3&+ zy{z_BtsLztr1#o86X%lGqgFlnHcv^)JtOd^nWx@-23ya*gNx_&!O0T)L^6;tJ7(d& z^^uNqinIDABFflvP^?I?SfGtPga-A2!2?WmPK7QaFyb=MRpm7p72W~l0eprmTMRfy zjpVsw;&j<5XbRc;8oX3n?Q>mI_R^#HYQ|R!k`9XfnJAtHWlM`tH=&UX8Uycy!z-cj zHFD~)D^fWOwZdldY`xvw4FNM$5|Ongb4=ULQqCl0mJ0`!4NcaiaoC5x57JN&Vi6;? z=k%%Ep%c16CDmK~3NB*m0wx>3q6Z|Fq*5H965=mgNK=P=&bKePiSYVk&M0FGH*XEy zRUW`6QCxL<;tYeAMZ$HFZMRnZ*xxqqsAvr2D*KLhrYV;Nu;HL~?D3Y|j(C75dE$l)|a7fRjXT&Iy zK;3X)EiO}i7!g)nz)HfBEe-Txmkg3=S3>x$*=|;4T+s5~KQ@Ib*e9F6RWN&b0w`5m(g9#*JEz(+;Q7%MC_M)nR1Dy z&(_m7=vt7SbZLlAh-%Nf-51tn=`VAkbP&o1MY>rw+7+3W5MAHkK9%}d6Bt%f1K3aK ztrxw8rlW*Kk+vuRt4F-*?Jgqgc&L@COup!hhIoJzO6O!k z77cP>w(}KDRWDEH$gQuwz%4xAE07LYMjM>`ShEXSXUF({w=nu61#);?ahH(+P+m8A zCg({hx{uJNP9hIv3+C*hJlA{-+-^$-Vlu@8jy6aJ&pLWjO*k_YH zl8~0Jl`^f-{5eBPXZJqsVLg2GDM>fDZ?33VfoRdaceEh1X*S#ANrR4oYKXrDV%t@m z_7wd>O*?|gG<*F0J$h6^^GY~2vQ>{s@%v_V_I{8i`Q#Qezmy@aL4cy_!%cHv8BMW8 zbOzga`9OH<#Dv*RVTir2pZ|@ro|HZEv%akJ7Rm;2Kb_i!oe4n%Q@Nvc-~ZL1@V}Cd zprSBxX$N1*1XK;)($aO3cpT;m?x7HcwQo`2ap)Y#peTcxz4IiKK6fyeTq*1Z83Szq zf;2$qOG1?SP&qn(4QhScOZg5>M;TY$_UdrB$y_>DkI}Dz&gysJVgrodm6Q1P5*X%I zFPenEI=OzV%XtWp>pP^sEGp@qDMMk(96{g-67pZ^K}6KB8;wth5Ru1uxac|H**TJd(5B>k)XV3$L3DyKI!Gs;D8;`km%YpQ=p+g=RdF&X zbhm!ak79dGWIae#3LfwLX|N$z&T|hv0O3DdvGC0my_3kRrsG|IHBQX=;U~9AUPwOl z&Mtx_ey-cZB|;(x*eE{!;I7kwTNP!W>Q)qwh{2u-TJ^~t2gR{}Cxr^wC&hn2;rPbC zhQ?Q~#Cg}O+#1uQSeb3XhU6pS=mOnoTNnMaS)!^Jx0%KAb-!!kpU$vuQ~`ul`v;re z`M44CL>oMhZ1~7;+%uBM>j(#NTK2-c00^Y@`{9(+rR5E${VVFO{w_gj4xCEcpvPY1GT0QGPPcB1q&VzZ-%VG(rt-GadWC3F3zbvxUdcvrsJm0}#$XiU}0V zLmu%#Sz-DjK9BDRtKoYh;`o&i13m&^@R2}2KMXV59{?#Ck;V+SCCEaX5>X$+33IA~ zYU+MHH1{3?k0fwk$y7utFc`&fNEIHQ&tqf_nPtd|)tmfKoF{0KqG)2QO`9^Akrx3J z=8=3KL%<2iy^OdW_*_0%6ViQoYKoWm5PoFA|7BiYPmVRwP3z-ux4yr<%u7sBz|J6Z zJ>V{_lwuVizjN|3+t0qXbRN2JvZ@97@8s=!?yHi4i6Ao&Ee) z2h}+E>S>Ct6E(wduI^Hngo=ue6xw^0Iy7HNPIp^~j)aO6r8->|_DL423WWic9 z4qIei_C3pd77w+vlcx!@i7>WUEQZX8tvQH zQU3Jund90Y2m6Ot5kJ^Z4*;6|{wKP3czjk9D}PU$JH~H~^gsMYJF5J~zt5-ezXHL3 z`xx8;w18;>G|3uOW}CrWCtha+frt2jj>v>S3>(h>3f(U#f?XSX4ht020qcA<#3Q~R z&%DQB1#^B z#cZeR08vr~^kGz%QD?3OU?=0?#A(CdA4hjNnHPBO_)*VN8p#DE!lb&283%2rIkBbN>@aHNuyM=6 zM#!UL{UFD@5{-2pZ?|Y^rGo`J96PPr1N0(w3YKV z1@BYJ_*J43NkXBVSg2-RQUWT(7tolQx6XT;1r{x1vPS%oo1CXcyU>;CuabJ9Xy`E~ z@7XvvR!KI(I<)DS(R~ow9%?T0vGD@gDgWK)v-+!i+3dM8>!(VAFg&8keK)GIw?NY& z`rL^OZdL@1eEj-YhA-J%s=w|Xn2=yu>GkuRPZjOUoYlirG7^RSa<600%TgJcYsC7T zbOWev`kkEiRy%mJ_|L)if!%dl8=_-Iv&hF~uUH%Sl-=S5Tu)J}CVXL)oi(g~mVD(w zSn#u>?T$Ao<0FLUxtwjBsW~Sn8F{|re@zPiCdL2^fFy$Xy~?J2r9oTfZDfg@%pYKq z;1p;MEPy!!WRNWEAPlaKv4yNbv%ix;=zXhZ;bK#U42aaIK`yTkJRB;n7V>uSbj_>DtRitod z8RQ6D_N}_CXQe*XTKaZ_)0adBOH7aYo2r6PoFUZhQIGK&@Ym2-llke1m@weo^L8YK zCv-Wlh7{Z^`AF^ZKlF2O>0Z4bGoTb>{BtxxUSP_vR-!ss#1_vvp~ zs)M8NrkXUcC-BDt8XO;$Bpc&!Cl$9`ri8{7-KcwKSmNSU>G5$VSf1j6Y6G6%vbk5p^}oMf;$324IciZre0++>Nho4R@&3r8Ky$^fQanjQF)9v02}rS_)3t}kASm(8a`wy+zlCZBKp8^<=A z+>8FReL~BMR~VWY8uYod8Ot?!8}sbMj!vEDRqI+F1{uQdAIa?Sfa?k!SQ@#0vbYNb zPG7W6uu1H#mnvkp7F(C>Z=@JMli&ZsRx9(3*O!(*f|9*U8x0;Ov2rR7$@j^<#}ivZ z4GlVWd>}GTT|ZD%`%IHr<~?*NIVkVgCDF~MY0T2BDBo>wo>b;fFVC?TY^YL2H&gTv z6)|tO{7A3rvUWV_*L%V zQW%xcXzZqR#G*g-2@%s50y;4*K`p*LSShqO?&WubJ6I@_Coog+0H6$-QXYVt0Tmr! z%m}Drl5h>|Yw+k}PDGBNn@OMrLNqaK{<^r7gw!D-Yk?P1M%RfCA5h($dYDdjrqj&` zn6e-&J|=291Vs76FX3(ULQvY#3imLwX(tH{-UtaDu3xWPCPgZS#H#})(lYhnZAp3I zjp`Tk=4-n)T~yNxgH}T{8$PPBL(xX4+Jw4Io&&-I0YA0Mp?BxE?vP1=}t-9~{O`eNP02*JJ{tFI_Cg2iCX6p05bT;)vH#74EUo%ZeTyX> zHHp;SNu>d0@(NpOwv2WzFbk}XBq>C?;BJ{*-x}oWtI#rPMcnaA0+QUcbgDhN>E0I4 zC!yxR$kUVFaeOvlEeL|n3QD4ZKeT#-hx1&_5&N9nIyrMtMf!7`6O^|z5U`^`u+YgY!E3xKL;yfrvi50bbA2)K^@2x~ zemhQXDqQibI#J<*6>lExVDs^)#Zl%~%ps^75u`Bxv6^t3hd*X z&%{U^lC>FtP+yu29jeZkfI;4u8oSMO0yzA`!j)xx? zC6K{=zRXX$Tf@W{JKf}3EcN^iypOzWy1tr7NPfHL)WZi`@A3jM@9+L{+DVY;ue}#C zIz1=`?FL15>p4&a%K_=#mu24>oeU_xQ8KejivGD~_VojTQ^oBL@3%~FO51U^#U(Wm z{rJOsVkwOA7RUO$J=1|P)|&KueJbU0{(U!>)0l;fi0Ow7n>3+AN^g?eYiRo$3jF&c z{+)xu|0hEYxQWjOw==zn&n5W+4Z9nXuvY%PZ}N*dpReTeqz|K92#^k*98dN*y-OF5iAvFplq%xhX!lIi!G@d-nQb zPe0)=D6nAfTg8RjLu`(UaC;DfLc{iNOB>GROQS}1yt&>(W4IJMzhCmlqha8inedE@ z5~$SLM-?50`shQ3hZFG`Q7&Jn@5j`CU6pyf_s0&&ol#0%i;^73_&|@*k{S)Fa3|

g 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

!R2Jd&vTuhh#A`hHmQW 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 literal 0 HcmV?d00001 From ef6203653addcc0bacd5624f865eda5affc6b11f Mon Sep 17 00:00:00 2001 From: Ottomated Date: Fri, 4 Dec 2020 13:35:37 -0800 Subject: [PATCH 06/45] clean up --- src/main/index.ts | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index dc0eaa0f..836d14e0 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,7 +1,7 @@ 'use strict' import { autoUpdater } from 'electron-updater'; -import { app, BrowserWindow, ipcMain } from 'electron'; +import { app, BrowserWindow } from 'electron'; import * as path from 'path' import { format as formatUrl } from 'url' import './hook'; @@ -96,21 +96,4 @@ if (!gotTheLock) { mainWindow = createMainWindow(); }); - // ipcMain.on('alwaysOnTop', (event, onTop: boolean) => { - // if (mainWindow) { - // mainWindow.setAlwaysOnTop(onTop, 'floating', 1); - // mainWindow.setVisibleOnAllWorkspaces(true); - // mainWindow.setFullScreenable(false); - // } - // }); - - ipcMain.on('shortcut', (event, val) => { - event.returnValue = false; - // console.log('register', val); - // globalShortcut.unregisterAll(); - // event.returnValue = globalShortcut.register(val!, () => { - // console.log("push-to-talk"); - // }) - - }); } \ No newline at end of file From ad23db76732412a4aeee616db925c457d6aac940 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Fri, 4 Dec 2020 13:35:45 -0800 Subject: [PATCH 07/45] Disable offset caching temporarily --- src/main/hook.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/hook.ts b/src/main/hook.ts index 9b0648fa..1256452c 100644 --- a/src/main/hook.ts +++ b/src/main/hook.ts @@ -65,7 +65,8 @@ async function loadOffsets(event: Electron.IpcMainEvent): Promise Date: Fri, 4 Dec 2020 13:40:21 -0800 Subject: [PATCH 08/45] v1.1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f605a99..699279e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crewlink", - "version": "1.1.3", + "version": "1.1.4", "license": "GPL-3.0-or-later", "description": "Free, open, Among Us proximity voice chat", "repository": { From 2b3324484e840ab05b47e7d2b7cba998cc016ea7 Mon Sep 17 00:00:00 2001 From: Edgar Orendain Date: Fri, 4 Dec 2020 17:26:24 -0800 Subject: [PATCH 09/45] Voice audio calculated using modified pan positions. --- src/renderer/Voice.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/Voice.tsx b/src/renderer/Voice.tsx index 058c7d43..8c2a874e 100644 --- a/src/renderer/Voice.tsx +++ b/src/renderer/Voice.tsx @@ -98,7 +98,7 @@ function calculateVoiceAudio(state: AmongUsState, settings: ISettings, me: Playe } else { gain.gain.value = 0; } - if (gain.gain.value === 1 && Math.sqrt(Math.pow(me.x - other.x, 2) + Math.pow(me.y - other.y, 2)) > 7) { + if (gain.gain.value === 1 && Math.sqrt(Math.pow(panPos[0], 2) + Math.pow(panPos[1], 2)) > 7) { gain.gain.value = 0; } } From f1e784c439ec7880db2c380489688f37b10e0e21 Mon Sep 17 00:00:00 2001 From: ottomated <31470743+ottomated@users.noreply.github.com> Date: Mon, 7 Dec 2020 22:35:13 -0800 Subject: [PATCH 10/45] Re-enable caching and more verbose error --- src/main/hook.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/hook.ts b/src/main/hook.ts index 1256452c..42a572c3 100644 --- a/src/main/hook.ts +++ b/src/main/hook.ts @@ -65,8 +65,7 @@ async function loadOffsets(event: Electron.IpcMainEvent): Promise { ipcMain.on('relaunch', () => { app.relaunch(); app.quit(); -}); \ No newline at end of file +}); From bf0277e3308eef1f102e8b5ae6ef18871b0603fd Mon Sep 17 00:00:00 2001 From: Ottomated Date: Mon, 7 Dec 2020 23:00:15 -0800 Subject: [PATCH 11/45] More error handling --- src/main/hook.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/hook.ts b/src/main/hook.ts index 42a572c3..ec7e39bd 100644 --- a/src/main/hook.ts +++ b/src/main/hook.ts @@ -79,8 +79,15 @@ async function loadOffsets(event: Electron.IpcMainEvent): Promise Date: Mon, 7 Dec 2020 23:00:22 -0800 Subject: [PATCH 12/45] Migrate to https://crewl.ink --- src/renderer/App.tsx | 2 +- src/renderer/Settings.tsx | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index c572eee9..ace43b85 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -31,7 +31,7 @@ function App() { microphone: 'Default', speaker: 'Default', pushToTalk: false, - serverURL: 'http://54.193.94.35:9736', + serverURL: 'https://crewl.ink', pushToTalkShortcut: 'V', deafenShortcut: 'RControl', offsets: { diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 379ef587..52ca4870 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -31,6 +31,12 @@ const store = new Store({ // @ts-ignore: Old serverIP property no longer exists in ISettings store.delete('serverIP') } + }, + '1.1.5': store => { + const serverURL = store.get('serverURL'); + if (serverURL === 'http://54.193.94.35:9736') { + store.set('serverURL', 'https://crewl.ink'); + } } }, schema: { @@ -52,7 +58,7 @@ const store = new Store({ }, serverURL: { type: 'string', - default: 'http://54.193.94.35:9736', + default: 'https://crewl.ink', format: 'uri' }, pushToTalkShortcut: { From 7e4054afa1dc03325d921f73e4d40f693dbdd9f8 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Mon, 7 Dec 2020 23:00:26 -0800 Subject: [PATCH 13/45] v1.1.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 699279e3..264770d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "crewlink", - "version": "1.1.4", + "version": "1.1.5", "license": "GPL-3.0-or-later", "description": "Free, open, Among Us proximity voice chat", "repository": { From 6e2773b67430310f5ea63728f1c1d5a572ffe949 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Mon, 7 Dec 2020 23:06:30 -0800 Subject: [PATCH 14/45] Further SSL migrations --- src/renderer/Settings.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 52ca4870..47580ad4 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -93,6 +93,12 @@ const store = new Store({ } }); +store.onDidChange('serverURL', (newUrl, oldUrl) => { + if (newUrl === 'http://54.193.94.35:9736') { + store.set('serverURL', 'https://crewl.ink'); + } +}); + export interface SettingsProps { open: boolean; onClose: any; From 88df2a2c83d9b06d54b78313f7baf0283cee02b3 Mon Sep 17 00:00:00 2001 From: ottomated <31470743+ottomated@users.noreply.github.com> Date: Tue, 8 Dec 2020 09:37:44 -0800 Subject: [PATCH 15/45] Add support link --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a8f55c3c..2db9d4d5 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,13 @@ · INSTALLATION INSTRUCTIONS

+

+ DONATE TO THE PROJECT + (all donations will be used for server costs or paying for college) +

- ## Table of Contents From 586db216de0ede09635158c68959ea88d00491bf Mon Sep 17 00:00:00 2001 From: KindarConrath Date: Tue, 8 Dec 2020 16:26:43 -0500 Subject: [PATCH 16/45] Changed regex to include device name --- src/renderer/Settings.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 47580ad4..36ab4665 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -189,9 +189,9 @@ export default function Settings({ open, onClose }: SettingsProps) { if (d.deviceId === 'default') { label = "Default"; } else { - let match = /\((.+?)\)/.exec(d.label); + let match = /(.+?)\)/.exec(d.label); if (match && match[1]) - label = match[1]; + label = match[1] + ")"; } return { id: d.deviceId, From 65340ad76bb3e70f69f77302bf4eeb9e3b8285a0 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Tue, 8 Dec 2020 16:29:41 -0800 Subject: [PATCH 17/45] docs: fix the donate link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2db9d4d5..c302baa0 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ INSTALLATION INSTRUCTIONS

- DONATE TO THE PROJECT + DONATE TO THE PROJECT (all donations will be used for server costs or paying for college)

From 57d503a5980e03dcc05a8ee32aa87df0cefe8e8b Mon Sep 17 00:00:00 2001 From: Jason Allan Date: Sun, 6 Dec 2020 17:43:31 +0000 Subject: [PATCH 18/45] Rm circular deps & rm x dep between main/renderer Just simplifying out the import graph reducing and removing the cross dependance loads un-needed code to be loaded into memory. But this is probably treeshaken anyway --- src/common/AmongUsState.ts | 29 ++++++++++++++++++++++++++ src/common/ISettings.d.ts | 16 +++++++++++++++ src/main/GameReader.ts | 32 ++--------------------------- src/main/IOffsets.d.ts | 28 +++++++++++++++++++++++++ src/main/hook.ts | 31 ++-------------------------- src/patcher.ts | 2 +- src/renderer/App.tsx | 13 ++++-------- src/renderer/Avatar.tsx | 2 +- src/renderer/MicrophoneSoundBar.tsx | 2 +- src/renderer/Settings.tsx | 20 +++--------------- src/renderer/TestSpeakersButton.tsx | 2 +- src/renderer/Voice.tsx | 6 +++--- src/renderer/contexts.tsx | 10 +++++++++ 13 files changed, 101 insertions(+), 92 deletions(-) create mode 100644 src/common/AmongUsState.ts create mode 100644 src/common/ISettings.d.ts create mode 100644 src/main/IOffsets.d.ts create mode 100644 src/renderer/contexts.tsx diff --git a/src/common/AmongUsState.ts b/src/common/AmongUsState.ts new file mode 100644 index 00000000..17d7301d --- /dev/null +++ b/src/common/AmongUsState.ts @@ -0,0 +1,29 @@ + +export interface AmongUsState { + gameState: GameState; + oldGameState: GameState; + lobbyCode: string; + players: Player[]; +} +export interface Player { + ptr: number; + id: number; + name: string; + colorId: number; + hatId: number; + petId: number; + skinId: number; + disconnected: boolean; + isImpostor: boolean; + isDead: boolean; + taskPtr: number; + objectPtr: number; + isLocal: boolean; + + x: number; + y: number; + inVent: boolean; +} +export enum GameState { + LOBBY, TASKS, DISCUSSION, MENU, UNKNOWN +} diff --git a/src/common/ISettings.d.ts b/src/common/ISettings.d.ts new file mode 100644 index 00000000..3b4e7f34 --- /dev/null +++ b/src/common/ISettings.d.ts @@ -0,0 +1,16 @@ + +export interface ISettings { + alwaysOnTop: boolean; + microphone: string; + speaker: string; + pushToTalk: boolean; + serverURL: string; + pushToTalkShortcut: string; + deafenShortcut: string; + offsets: { + version: string; + data: string; + }, + hideCode: boolean; + stereoInLobby: boolean; +} diff --git a/src/main/GameReader.ts b/src/main/GameReader.ts index 2ddc244e..d5b1d103 100644 --- a/src/main/GameReader.ts +++ b/src/main/GameReader.ts @@ -1,36 +1,8 @@ import { DataType, findModule, getProcesses, ModuleObject, openProcess, ProcessObject, readBuffer, readMemory as readMemoryRaw } from "memoryjs"; import * as Struct from 'structron'; import patcher from '../patcher'; -import { IOffsets } from "./hook"; - -export interface AmongUsState { - gameState: GameState; - oldGameState: GameState; - lobbyCode: string; - players: Player[]; -} -export interface Player { - ptr: number; - id: number; - name: string; - colorId: number; - hatId: number; - petId: number; - skinId: number; - disconnected: boolean; - isImpostor: boolean; - isDead: boolean; - taskPtr: number; - objectPtr: number; - isLocal: boolean; - - x: number; - y: number; - inVent: boolean; -} -export enum GameState { - LOBBY, TASKS, DISCUSSION, MENU, UNKNOWN -} +import { GameState, AmongUsState, Player } from "../common/AmongUsState"; +import { IOffsets } from "./IOffsets"; export default class GameReader { reply: Function; diff --git a/src/main/IOffsets.d.ts b/src/main/IOffsets.d.ts new file mode 100644 index 00000000..d8096d53 --- /dev/null +++ b/src/main/IOffsets.d.ts @@ -0,0 +1,28 @@ + +export interface IOffsets { + meetingHud: number[]; + meetingHudCachePtr: number[]; + meetingHudState: number[]; + gameState: number[]; + allPlayersPtr: number[]; + allPlayers: number[]; + playerCount: number[]; + playerAddrPtr: number; + exiledPlayerId: number[]; + gameCode: number[]; + player: { + isLocal: number[]; + localX: number[]; + localY: number[]; + remoteX: number[]; + remoteY: number[]; + bufferLength: number; + offsets: number[]; + inVent: number[]; + struct: { + type: string; + skip?: number; + name: string; + }[]; + }; +} diff --git a/src/main/hook.ts b/src/main/hook.ts index ec7e39bd..d8d17345 100644 --- a/src/main/hook.ts +++ b/src/main/hook.ts @@ -7,44 +7,17 @@ import spawn from 'cross-spawn'; import GameReader from './GameReader'; import iohook from 'iohook'; import Store from 'electron-store'; -import { ISettings } from '../renderer/Settings'; +import { ISettings } from "../common/ISettings"; import axios, { AxiosError } from 'axios'; import { createCheckers } from 'ts-interface-checker'; import TI from './hook-ti'; import { existsSync, readFileSync } from 'fs'; +import { IOffsets } from './IOffsets'; const { IOffsets } = createCheckers(TI); const store = new Store(); -export interface IOffsets { - meetingHud: number[]; - meetingHudCachePtr: number[]; - meetingHudState: number[]; - gameState: number[]; - allPlayersPtr: number[]; - allPlayers: number[]; - playerCount: number[]; - playerAddrPtr: number; - exiledPlayerId: number[]; - gameCode: number[]; - player: { - isLocal: number[]; - localX: number[]; - localY: number[]; - remoteX: number[]; - remoteY: number[]; - bufferLength: number; - offsets: number[]; - inVent: number[]; - struct: { - type: string; - skip?: number; - name: string; - }[]; - } -} - async function loadOffsets(event: Electron.IpcMainEvent): Promise { const valuesFile = resolve((process.env.LOCALAPPDATA || '') + "Low", 'Innersloth/Among Us/Unity/6b8b0d91-4a20-4a00-a3e4-4da4a883a5f0/Analytics/values'); diff --git a/src/patcher.ts b/src/patcher.ts index 189ad6d4..941953ac 100644 --- a/src/patcher.ts +++ b/src/patcher.ts @@ -1,5 +1,5 @@ import { create } from "jsondiffpatch"; -import { Player } from "./main/GameReader"; +import { Player } from "./common/AmongUsState"; export default create({ objectHash: (obj: Player) => obj.ptr, diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index ace43b85..05073a08 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -1,10 +1,11 @@ -import React, { createContext, useEffect, useReducer, useState } from 'react'; +import React, { useEffect, useReducer, useState } from 'react'; import ReactDOM from 'react-dom'; import Voice from './Voice'; import Menu from './Menu'; import { ipcRenderer, remote } from 'electron'; -import { AmongUsState } from '../main/GameReader'; -import Settings, { ISettings, settingsReducer } from './Settings'; +import { AmongUsState } from "../common/AmongUsState"; +import Settings, { settingsReducer } from './Settings'; +import { GameStateContext, SettingsContext } from './contexts'; let appVersion = ''; if (typeof window !== 'undefined' && window.location) { @@ -15,12 +16,6 @@ if (typeof window !== 'undefined' && window.location) { enum AppState { MENU, VOICE }; -export const GameStateContext = createContext({} as AmongUsState); -export const SettingsContext = createContext<[ISettings, React.Dispatch<{ - type: "set" | "setOne"; - action: ISettings | [string, any]; -}>]>(null as any); - function App() { const [state, setState] = useState(AppState.MENU); const [gameState, setGameState] = useState({} as AmongUsState); diff --git a/src/renderer/Avatar.tsx b/src/renderer/Avatar.tsx index 3566ded3..b8c7b2ce 100644 --- a/src/renderer/Avatar.tsx +++ b/src/renderer/Avatar.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useRef } from "react"; import Color from 'color'; -import { Player } from "../main/GameReader"; +import { Player } from "../common/AmongUsState"; // @ts-ignore import alive from '../../static/alive.png'; // @ts-ignore diff --git a/src/renderer/MicrophoneSoundBar.tsx b/src/renderer/MicrophoneSoundBar.tsx index 1514dda3..2449e51b 100644 --- a/src/renderer/MicrophoneSoundBar.tsx +++ b/src/renderer/MicrophoneSoundBar.tsx @@ -1,5 +1,5 @@ import React, { useContext, useEffect, useState } from 'react' -import { SettingsContext } from './App'; +import { SettingsContext } from './contexts'; const TestMicrophoneButton = function() { const [{ microphone }] = useContext(SettingsContext) diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 47580ad4..443d654b 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -1,10 +1,11 @@ import Store from 'electron-store'; import React, { useContext, useEffect, useReducer, useState } from "react"; -import { SettingsContext } from "./App"; +import { SettingsContext } from "./contexts"; import Ajv from 'ajv'; import './css/settings.css'; import MicrophoneSoundBar from './MicrophoneSoundBar'; import TestSpeakersButton from './TestSpeakersButton'; +import { ISettings } from '../common/ISettings'; const keys = new Set(['Space', 'Backspace', 'Delete', 'Enter', 'Up', 'Down', 'Left', 'Right', 'Home', 'End', 'PageUp', 'PageDown', 'Escape', 'LControl', 'LShift', 'LAlt', 'RControl', 'RShift', 'RAlt']); @@ -104,21 +105,6 @@ export interface SettingsProps { onClose: any; } -export interface ISettings { - alwaysOnTop: boolean; - microphone: string; - speaker: string; - pushToTalk: boolean; - serverURL: string; - pushToTalkShortcut: string; - deafenShortcut: string; - offsets: { - version: string; - data: string; - }, - hideCode: boolean; - stereoInLobby: boolean; -} export const settingsReducer = (state: ISettings, action: { type: 'set' | 'setOne', action: [string, any] | ISettings }): ISettings => { @@ -328,4 +314,4 @@ export default function Settings({ open, onClose }: SettingsProps) {
-} \ No newline at end of file +} diff --git a/src/renderer/TestSpeakersButton.tsx b/src/renderer/TestSpeakersButton.tsx index 0023af82..4e138e40 100644 --- a/src/renderer/TestSpeakersButton.tsx +++ b/src/renderer/TestSpeakersButton.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react' -import { SettingsContext } from './App'; +import { SettingsContext } from './contexts'; // @ts-ignore import chime from '../../static/chime.mp3'; diff --git a/src/renderer/Voice.tsx b/src/renderer/Voice.tsx index 8c2a874e..c7429c68 100644 --- a/src/renderer/Voice.tsx +++ b/src/renderer/Voice.tsx @@ -1,12 +1,12 @@ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; import io, { Socket } from 'socket.io-client'; import Avatar from './Avatar'; -import { GameStateContext, SettingsContext } from './App'; -import { AmongUsState, GameState, Player } from '../main/GameReader'; +import { GameStateContext, SettingsContext } from "./contexts"; +import { AmongUsState, GameState, Player } from "../common/AmongUsState"; import Peer from 'simple-peer'; import { ipcRenderer, remote } from 'electron'; import VAD from './vad'; -import { ISettings } from './Settings'; +import { ISettings } from "../common/ISettings"; interface PeerConnections { [peer: string]: Peer.Instance; diff --git a/src/renderer/contexts.tsx b/src/renderer/contexts.tsx new file mode 100644 index 00000000..412ba949 --- /dev/null +++ b/src/renderer/contexts.tsx @@ -0,0 +1,10 @@ +import React, { createContext } from 'react'; +import { AmongUsState } from "../common/AmongUsState"; +import { ISettings } from "../common/ISettings"; + + +export const GameStateContext = createContext({} as AmongUsState); +export const SettingsContext = createContext<[ISettings, React.Dispatch<{ + type: "set" | "setOne"; + action: ISettings | [string, any]; +}>]>(null as any); From eac315fa69034d53d025d3b3e45145596b09d2d2 Mon Sep 17 00:00:00 2001 From: Jason Allan Date: Mon, 7 Dec 2020 02:43:38 +0000 Subject: [PATCH 19/45] Add a window state keeper This means, instead of being centered on the screen, the app will remember where it was when it was last open --- package.json | 1 + src/main/index.ts | 10 ++++++++-- yarn.lock | 8 ++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 264770d5..6c59993e 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "cross-spawn": "^7.0.3", "electron-store": "^6.0.1", "electron-updater": "^4.3.5", + "electron-window-state": "^5.0.3", "iohook": "git://github.com/ykhwong/iohook", "jsondiffpatch": "^0.4.1", "memoryjs": "https://github.com/Rob--/memoryjs", diff --git a/src/main/index.ts b/src/main/index.ts index 836d14e0..a9b4800a 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -2,6 +2,7 @@ import { autoUpdater } from 'electron-updater'; import { app, BrowserWindow } from 'electron'; +import * as windowStateKeeper from 'electron-window-state' import * as path from 'path' import { format as formatUrl } from 'url' import './hook'; @@ -27,11 +28,15 @@ if (!gotTheLock) { } }) - function createMainWindow() { + const mainWindowState = windowStateKeeper({}) + const window = new BrowserWindow({ width: 250, height: 350, + x: mainWindowState.x, + y: mainWindowState.y, + resizable: false, frame: false, fullscreenable: false, @@ -44,6 +49,8 @@ if (!gotTheLock) { } }); + mainWindowState.manage(window) + if (isDevelopment) { window.webContents.openDevTools() } @@ -95,5 +102,4 @@ if (!gotTheLock) { app.on('ready', () => { mainWindow = createMainWindow(); }); - } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index bbacc8a5..b38d1347 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3372,6 +3372,14 @@ electron-webpack@^2.8.2: webpack-merge "^4.2.2" yargs "^15.3.1" +electron-window-state@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/electron-window-state/-/electron-window-state-5.0.3.tgz#4f36d09e3f953d87aff103bf010f460056050aa8" + integrity sha512-1mNTwCfkolXl3kMf50yW3vE2lZj0y92P/HYWFBrb+v2S/pCka5mdwN3cagKm458A7NjndSwijynXgcLWRodsVg== + dependencies: + jsonfile "^4.0.0" + mkdirp "^0.5.1" + electron@9.3.3: version "9.3.3" resolved "https://registry.yarnpkg.com/electron/-/electron-9.3.3.tgz#99a6619d5df68f97697a5d1d82ef3a8a63fcdf36" From c06fe9afd6a35a5aa45bd6c15d76a590892c692b Mon Sep 17 00:00:00 2001 From: Jason Allan Date: Tue, 8 Dec 2020 18:16:18 +0000 Subject: [PATCH 20/45] Using props instead of context React will cache should then cache an not need to rerender the components --- src/renderer/MicrophoneSoundBar.tsx | 10 ++++++---- src/renderer/Settings.tsx | 4 ++-- src/renderer/TestSpeakersButton.tsx | 9 +++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/renderer/MicrophoneSoundBar.tsx b/src/renderer/MicrophoneSoundBar.tsx index 2449e51b..9163e190 100644 --- a/src/renderer/MicrophoneSoundBar.tsx +++ b/src/renderer/MicrophoneSoundBar.tsx @@ -1,8 +1,10 @@ -import React, { useContext, useEffect, useState } from 'react' -import { SettingsContext } from './contexts'; +import React, { useEffect, useState } from 'react' -const TestMicrophoneButton = function() { - const [{ microphone }] = useContext(SettingsContext) +interface ITestMicProps { + microphone: string +} + +const TestMicrophoneButton: React.FunctionComponent = function({ microphone }) { const [error, setError] = useState(false) const [rms, setRms] = useState(0) diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 443d654b..68186771 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -247,7 +247,7 @@ export default function Settings({ open, onClose }: SettingsProps) { )) } - {open && } + {open && }
@@ -263,7 +263,7 @@ export default function Settings({ open, onClose }: SettingsProps) { )) } - {open && } + {open && }
setSettings({ diff --git a/src/renderer/TestSpeakersButton.tsx b/src/renderer/TestSpeakersButton.tsx index 4e138e40..96d7f812 100644 --- a/src/renderer/TestSpeakersButton.tsx +++ b/src/renderer/TestSpeakersButton.tsx @@ -1,11 +1,12 @@ -import React, { useContext } from 'react' -import { SettingsContext } from './contexts'; +import React from 'react' // @ts-ignore import chime from '../../static/chime.mp3'; -const TestSpeakersButton = () => { - const [{ speaker }] = useContext(SettingsContext) +interface ITestSpeakersProps { + speaker: string +} +const TestSpeakersButton: React.FunctionComponent = ({ speaker }) => { const testSpeakers = () => { const audio = new Audio(); audio.src = chime; From 887a947d0580d818f55de97ce22d54cf3cdf5fc0 Mon Sep 17 00:00:00 2001 From: Jason Allan Date: Wed, 9 Dec 2020 15:42:53 +0000 Subject: [PATCH 21/45] Remove cruft and add some comments --- src/renderer/Voice.tsx | 84 +++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 55 deletions(-) diff --git a/src/renderer/Voice.tsx b/src/renderer/Voice.tsx index c7429c68..8f9f888a 100644 --- a/src/renderer/Voice.tsx +++ b/src/renderer/Voice.tsx @@ -11,9 +11,6 @@ import { ISettings } from "../common/ISettings"; interface PeerConnections { [peer: string]: Peer.Instance; } -interface InCall { - [peer: string]: boolean; -} interface AudioElements { [peer: string]: { element: HTMLAudioElement; @@ -31,7 +28,7 @@ interface SocketIdMap { interface ConnectionStuff { socket: typeof Socket; - stream: MediaStream; + stream?: MediaStream; pushToTalk: boolean; deafened: boolean; } @@ -44,19 +41,6 @@ interface OtherDead { [playerId: number]: boolean; // isTalking } -// function clamp(number: number, min: number, max: number): number { -// if (min > max) { -// let tmp = max; -// max = min; -// min = tmp; -// } -// return Math.max(min, Math.min(number, max)); -// } - -// function mapNumber(n: number, oldLow: number, oldHigh: number, newLow: number, newHigh: number): number { -// return clamp((n - oldLow) / (oldHigh - oldLow) * (newHigh - newLow) + newLow, newLow, newHigh); -// } - function calculateVoiceAudio(state: AmongUsState, settings: ISettings, me: Player, other: Player, gain: GainNode, pan: PannerNode): void { const audioContext = pan.context; pan.positionZ.setValueAtTime(-0.5, audioContext.currentTime); @@ -90,9 +74,7 @@ function calculateVoiceAudio(state: AmongUsState, settings: ISettings, me: Playe pan.positionX.setValueAtTime(panPos[0], audioContext.currentTime); pan.positionY.setValueAtTime(panPos[1], audioContext.currentTime); } else if (state.gameState === GameState.TASKS) { - // const distance = Math.sqrt(Math.pow(me.x - other.x, 2) + Math.pow(me.y - other.y, 2)); gain.gain.value = 1; - // gain.gain.value = mapNumber(distance, 0, 2.66, 1, 0); pan.positionX.setValueAtTime(panPos[0], audioContext.currentTime); pan.positionY.setValueAtTime(panPos[1], audioContext.currentTime); } else { @@ -120,16 +102,19 @@ export default function Voice() { const [deafenedState, setDeafened] = useState(false); const [connected, setConnected] = useState(false); + // Handle pushToTalk, if set useEffect(() => { if (!connectionStuff.current.stream) return; connectionStuff.current.stream.getAudioTracks()[0].enabled = !settings.pushToTalk; connectionStuff.current.pushToTalk = settings.pushToTalk; }, [settings.pushToTalk]); + // Add settings to settingsRef useEffect(() => { settingsRef.current = settings; }, [settings]); + // Set dead player data useEffect(() => { if (gameState.gameState === GameState.LOBBY) { setOtherDead({}); @@ -144,8 +129,12 @@ export default function Voice() { } }, [gameState.gameState]); - // const [audioContext] = useState(() => new AudioContext()); - const connectionStuff = useRef({ pushToTalk: settings.pushToTalk, deafened: false } as any); + const connectionStuff = useRef>({ + pushToTalk: settings.pushToTalk, + deafened: false, + }); + + // BIG ASS BLOB - Handle audio useEffect(() => { // Connect to voice relay server connectionStuff.current.socket = io(settings.serverURL, { transports: ['websocket'] }); @@ -182,7 +171,6 @@ export default function Voice() { if (!connectionStuff.current.deafened) { stream.getAudioTracks()[0].enabled = pressing; } - // console.log(stream.getAudioTracks()[0].enabled); }); const ac = new AudioContext(); @@ -190,15 +178,10 @@ export default function Voice() { audioListener = VAD(ac, ac.createMediaStreamSource(stream), undefined, { onVoiceStart: () => setTalking(true), onVoiceStop: () => setTalking(false), - // onUpdate: console.log, noiseCaptureDuration: 1, }); - // audioListener = audioActivity(stream, (level) => { - // setTalking(level > 0.1); - // }); const peerConnections: PeerConnections = {}; - const inCall: InCall = {}; audioElements.current = {}; const audioListeners: AudioListeners = {}; @@ -214,8 +197,9 @@ export default function Voice() { function disconnectPeer(peer: string) { const connection = peerConnections[peer]; - if (!connection) return; - delete inCall[peer]; + if (!connection) { + return; + } connection.destroy(); delete peerConnections[peer]; if (audioElements.current[peer]) { @@ -233,7 +217,6 @@ export default function Voice() { }; setConnect({ connect }); function createPeerConnection(peer: string, initiator: boolean) { - // console.log("Opening connection to ", peer, "Initiator: ", initiator); const connection = new Peer({ stream, initiator, config: { iceServers: [ @@ -256,7 +239,6 @@ export default function Voice() { var source = context.createMediaStreamSource(stream); let gain = context.createGain(); let pan = context.createPanner(); - // let compressor = context.createDynamicsCompressor(); pan.refDistance = 0.1; pan.panningModel = 'equalpower'; pan.distanceModel = 'linear'; @@ -269,7 +251,6 @@ export default function Voice() { VAD(context, gain, context.destination, { onVoiceStart: () => setTalking(true), onVoiceStop: () => setTalking(false), - // onUpdate: console.log, }); const setTalking = (talking: boolean) => { @@ -281,24 +262,7 @@ export default function Voice() { return socketPlayerIds; }); }; - // gain.connect(compressor); - // compressor.connect(); - - // console.log(pan, audio); - // pan.pan.setValueAtTime(-1, audioContext.currentTime); - // source.connect(pan); - // pan.connect(audioContext.destination); audioElements.current[peer] = { element: audio, gain, pan }; - - // audioListeners[peer] = audioActivity(stream, (level) => { - // setSocketPlayerIds(socketPlayerIds => { - // setOtherTalking(old => ({ - // ...old, - // [socketPlayerIds[peer]]: level - // })); - // return socketPlayerIds; - // }); - // }); }); connection.on('signal', (data) => { socket.emit('signal', { @@ -314,8 +278,11 @@ export default function Voice() { }); socket.on('signal', ({ data, from }: any) => { let connection: Peer.Instance; - if (peerConnections[from]) connection = peerConnections[from]; - else connection = createPeerConnection(from, false); + if (peerConnections[from]) { + connection = peerConnections[from]; + } else { + connection = createPeerConnection(from, false); + } connection.signal(data); }); socket.on('setId', (socketId: string, id: number) => { @@ -331,16 +298,19 @@ export default function Voice() { }); return () => { - connectionStuff.current.socket.close(); + connectionStuff.current.socket?.close(); audioListener.destroy(); } }, []); const myPlayer = useMemo(() => { - if (!gameState || !gameState.players) return undefined; - else return gameState.players.find(p => p.isLocal); - }, [gameState]); + if (!gameState || !gameState.players) { + return undefined; + } else { + return gameState.players.find((p) => p.isLocal); + } + }, [gameState.players]); const otherPlayers = useMemo(() => { let otherPlayers: Player[]; @@ -364,23 +334,27 @@ export default function Voice() { return otherPlayers; }, [gameState]); + // Connect to P2P negotiator, when lobby and connect code change useEffect(() => { if (connect?.connect && gameState.lobbyCode && myPlayer?.id !== undefined) { connect.connect(gameState.lobbyCode, myPlayer.id); } }, [connect?.connect, gameState?.lobbyCode]); + // Connect to P2P negotiator, when game mode change useEffect(() => { if (connect?.connect && gameState.lobbyCode && myPlayer?.id !== undefined && gameState.gameState === GameState.LOBBY && (gameState.oldGameState === GameState.DISCUSSION || gameState.oldGameState === GameState.TASKS)) { connect.connect(gameState.lobbyCode, myPlayer.id); } }, [gameState.gameState]); + // Emit player id to socket useEffect(() => { if (connectionStuff.current.socket && myPlayer && myPlayer.id !== undefined) { connectionStuff.current.socket.emit('id', myPlayer.id); } }, [myPlayer?.id]); + return (
From bda82470f535457ae0e48de7948e6cbab345d6dd Mon Sep 17 00:00:00 2001 From: Jason Allan Date: Wed, 9 Dec 2020 17:41:41 +0000 Subject: [PATCH 22/45] Add Issue templates and config to help reduce spam --- .github/ISSUE_TEMPLATE/bug_report.md | 42 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 8 +++++ .github/ISSUE_TEMPLATE/feature_request.md | 19 ++++++++++ 3 files changed, 69 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..dc768594 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,42 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' +--- + +# Pre-Flight Checklist +Please use this checklist to avoid spamming: + +1. [ ] I am not asking a question => goto the Discord if you are [discord](https://discord.gg/9mwuVNA) +2. [ ] I am using the Steam version of Among Us +3. [ ] I have tried to use an [alternative server](https://status.crewl.ink/) +4. [ ] I have checked everyone in my lobby is on the same CrewLink server +5. [ ] I have used `Ctrl+r` on the CrewLink app when I can't hear some people (this is a known issue) +6. [ ] I have checked the CrewLink server I'm using is up to date +7. [ ] I have a screenshot of any errors +8. [ ] I checked someone else has not reported this. Meaning the devs don't have to deal with duplicates and have more time to add cool stuff + +**Describe the bug** + + +**To Reproduce** +Steps to reproduce the behaviour: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behaviour** + + +**Screenshots** + + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Version: [e.g. 22] + +**Additional context** + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..a8c0e72d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: I need help? + url: https://discord.gg/9mwuVNA + about: Please ask and answer questions here. + - name: Security issue + url: https://discord.gg/9mwuVNA + about: Please report security vulnerabilities directly to Ottomated#9999. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..0810936b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' +--- + +**Is your feature request related to a problem? Please describe.** + + +**Describe the solution you'd like** + + +**Describe alternatives you've considered** + + +**Additional context** + From 2f94367e9a96af4999962736fde6e560b1e9868f Mon Sep 17 00:00:00 2001 From: Ottomated Date: Wed, 9 Dec 2020 15:38:03 -0800 Subject: [PATCH 23/45] Adjust templates --- .github/ISSUE_TEMPLATE/bug_report.md | 18 +++++++++--------- .github/ISSUE_TEMPLATE/config.yml | 2 +- .github/ISSUE_TEMPLATE/feature_request.md | 15 +++++++++++++-- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dc768594..5d7e39c3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,22 +1,22 @@ --- name: Bug report about: Create a report to help us improve -title: '' -labels: '' +title: '[BUG REPORT]' +labels: 'bug' assignees: '' --- # Pre-Flight Checklist Please use this checklist to avoid spamming: -1. [ ] I am not asking a question => goto the Discord if you are [discord](https://discord.gg/9mwuVNA) +1. [ ] I am not asking a question => use the [Discord](https://discord.gg/9mwuVNA) if you are 2. [ ] I am using the Steam version of Among Us -3. [ ] I have tried to use an [alternative server](https://status.crewl.ink/) +3. [ ] I have tried to use an [alternative voice server server](https://status.crewl.ink/) 4. [ ] I have checked everyone in my lobby is on the same CrewLink server -5. [ ] I have used `Ctrl+r` on the CrewLink app when I can't hear some people (this is a known issue) -6. [ ] I have checked the CrewLink server I'm using is up to date +5. [ ] I have used `Ctrl+R` on the CrewLink app when I can't hear some people (this is a known issue) +6. [ ] I have checked that the CrewLink server I'm using is up to date 7. [ ] I have a screenshot of any errors -8. [ ] I checked someone else has not reported this. Meaning the devs don't have to deal with duplicates and have more time to add cool stuff +8. [ ] I have checked that someone else has not reported this using the [search bar](https://github.com/ottomated/CrewLink/issues?q=is%3Aissue) **Describe the bug** @@ -35,8 +35,8 @@ Steps to reproduce the behaviour: **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Version: [e.g. 22] + - OS: [e.g. Windows 10] + - Version: [e.g. 1.1.5] **Additional context** diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index a8c0e72d..0c71f538 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,6 +1,6 @@ blank_issues_enabled: false contact_links: - - name: I need help? + - name: I need help url: https://discord.gg/9mwuVNA about: Please ask and answer questions here. - name: Security issue diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 0810936b..fef99b67 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,11 +1,22 @@ --- name: Feature request about: Suggest an idea for this project -title: '' -labels: '' +title: '[FEATURE]' +labels: 'enhancement' assignees: '' --- +# Pre-Flight Checklist +Please use this checklist to avoid spamming: + +1. [ ] I am not asking a question => use the [Discord](https://discord.gg/9mwuVNA) if you are +2. [ ] I have checked that someone else has not suggested this using the [search bar](https://github.com/ottomated/CrewLink/issues?q=is%3Aissue) +3. [ ] My feature request is not one of the **commonly suggested features**: +- Adjustable voice radius +- Mobile support +- Linux / MacOS support +- Itch.io support + **Is your feature request related to a problem? Please describe.** From 3a53b506befb56e71c9cf500416fc001bd5edb16 Mon Sep 17 00:00:00 2001 From: ottomated <31470743+ottomated@users.noreply.github.com> Date: Wed, 9 Dec 2020 18:53:06 -0800 Subject: [PATCH 24/45] Create FUNDING.yml --- .github/FUNDING.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..7948cecf --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +patreon: ottomated +custom: https://www.paypal.me/ottomated From b4615d948cfcd3cb24a2e0a0e54b235b47fc00c3 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Wed, 9 Dec 2020 18:54:54 -0800 Subject: [PATCH 25/45] expand issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 1 + .github/ISSUE_TEMPLATE/config.yml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5d7e39c3..17503054 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -5,6 +5,7 @@ title: '[BUG REPORT]' labels: 'bug' assignees: '' --- +# You MUST use this template or your issue will be deleted. # Pre-Flight Checklist Please use this checklist to avoid spamming: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0c71f538..cd441b50 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: false contact_links: + - name: YOU MUST USE ONE OF THE ABOVE TEMPLATES OR YOUR ISSUE WILL BE DELETED! + url: '' + about: '' - name: I need help url: https://discord.gg/9mwuVNA about: Please ask and answer questions here. From 9a99329c511bf7fa17aa507a1c44a30de6c4b0ff Mon Sep 17 00:00:00 2001 From: Ottomated Date: Wed, 9 Dec 2020 18:55:57 -0800 Subject: [PATCH 26/45] fix yml --- .github/ISSUE_TEMPLATE/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index cd441b50..a0440d3b 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,8 @@ blank_issues_enabled: false contact_links: - name: YOU MUST USE ONE OF THE ABOVE TEMPLATES OR YOUR ISSUE WILL BE DELETED! - url: '' - about: '' + url: https://github.com/ottomated/CrewLink/issues/new/choose + about: This is to prevent duplicate issues and spam. - name: I need help url: https://discord.gg/9mwuVNA about: Please ask and answer questions here. From 6465e88c88a7947d2a0983e39588c188a0b2ec1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nagy=20R=C3=B3bert?= Date: Thu, 10 Dec 2020 12:36:17 +0100 Subject: [PATCH 27/45] Replace on-the-fly player image generation with static images --- package.json | 1 - src/renderer/Avatar.tsx | 52 +++++--------------------------- src/renderer/cosmetics.ts | 38 +++++++++++++++++++++++ static/alive.png | Bin 3577 -> 0 bytes static/dead.png | Bin 5097 -> 0 bytes static/players/black-alive.png | Bin 0 -> 2551 bytes static/players/black-dead.png | Bin 0 -> 3864 bytes static/players/blue-alive.png | Bin 0 -> 3084 bytes static/players/blue-dead.png | Bin 0 -> 3885 bytes static/players/brown-alive.png | Bin 0 -> 2860 bytes static/players/brown-dead.png | Bin 0 -> 3827 bytes static/players/cyan-alive.png | Bin 0 -> 3320 bytes static/players/cyan-dead.png | Bin 0 -> 3855 bytes static/players/green-alive.png | Bin 0 -> 2759 bytes static/players/green-dead.png | Bin 0 -> 3872 bytes static/players/lime-alive.png | Bin 0 -> 3060 bytes static/players/lime-dead.png | Bin 0 -> 3894 bytes static/players/orange-alive.png | Bin 0 -> 3185 bytes static/players/orange-dead.png | Bin 0 -> 3823 bytes static/players/pink-alive.png | Bin 0 -> 3305 bytes static/players/pink-dead.png | Bin 0 -> 3841 bytes static/players/purple-alive.png | Bin 0 -> 3047 bytes static/players/purple-dead.png | Bin 0 -> 3771 bytes static/players/red-alive.png | Bin 0 -> 2977 bytes static/players/red-dead.png | Bin 0 -> 3820 bytes static/players/white-alive.png | Bin 0 -> 3480 bytes static/players/white-dead.png | Bin 0 -> 3860 bytes static/players/yellow-alive.png | Bin 0 -> 3334 bytes static/players/yellow-dead.png | Bin 0 -> 3803 bytes yarn.lock | 34 ++------------------- 30 files changed, 48 insertions(+), 77 deletions(-) delete mode 100644 static/alive.png delete mode 100644 static/dead.png create mode 100644 static/players/black-alive.png create mode 100644 static/players/black-dead.png create mode 100644 static/players/blue-alive.png create mode 100644 static/players/blue-dead.png create mode 100644 static/players/brown-alive.png create mode 100644 static/players/brown-dead.png create mode 100644 static/players/cyan-alive.png create mode 100644 static/players/cyan-dead.png create mode 100644 static/players/green-alive.png create mode 100644 static/players/green-dead.png create mode 100644 static/players/lime-alive.png create mode 100644 static/players/lime-dead.png create mode 100644 static/players/orange-alive.png create mode 100644 static/players/orange-dead.png create mode 100644 static/players/pink-alive.png create mode 100644 static/players/pink-dead.png create mode 100644 static/players/purple-alive.png create mode 100644 static/players/purple-dead.png create mode 100644 static/players/red-alive.png create mode 100644 static/players/red-dead.png create mode 100644 static/players/white-alive.png create mode 100644 static/players/white-dead.png create mode 100644 static/players/yellow-alive.png create mode 100644 static/players/yellow-dead.png diff --git a/package.json b/package.json index 264770d5..23897ce9 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "analyser-frequency-average": "^1.0.0", "audio-activity": "^1.0.0", "axios": "^0.21.0", - "color": "^3.1.3", "cross-spawn": "^7.0.3", "electron-store": "^6.0.1", "electron-updater": "^4.3.5", diff --git a/src/renderer/Avatar.tsx b/src/renderer/Avatar.tsx index 3566ded3..2bb491a5 100644 --- a/src/renderer/Avatar.tsx +++ b/src/renderer/Avatar.tsx @@ -1,19 +1,12 @@ import React, { useEffect, useRef } from "react"; -import Color from 'color'; import { Player } from "../main/GameReader"; -// @ts-ignore -import alive from '../../static/alive.png'; -// @ts-ignore -import dead from '../../static/dead.png'; -import { backLayerHats, hatOffsets, hats, skins } from "./cosmetics"; +import { backLayerHats, hatOffsets, hats, skins, players } from "./cosmetics"; import Tooltip from "react-tooltip-lite"; export interface CanvasProps { src: string; hat: number; skin: number; - color: string; - shadow: string; isAlive: boolean; } @@ -26,24 +19,10 @@ export interface AvatarProps { deafened?: boolean; } -const playerColors = [ - ['#C51111', '#7A0838',], - ['#132ED1', '#09158E',], - ['#117F2D', '#0A4D2E',], - ['#ED54BA', '#AB2BAD',], - ['#EF7D0D', '#B33E15',], - ['#F5F557', '#C38823',], - ['#3F474E', '#1E1F26',], - ['#D6E0F0', '#8394BF',], - ['#6B2FBB', '#3B177C',], - ['#71491E', '#5E2615',], - ['#38FEDC', '#24A8BE',], - ['#50EF39', '#15A742',] -]; - export default function Avatar({ talking, deafened, borderColor, isAlive, player, size }: AvatarProps) { - let color = playerColors[player.colorId]; - if (!color) color = playerColors[0]; + const status = isAlive ? 'alive' : 'dead'; + let image = players[status][player.colorId]; + if (!image) image = players[status][0]; return (
- + { deafened && @@ -63,7 +42,7 @@ export default function Avatar({ talking, deafened, borderColor, isAlive, player ); } -function Canvas({ src, hat, skin, color, shadow, isAlive }: CanvasProps) { +function Canvas({ src, hat, skin, isAlive }: CanvasProps) { const canvas = useRef(null); const hatImg = useRef(null); const skinImg = useRef(null); @@ -94,23 +73,6 @@ function Canvas({ src, hat, skin, color, shadow, isAlive }: CanvasProps) { ctx.drawImage(hatImg.current!, 0, hatY > 0 ? 0 : -hatY, hatImg.current!.width, hatImg.current!.height, canvas.current!.width / 2 - hatImg.current!.width / 2 + 2, Math.max(hatY, 0), hatImg.current!.width, hatImg.current!.height); } - - let data = ctx.getImageData(0, 0, image.current.width, image.current.height); - for (let i = 0; i < data.data.length; i += 4) { - let r = data.data[i], - g = data.data[i + 1], - b = data.data[i + 2]; - if (r !== 255 || g !== 255 || b !== 255) { - let pixelColor = Color('#000000') - .mix(Color(shadow), b / 255) - .mix(Color(color), r / 255) - .mix(Color('#9acad5'), g / 255); - data.data[i] = pixelColor.red(); - data.data[i + 1] = pixelColor.green(); - data.data[i + 2] = pixelColor.blue(); - } - } - ctx.putImageData(data, 0, 0); if (isAlive) { if (backLayerHats.has(hat)) ctx.globalCompositeOperation = 'destination-over'; @@ -121,7 +83,7 @@ function Canvas({ src, hat, skin, color, shadow, isAlive }: CanvasProps) { } })(); - }, [src, color, shadow, hat, skin, isAlive]); + }, [src, hat, skin, isAlive]); return ( <> diff --git a/src/renderer/cosmetics.ts b/src/renderer/cosmetics.ts index 7db74323..f80c9325 100644 --- a/src/renderer/cosmetics.ts +++ b/src/renderer/cosmetics.ts @@ -110,6 +110,44 @@ import skin13 from '../../static/skins/13.png';// @ts-ignore import skin14 from '../../static/skins/14.png';// @ts-ignore import skin15 from '../../static/skins/15.png'; +// @ts-ignore +import redAlive from '../../static/players/red-alive.png';// @ts-ignore +import blueAlive from '../../static/players/blue-alive.png';// @ts-ignore +import greenAlive from '../../static/players/green-alive.png';// @ts-ignore +import pinkAlive from '../../static/players/pink-alive.png';// @ts-ignore +import orangeAlive from '../../static/players/orange-alive.png';// @ts-ignore +import yellowAlive from '../../static/players/yellow-alive.png';// @ts-ignore +import blackAlive from '../../static/players/black-alive.png';// @ts-ignore +import whiteAlive from '../../static/players/white-alive.png';// @ts-ignore +import purpleAlive from '../../static/players/purple-alive.png';// @ts-ignore +import brownAlive from '../../static/players/brown-alive.png';// @ts-ignore +import cyanAlive from '../../static/players/cyan-alive.png';// @ts-ignore +import limeAlive from '../../static/players/lime-alive.png'; + +// @ts-ignore +import redDead from '../../static/players/red-dead.png';// @ts-ignore +import blueDead from '../../static/players/blue-dead.png';// @ts-ignore +import greenDead from '../../static/players/green-dead.png';// @ts-ignore +import pinkDead from '../../static/players/pink-dead.png';// @ts-ignore +import orangeDead from '../../static/players/orange-dead.png';// @ts-ignore +import yellowDead from '../../static/players/yellow-dead.png';// @ts-ignore +import blackDead from '../../static/players/black-dead.png';// @ts-ignore +import whiteDead from '../../static/players/white-dead.png';// @ts-ignore +import purpleDead from '../../static/players/purple-dead.png';// @ts-ignore +import brownDead from '../../static/players/brown-dead.png';// @ts-ignore +import cyanDead from '../../static/players/cyan-dead.png';// @ts-ignore +import limeDead from '../../static/players/lime-dead.png'; + +export interface playersInterface { + alive: any[] + dead: any[] +} + +export const players: playersInterface = { + alive: [redAlive, blueAlive, greenAlive, pinkAlive, orangeAlive, yellowAlive, blackAlive, whiteAlive, purpleAlive, brownAlive, cyanAlive, limeAlive], + dead: [redDead, blueDead, greenDead, pinkDead, orangeDead, yellowDead, blackDead, whiteDead, purpleDead, brownDead, cyanDead, limeDead], +}; + export const skins = [ skin1, skin2, diff --git a/static/alive.png b/static/alive.png deleted file mode 100644 index 8566d981a044283a0e785796ddf1bee5ed48afbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3577 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 LNkvXXu0mjfAc2!B diff --git a/static/players/black-alive.png b/static/players/black-alive.png new file mode 100644 index 0000000000000000000000000000000000000000..065a2201b236bc1ce19fc26aa731e7084ccd8638 GIT binary patch literal 2551 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 CUMqtD literal 0 HcmV?d00001 diff --git a/static/players/black-dead.png b/static/players/black-dead.png new file mode 100644 index 0000000000000000000000000000000000000000..127d9deaf36f651673ec8516ea8b0d24b9cd35ea GIT binary patch literal 3864 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 pt+dpa8Fd^9UKwpXeQZ literal 0 HcmV?d00001 diff --git a/static/players/blue-alive.png b/static/players/blue-alive.png new file mode 100644 index 0000000000000000000000000000000000000000..dddf7697b042499c539804a58de4fc8cf91b9f03 GIT binary patch literal 3084 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 a)&#chE`PNWw*UO^D{W?MO>QvqO#C0%mL2#2 literal 0 HcmV?d00001 diff --git a/static/players/blue-dead.png b/static/players/blue-dead.png new file mode 100644 index 0000000000000000000000000000000000000000..82a7505cd263ef1a1359767b8af84f978fb12351 GIT binary patch literal 3885 zcmZ8kc|4T+_n#Rv(Hh}FW}7|&P< zf8PKTL!0Sd@dJS%2ewuYCJd8ZX@;Qz&aA(&^2>{a00ehN(bOC}yM(2Wf8pdD2n7Dy zr8o(KAdozXUN61Yrg^Ga(Qt7z{yh{mzUDf-qsM2-g?^3;{E- z{s%w>!B7bp$`Zgvfgva+Kn*33_Kyp|SU{16FjhQ_)dMY7is1ea4@D|-3J5VVD>1@Y z&*UO`Xbb>>p}vh;sk3|%lehmr1NR~Y#(!vNCS0gM-i!QpTO0s@zX0q0PHi2z4DTC~W_ z(>HJA1tW${vYw%t04ade4GQ2`Mej0WL;sI&W)b>(nExZpC=?iW1`HKpJh@sY)c}gpIBRT<;BXJkZ_F8d;T}c`xmTLf z(Z?>^M;n-ku44?PPvB1Na6f^;?pp^iZZw> zjNTX~qe*~;k1-z^ZGXnb5K(dxkhWywR!|FjXT_M*!7aRvJ&5#-G#N)ClOVBi6KL`% zd4N34S4J9(nH(cihRExJl|==4w2Z`fa%_yF+OOm7&+}7*T^$YOWkvZJzu$?A zy=f`B{j{l}B!^1*J^mIk@C)sg7YKwrurM}s2zdYJ8#gO_u;7#3qaXSJ=_ z?S|grk5lcNK7dCnEhxvR`fDs?e(P6D~w4!A^ zScn%{=b~;)*>vZWnoNjQ6>SAjfxm_%_<6x5@%7nf`1tW{0JldV7ebU$WPhm`J(0RR z4Oun!iqr2LCu&L_$+_5IHT5+(2_95e|>};aP^V+&fu$wnp*M+AM}HOT1#Q zHmSP0FM<_L^hYmzjZc`5?M#Ud^-znXJ#M%e(0*0jOfOZvQQbC@+k3#NF;TBTd!&LZ zr-0V}75dbYKEpQHv&1dz8I+Zo36~JtiZUCU{nvNttk95a*W%XQv#5*8!!0fkv~L5; zYnt0jp1GdxP4?bR57fY^=iS8+r<~TD_(1ukQ43KY4 zi5%)tQpU(K8{>b{MBMR8FNXWm+wNu8Ap{ocZYfCHR*(I8VaZi1YypHI1)Kq{_QHzr z4{ag>iMm@%A{|_@sdlU+`^BLO$;NHYmG_!uhr6>gZaYf#iFLu=YGyLs@Z0>R{vQQm zfD4BR6ZMP2555Hh%nLvMTD)}Vbg|F@$iNzl;j-tRppW16zV@su6bX#GASYWn<8ave z{riqg!@xjPn(>}NmiNaOJVv!MDA~^IUgdrXk6ow4uMo~_UX_6;?$*xSR8erc$Ww4+ zBw$hu=1Jh1-PBPD(GU*xTXz%=mK(qR__s^vBiJWm_2@y|{-~fqYXH-nQ(<1ko?+K? zaKWl{#gR{tW{~@rdr0^3#iTrfz9EaGFhQs3!;oWK>gS~FXM2H)hS+QMDk6_4)rMFz zh{>}JP(jZ%<}8&yoKUFl~tcac+s?ZT^1 z9TCh)*FztdW1T?1;RQ3TEf6SFQ8$Jvo|bij^<}z@wE_WL&Ytbj?y zG4H3%S7;OMU|_$3Rs&d@Ks4H(S0$!DlOBJqvPe)A6tq~7LXOW{k>vNhmGVklYo*4< z@JY1%?Hz?}EL#ZgFtmup+)HitxmW7<$h5aHX@XzfbpWIOQc9^shO8UVqXt^3ZJ%&i zPmy6^#eM4Yt6~XzZA-l>A3=B{5z&NBR-q7w|5`7attd5(e9v5E2M2vLykEo2ru*A%kD9im~W%q9&qjMy;nP= zh5isy%E9dYJY%6CFz3@!wCWhk>!@I8P0$~sd6o3Ac2z^BcD`IIDpHMV7|PrCvWB{H zMI>JtXN1dk#T+mngmLxp_PslZE)6AqIUsH{{pBe%zi@nWdjF(!Lt8mQvt2YH;tpi! z@Z^TElR;ru#M@iWIll(XzhRR_B*LVLKZFA0+CXbHA&E3Y{?@Msx^iH{lXASoUg{Dc zBzt*>CtT!0&+5~C;BLK|vCvIfgFn3#`Cn5f^eq#6qUL=DlaEL}&WMOKtX&5@_^eR3iv<_?N)#dO&*pNIBRZ}W-^ z8P11kii)29)!^O>r9g({4CmV)+orb(6^cT=35zCr2~?U0j!Ps;O_e{znVZd{zWiXk zc!G0MT1Cx6K0S3dZTN*z@?Jfr-|S0>HgTxBhI6wkVJ3`g8>q8r3^)92I%2)9of?v; z;MgT(0@Ove*&^)@13`R^fa>BFxP6*awEW-@Vx*5ni`v7*{llijzlA}2r5(ugR_st@ z?TGF%IYrN}i8syh-Wid)-72CJx~4-Tf-l=j)IzJOXz`>^9DwW#R=1v59t9BD^#i8S z;ex&(M3f{{Ti_3?<9st}qXsX1UM7_7hF$!s)%;H4oMvg2NV&14d-L6kNmzQ_@Z3A^ zOF(hzTzWmgbHuTExFXEwGidv*;8W?%5_?sjuJ4?c$+O0%O~z{8TdHan(U4g9#%j&1 ze#QAt+Y%Is@wjw3JFxclM_9185Ba3A*;Pz*q zkv2s|osvvqJ3J^PADNn~>>*HBv9!MiCwAEuCDNc2ez#fO`_RodH;X5peh?gRuYq1g zNml$z-cani_}E|vcgXK?s1Zt}uJ8btbk5F?pGv*B6geX?aot;g)<#hhHyZ&dE&Gko zTSk65DMIL!>a|H+jKq`la1u4%P6y)X?Rab!Se(Q074?g{Um2c4b*$@l4E-PKEL@){6DyMuI(EZPM#%jYRPBVtQ#B!!%B zg&}I@IwfD;?8LOw_;Fr@+uEi6jtnmJipH@YUe0j3>19tO6zCNOV zRKN$?VT~yj)?Z)wWea6?SQFG2avs>q5Ug1iwp-vtmF;)83>|o{vS=)NJvcBYhPZUI zMlnTNw}$I{W0{tq$X>a--v8Ym4{z}pGREOunmtF&IWluE2Rq_khq<85G0yatjjsr| z@t#aW8?ZfPrQax?UwZk@OCpEt_;qDREK+ss?-(v6%^(Kfrq~p5#hr#!hIO6eE@~6J zCJJYgcdUXI?BR&v$2(+`X9x88D>JrI1<%dGab+2-f+E`xOV#YF9F*w1FYA@9!FM@e z*AB0qfRh~xEdP`odB5+G!Q6O1SWf>alT`2mtrDtmF8uIQx3p8@pLG53JA^O8TR7t* z9zs~?+T6zB*Y`>#iMj(nF(CqbC)LzZ|K@O!Dfz~&*7HF`#!pWO^Nqbt@9x$RKK-?i zQq(VvO(F&bjjlCQKh1T&>Esf<@%qw-og?7LK>Z5#)BwXi_^7j^zk!-w? pxj}`rA24OwTs+xI&#IZ;;L)itp3?~c9{hcFvM{kRZZYyo_%~xheaip< literal 0 HcmV?d00001 diff --git a/static/players/brown-alive.png b/static/players/brown-alive.png new file mode 100644 index 0000000000000000000000000000000000000000..d5903c5566292c51611713436c003c060dc6ab7a GIT binary patch literal 2860 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 M&27z^O}vu-2h#GSY5)KL literal 0 HcmV?d00001 diff --git a/static/players/brown-dead.png b/static/players/brown-dead.png new file mode 100644 index 0000000000000000000000000000000000000000..6cedd6af995cea28e8976be4646544feae007bb3 GIT binary patch literal 3827 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 literal 0 HcmV?d00001 diff --git a/static/players/cyan-dead.png b/static/players/cyan-dead.png new file mode 100644 index 0000000000000000000000000000000000000000..515b339bac013138c9f83f61b5d1cd1eab10a350 GIT binary patch literal 3855 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 YX^iRRa);%5xL@Ze}oAB zQd{$LK>&cjn=@o*n_uz&1%dyy7-o-^NY)_-hL*k^lStAo;f@MGg%1u61mMB~LO`Gx z1f;77BdLLLDgt0Z@dPbFSp>uqBXk%ktRX8X1&5NfpthQ#!5EOCviL;}gbxY|M~Kt4 zM9&`uN`j#Tb1-BhSB1F!j4#_J(ZDhgtLqy+mV$td_3M!+%#Va8N;in3x zs))F%fb=DV)eypHctmcAji;~v32Tg=A;KRGBgyA>aBn_t3(aKvr`|NSJ*}*+i3mi4 zw8aa026I}w>6M)L+tn^nm#kbp@g$0zifU5z@9uF|RJ3#;meL>%F`OM4a^h%OZ4=l? z;dYPL{;$0a;~XhY0O8~MBG!UZb5GnQAnP4tLrVLTWzm}Qh^=Le%G;jjS3{k5>n|6w zyw4EvKc;H}um2Vym1z_W06-FngpHfI)~uB|n!GT77ioU$UBF=S&!9(kA%WuDNZf<` z3zJ>3re$Sip0KdF4i|J-SZnocRC|kt1NJ+un}wT;mCCQFT=^peZB($OhtD538ujva z8ug%CgY{+QWXajXynLV5a%+A@&0E?1&6G~wzWbYENtZvIiCC%4D|33+wo!pNK{mW) z=f(B#(Q>J|TCBu3&#E{2^CEGvP)`5OM1xIzduj81&W3UJtMMc9AQ=OECR? zsn=)%PGPOn z>&1p`Wd`C0b0g_RJ8T|!`k?p^& zC#JmaR8>4yzk9-C=<5tUx|6sb1a4cTJ&mpZ&GY&(b}t% z&YSUlZQHI3O7=8jV$wyEY_nX{hBbFe@M%U6$aUVn!sDzajI@XlznNIu(^L;uT&;nG z{MolKrMG2oQ}R7REkNPMXNvgq{uR^f?2>Lb8M`aq?G|21VwjR5-HCzo*9CfSA8}RZ znsf4sm8nd=;>w6qbMpG^>{pzp?VX@4-RZby^@PXL{(QWdr;k|YpfK8keRjj_O8?ZC z%9`T(?#eG;93nqiR0w?X{+R0G~Co+rU&&Gb-Bo^n^@l|&%Sjw_138dbVI8A9OVi( zae7+kRHzbtz?678yWK90QE6Lx`4x&W0&xA9NE}{z1=O)!yDKIV{&uSx{3m%1dqhxr72>k91DhpvQgK*)Q>a z13fK=4J|BE5yikzCV*RcLny6~lR#v@Ck)1gHpDVkcn%myyd+cRz~k09AS`hPo-V&Qrn>F zYN-^q(b+~aq5+}XNHn_`7r}h8AqIr*l=cCgJ`y3U8(li2T(D3~dF}4db>`kT@g~gG*v7R}P{4UD zn4ClJCtpr>x@fh~4)^A`!Zg!=xE-eC9z*LJU!HpSNqSv194e7B_^AF7r{&MwK$1<` zUn9Hhf}id{X&oaTGQk}w>iU%}CUNJQ*)bG%D20_npkm1CBB{}(ECOCx)#d1qfxcr_ zN22l?ZnE6r^e|~A-6(b}?Qr-g#?g_gwJ3g1mwX~BGzShV%ASlWSwG|KBMKXmyEO9x zMfq$cNB;&}+X(d*){ebVWvM8-(-kN;Px4wcj7k9RTw1LMQiPtb4?cZ26Gc|=P3a&N|`@uOp)*8IY(kdxrs50}2Avco*;pIRf-V&n9hCABr|`S`z`hyf@diO==k8NJZXPvSx$eZ8pZzb49=FP)doh%_ROZeJOn)yn$40=4 zeiIh;-9meoTHD?c$!wFDCL}?WjEN@(NLq0#y$c{wqV#2j5eG+COZWBO_|=maUZ*O^ zkft*|C;ki_M(zt1;VQRPbxuk@>Gp5L!*{P>J-Mo;>R7eqZ@AKRgGs{QXVN=;tvd*N#3ITLxZpzR2jnEQR!U z*lTTmEkJ$<$(kcoIbxr)^NzFYY?=|Yu|sd7Z0qvB{7`vRJ11L!Ua&j>bpRN?jNQr` RDC_@TBhiLJcx2_9_Ae=|lkfll literal 0 HcmV?d00001 diff --git a/static/players/green-dead.png b/static/players/green-dead.png new file mode 100644 index 0000000000000000000000000000000000000000..1f5e6207be6eddb90ed418ed327ffc21d61080ac GIT binary patch literal 3872 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 N#lp;%*kt07_#g7RVW0p2 literal 0 HcmV?d00001 diff --git a/static/players/lime-alive.png b/static/players/lime-alive.png new file mode 100644 index 0000000000000000000000000000000000000000..3c3437d096cfd2f14582126da06f2553c968f096 GIT binary patch literal 3060 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 literal 0 HcmV?d00001 diff --git a/static/players/orange-alive.png b/static/players/orange-alive.png new file mode 100644 index 0000000000000000000000000000000000000000..be2081275ffeb3d07be2577ea2523eb5dff85bb6 GIT binary patch literal 3185 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 literal 0 HcmV?d00001 diff --git a/static/players/pink-alive.png b/static/players/pink-alive.png new file mode 100644 index 0000000000000000000000000000000000000000..d07962de67f7bbfb9009f8598809e923bbf0084b GIT binary patch literal 3305 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 literal 0 HcmV?d00001 diff --git a/static/players/pink-dead.png b/static/players/pink-dead.png new file mode 100644 index 0000000000000000000000000000000000000000..7a4452990bdaafc081871d259acc82aa1d8b17a2 GIT binary patch literal 3841 zcmX|DdpuMB|DVe+_ZD(l%xvy+oy?^S!^|btDq^`amn6E8TymZ3EOQyLxs?`?$R#3F zqf+jbbde$zz9FA-`JEm;9>3S)oacGHp6}=Da$bMEX>P6#5~7NtAP`8xk$@)w-@w1G zhyZ{NmO;TF5dXHDGuaLZzmvNFP&u%yrIaOc zFOiMOY_ZCjb#1KGuKg!Kh^Ud3tz%WPbAlJXF7ab;m;6R4IfZ2xgt zk0MktDdNoR;l?t(y#FsAU_+GD3WH5@sqo^Q-5EFYMAXp^d z%fJ8Vcyw$XHmet33NX97yT)?H|K=Bylv2^uG25$mP}a~3?!e+rC~Ih6*7XNu`UkCn z7G*<|9o9^L>kxne%nd=31WW8wQU;E2az+4yGBP1}`+J{_Kcy5&RSc`QNUJeRqGlA> zdHIIt6qf4cJR?;3#HRpCe;X=*2M}0|eVRZz@cf;D2Vf|`?^RG_4Na=)8ERp$tlIlcIjzXh#>0QAKL`P&8s*is?jzdJF; z6Ov20K&hghrygf6au23Q7gu;6^zp@q8>$$)W5~|?Tv!96fZo{J0T?OJntERKVzySc zuj-LJ{foJ64|QN@Kbw%Frk(+|q4JUnz`B5@O42YO_k^X7vyq#vj{SM2Mi$U}<1ESb z2q^Js;!t8zV&ao{NdeL4Nsk8;p9nP%_9rE!$k$d}^uhG@+^9~>Nlrp3wcVg6CMJ?) zxB5F;n#}dEL{|cBlTv z^)gm*PIAKONZjV*zMk8+IBXV^d6k}@k_0Fdg#H%*yRP;$?kS`VQ;%ZAkl6|yfv9R`>oi~ zd9S;C(y7uq*U-gu%+Woluv&NNBMn!^Gc!%nYYA+GBXh7;i;O=|EFy>yAu&_;3+ANT zAw?O!&KSI>jI8AB%s~bHue9pjOJnCxEZT_8Zs|R(zPwzvyS=;{()rD5S5PniOSsfX zW!HdY#m%;ym4Mf{x_7+dpIgNS;_uiPhFRspbd=d?8f>Rjr@Ayxb;#&rF@CPB(%#_O z5jmvKTHTqssq+3`&TDIe({Q**3oD2B1wG0kYFOjwePAXt`M`onAGF!?tUjUV#?>}- z2Hsr+BXp==xu^4v*->Y^z1ONwq^2n~+IgWOwDuT&R^tjuv<9`7&U$?ugWyPo!ys7L zc@fRwp^K-{GgvfMFfIyfOVJzfD!Qio%Un(K3p(t&XavWf_k3mDm60gO&@;@G7i+G0 zyWSXZP#stG3VWLJ@>>MYUgs!{e8T9ycCnM;Lf|&DU?w;HX5QrFaf@3rgp!i-i>F7G z&q^ZCE4V9}XR%TSoik({VwvYlw0^L;ZovzO;h@KogzW<(`KzzxOG>f$sZ9*&1=L1U zMmtXS?)=F+L+|EV&Pl0njCCDFr8avaetf^SL5|eVuHqOC_A;e(#SkrUb;`E?>SpG?qTvv#g>c`m!3H9WVE?hAmY5&5X@z0Y;?p&UC@`dO6{-8@_V^|GFrb6HKoN=)N(XM zaZKhqKR_<_(0Okx!@QfQu{68?8GzEWEbG^*%osI7mz;d=MYhwDSY&ilDDSAdJ8y&| zAUqU-6kJ8*4;n4PRpE=Siu!2usf!!mLW#u7+ulSUQ?CmuH`SMPN4jycJD(`u8$SA@ z9i{8B%XjfS{+x(FzRs@BPR60jVc})0IIBZU!QJgi!4Hj|^Nq~ZclT>^+X^x6D-$P4 znaDbGU5;-VM{h~p??GfxXY9=EcvV&lF`}X?43Z-o`^2a!M%_>n_jCMYG)2++K2<#$3zdgU3SZTrpV29tF)2~%&e#*c2nQ4lCLuUJ4$;aJo)UmC`Lz#~K@t+DYr z)+o%s)fSnchw8yf+wAqAoRS~Ce&y4-1s{f@ZUNDyIs={KjnBzrAv|t55JjvmHRw2s zNa6!}@4ZV#?W59!g1D3{6fPB9FO$7m`P_bdl_D!@sx9_WI--tPO|sdf?8N32Ex1?9 zK5z0isK#%j56m7-ORav!SWqZA##o&C`5SA({zLT3jd6IEtt)ftk#ez?H6vA9DA+jA zV6`C^KYryHT+HH{#lQkSthzlC1tvR{qlJ02d#3UjA-><`S* zpxh-SQUe!O8$uFH`UNjR9wgzjr9Z}c6`2~d$@KOd&O{95ftf+_&YLc&{i0$PQP9Yx zwOINKG6cs@7oEq2RG6f*Htg*%yc*4zG3D)_ADpgC_`&k>^G9~R!(Z)dn>dCD=lqcC zj45hzr)iNjQ~lLlU?VQOxwau^4+=ZYBCiB$Ja$ENvNf6oZ4td;Bc2x?;EbCFgj-_t z#lNAFZmIR|%;z=Xgs7yK(-b6kw(lPDk0vk7gBTA+Zmc+E!5oqEN59S-r)~x2htpu) z6}K$1_IJ6eemHu?wO^$h2} zv_^MUpGyI;k*%tc$c1&}W^%q%MoXv@UuQyphcYi}z@$fEk4YV>S*)OZCKXwpqVXYa z(E540TY9)9)BE?>%~xp{*+IVenM)l8G2xZ5yyn;E9k`q~IeqC|?~X@@NGghj9URZj zJ;^2A@^XeH(h#}z8C%lr9tBqNwAYK2(i7bqc5AC{3a^E?M>;MvoC@ih`u1fQyt?(n zZ1?BxZhnYGnowQyr!yJw4?ng;c&_KHqaSJ$__KGtZ2Ta>GPRECjusUWZ<7SEGdj!_ zFyyuj^6VDNwXS+~4;Yp)tK+_CO?qNCRCwij($gC`xo-jqtUP~+7ybRG3vY`|nUSt} zH3=4q)1@-VLQOxLndYRH@dpO?fqn%+!hFEK8t)pZ3NepE%|{=o(gN;EBA=)GLzFI<9%p6l z&vKupAvNwjp>O*35>7y%0W}2vfk(X1`mX&B;WHT{l-3Ec8U;$wo2|2jQ&j;Xl~qo@ z`!^yPHLqL+j^84DG$b!;3`>33MsKYIT7VgOZuJ7iCCa2uVd{Ijoa6Z$GSJovzAK?> zVIFZu3X#b+$MpKRvaMRE0RHj3vqt;|1wGO(bdbP2^qwu2Qw>g&a=WA9b!9)2bNq$>#7#%5mOZuN!*E#W^ae2#+2x5y`PDtO>-DSBpLGlh2rha zMQsKylrUphB%!2*KYrUL55GLGIyUbV<>L3sO&AQbtU?ff$Cw>j68v4h=zJjjXIj-- zI`Y|^A-%i_?x^wKSE1KF5=*Ch@eCf)h(P!@n3s$_G&!lt!*m32ZlxsR=ldUt&W9iW z^%1l$#B=<18q4N6o?HXh_;j`M$u!vFu?yH=QqCzFo13qhDe?v~>ZRxZeU$PZ7NJZS z6pyy_R(I+g7x#7aahw1#RySKbo|UKUWJ_z$d>y{yJLWrm5}WsbeHxqEaP$~M@J6-=B7W{qdcE`^7d5ef&b#$ z;L4ov#MUyAm{{=GiTm;ML|C&~gEcymM07E@!I8FYuOnAvUtfZA+=BZ99kfFxH0w#` z!YDmU^19mRfLf@103tYax*ioTJ{{*!ORw6%dENfC%boG^FFU^a*uW#<1~=L;-%nN?N*C5{ zSz7`>?yLS&cHqw`Sbx#w1u=Qw(ycci31Un2mR(1{{geDz&wQz6b?nCO_O*>Mg@XJq z`jmnDn_KI({L_V>CWb}_1|F78EnV7U`h(vzN%#^tcq`6!!4KHT!E8+8Si-f{Sy{G*v;arfoV3AR9Gd~hBeJ&;; z*skuwtB2nHt(ht8qQ3B3C0002W*jYJQ{E7d@aQz#Q|Ht?rI5&{T5FUR4)A8rJcwo}XFBk~qF6y5+ zJUoPO!@%57L&OzJpP*p%RwUGl2PmK_;%*=wBO_>nJsQBx1$I#^gn^aJrKtiSgrcxL z0-`0tdpr>R2o3WV=9LRTH%apA@qod03O9@-qBM_&z`zPn-edeAF)+UXCI1c%e$_-e zTwC;_yb#e-<({;_DRDlGIOK$nYOSkMiH&@wp7<4q3lwFMGmgkS9kFoRpi3B-Z%Tcu zyHcsW0$oRpf)RB*0V50XNbw6nuik6$Rc-K4F1MD;Fp-MJNd%j_d8r-o)FD{P3*#gN z)Mb=aMI|J?PgGgTrh3FC=pXaL**a?A%}(eV$UyZ(#Nd3~Lb+Z28BLx3YK_K{m#zIT z5WRej9bHf&CTa$!ps=I)JtH^TUxel`3C9zh!=m)aHcDDL(n4Aa>Kd`7RY4ha-z1v% zwN#R9vTFqOB-{fbBS(};l0+&-6;}jjGSuQSCjJzSi*&GY1pF4{IR%{H+Y`~;nCmua zrnpEuo<_;_pv8B$Kh#TzeqDN9RZPDYY^|p<-TyeB>UTTs+}V+`E1{i;?Xh+r9{>Pi zNHRBZ3YumYFQ0>*mwL)0YEPMaE2Td+l>6QYqk+eZ_+`YMDJ&|gY#;kr8yxq3I_@Cx zSLyPa-p!};54Uhun@V{@De#NUKoEaKf$!d1Qb3W9ecZOdcWs{`}$`OaipOAIJ7jzEib(rf@ zV4o%OTIwk>RJiqevS(JXxyO(6SD2<4CRvsRs&wpoGV+?)_oB_q+4hvA z7qC{LkbBKuTF)2Wv}O9)H#F3Fg5P#qYr^c8y6|O_uv`G+gM@%1DuNnt&^zOWHfrO9 ze!*e4*S@{j&YuiGCWahw&+})=HX35aDKe}VX(gA%myMsq#Z@(N_+GGCfiB1Ej9)P? zmOT#%zs^g{_O&85%+aj845OB57j`QE+v9nxGF?w>$qW7Guy#?lg29aOt^n%eBQe1 z>U`y8Ge|9eS;n;TK3@^p8~8=#q&f-Q`K_j=I$@h* z;%1##*~!(mjg>b&pnGbO>PbOwE>-Wk$a1Z9w{dL|fEGwO3V*Wi9=7E0&9~w`h*ZTM&r1%H=~oDUcjYWcs_0 zQ5lRv=OE?Q?w3JdJMZ2GKFDF^v_^EhGxy5G zx*hif?L0jg?b!(3g zHu#!HM8GW~v~;kHzEOY-^2#8IB8J?jPwQhV*_!twi>g zU+mP|jfG@w4gTG`?5^$^8u|H0K=6)RcxG4uVrcPFkn{~ix>>FN%>$-aH)@Ew;oDd- znYEO=P({7biyeG#4d;RD*c{(-!;P zwvU9+I43j;W6fsD-xq@l7fUjK)F$%JdmWInqUa7|Q*1Q)$)N5g%9d zR`fH#R1}B&pUlf&7m3=*H%e@JfZbZ&i^hZu;RAX5)iwG9C>hJoXf4kNcPrn%$leRklB@2h52nD%|>k!!bTaQ zJm+dL0MaL{$(x>hKz%)Pxqv`;9kBG7N_{+n)6=Te7`@KKl$`Ma5)HsOOIPjUx8g(D zJa?kGqa+E6eZ5Fu#6_j zl|U!i)ipTs{6NYM+oL}3si3RLSj2ENsr5MWrQ890Q&SmVadgCgHVI4P@+S|J${LaE zLb<-6qCPzsU#+{8aJS?YAGG(T%=c)j*Yg&4z4XD&__iY-3G!QyqB@?yU-nEdDF#cf zH0~fez~WzmYcA@X6>9Dz2di}>+pKKD6UG+2A4Jb_w|p_>zTxcu=-oWM5Z^RdaAE49 z4=daGGqk_#HOOt)B={t>0+I8c1n|cilis}Nkr!VCxHu%+auD=c0CcN)UwAV4CnR&` z93qGG@?CP;IaJfc#6%L7UMNulmywHLpYU}HCEff`BCOI*nGD01uLWpH zU0!F!asf?b4%*?FM=a;$Vp3&SJ!IP$>+xl<)QJ+1gR;?4NeMO!SfXYGSI zOlgk1w=qmt{bA`7O)a8Hq2FO!S$$C;NPdcV(!%oxfg}mBn3jamIQ@2cyz<6G6|@w! z+F^g^;mt-vaVMy@SQ+R$FRlNT$}KK6+A~S16BYr>k!qmyW3f$3fzkN*fzYaY{IDF6Up(x5UIN4 zntGx`%9L%jQwnpOO0F7zKZ)$B+1^QRhMqN6&_EcHWMhr5L{8hDB;~o+>y$ZLT zX!zh7Ctbvb->XPA^<%6fkY)2&3x-tdpECWmA5#>vx@V(0%BuR%sg~ZQllN`N`q@;X z1FgIZBl_D@j}fH8#CnquagU^KMR~)6Zs9r8)d*6;xr_?_kEpQ>`i&WF+Q^_$A)PLA zEMIy0c{GXKr0HL$prva)r!z&rXO<4VpOp+eAi$(x-M;5|y8>{!71JTlgsaYwQA9hI+VIlz46=$~oPw*cA0l^R&c1p-XcY%S1 zt#IO{FpHKji?#x%vl4fp3YVuO-0qJ!DCa)jg)-Owo4T?qgoXo3%R`|wuKsQ=1T(oN zT;L|r=pLW)M@MN008sHV%KcYnh)TGmt4|4a>|H!0TGD$*uLVW?$^QEFi<3nh!Oiz4 zhx1CyG+}lAXGWv+^bT%Sz6a zT4pE@AGb6EJqzVZvKSMJ=NFMciDOV0nSzOzYKl%NkICGe;%Z6`loVxLOi(TuBZs<@ zvkbb`iBqf>< zM@Wo^Om`F=*QQ1bx0R6y2>b7w!iCYNuxG*m-HH8@C@2z#VFy7zS)!tBFUtJmf^Z3W%?#5hqb3%o8pMQ@S>7y@$Vn03pyfix6P+wJElA02u z=s9Kb0ssIf;<1_*UTdEVuU|pvA)<$N;fJtJU>F^*&WD66+kBdlmbPBBpsEKnu2|D5 zG%gj39b9r-^ztRPC~^W0#tn6A91iYmDBTcOGA_M zqubcX7+z^2ZRx|aV6p2#^l#H@d-(1a>&i0r;QN5)7d)J*D`!NNi|fZk@k6u0MJc*E ztP86KS)&E2e|rsQ31iIXN%YCBTQUh1qN4)10 zSvlZinSdQW-rS+uSY49((T96JtbD7XO^Kr_!jjKghB7Ux%W^L1hzLGEs`2+)={Y(+ zz1WbOmCyBX2!GnZh9f`4*?MoRSq7xw;~M<9tX`E@D@J;A_5Vq{udN<4CEfu68n<^p z5px3SD=RN>U$3i

x*t=4Eu*TQmb9efw~@?&{~QX+m+w4Ye=-B(&`{+FMOopJ3YQ z*<_fYh1uEvWHFO_wlq$D_z&DVo90tjS697dw0g9Dy7lVXTMY=t-qpozHtW;Xhx4Dx z*R2Sz3d0nKYWO;s4f3Sa_ibl*dW`#D_tSc$+FxFthU3lYxI<=G3m2q>Sfr=y$@;!W zeIW*u*P3?EzMQpw;#pm7Y9VDIp9i^nuYufAAkYCO!`CUA z_HMs{WQ10tR4{v2kH&=Y;*Sz--btx{dLa@wEVA%wMY(P-oDBxS$?(oYrcBfM!h(eb zgMD8=zngDscUO)_(@GW{)q}itUf3nwT3)-qSQ7X6DcPETt8>DSt!S~y!A?9H<~x!( zj3R!&WY-++Iagz}L0InC+q7_2J9(xjVb%!_K47!8Y3aAPJ5lk#G6U|97R??(%8tKf zeUQ6AS9l8{rtebjjn+O~y{OzhO-20vPR)%ZaoyA`*Q!A39^R0-@NiwFN;Niql+?ns zB|De!X87jk=cUg9z`4~j5+qV=I1n5^p2!7*{^mF zpR{v+pVmBxF%50xQK)jnR#x+T`%YwrUQVV1?K-5meEj-E)3hWB#bS6Q ztV)XQbrd!3^7x|uhcbiCAH!&@s-ZWlPf62cVMTgtWZrY>UvBe)F zwmtG1i~_}A(~(S%3dIMh@-Y$0s=`Jm#swMWIU%yoe9CW*k;9TvwprH&du)((H`>XD zBKX&&8WgXS}#$rK*R#^nK!_i^&f$%Ni5b4II|yR&G)f z_U-#ve+e?A#z0%pkWMRuHOzCv(1;OYvNzqr@xUpZ?Ib@$DRhWs{548A5&74fNVJUz zc)fUiYtA~hyUqNuDy&UdM2{ADDa-BI#UD?bb>m!{t60(EbQxYmsoEAA!2wfro>p*C zq&%*IJ{7D$4wXeItSkyb4_AixMzkRAq2`?m97H$JiS)6G?%VXl3QOero8|AtC}MAe ztmH{V=Nh}GE^v%>2m9$uGGLu1V|(`XqbL47Ukh)C!z-R#g9k~>kVkPY@rPtX7Irq(Y#MO zIG|bt1JVGAIt4ys>$QUG$ivBkMNMdy5ApVZ+f7f6n{u#PBgbQvdKGs{NB{yqX%^^! zXQm?gMv+1?BNz~Bj4SU)a5xNAnZ?uwSG3S{`a$N@%?*8|gn}A+S-^D(j+7`hK{ix% zBzFv}axJJyWYTOFIgITH#Abd2?PvV(LoweM+HUa`7!&}@=H&qxaAlkkIMHnf(-Z_) zJb%`DYI8)M6_i@}dP-X$ZI~5-H=DJjhuZ8YychVI1|X83_hMBtms>@#?rP;aH0)XM zCVS7hw-ONpOfYb`;DW83uVH&OrhTR>gZ?M!4IIr-dL>YDxkOh8CA#OIi${wqlYXdQ z3H&Pacr*}+y~=|t{2Y$6py{r)=f)%V?9m0fhfkTA)W(ovh(iAiaJYo(a?zJGbFwVW zexreB_wFbR?GC5!oyp8G78YtrkeEF;sC*o)H!<`hMdAzoZ!GrnwgkJ>`+Jn+Ly@LK?ZoX~jawMS zd^icB^eI>*oHZA>R08~F`Fcc8AfFYK;~#^Tg@mcX%P*e6{|aFMCntZQeif7@C~&q2 zy3NXthf|m73+rp{XRjY6jh{Hvkv~$U7Ukt}a86|qg%lXyI6IxA#FH8I%Rcb((nB(; ze9#O#%TzXSpg}gWVAI`N>xGb6WJiDsvo5Jr2tEjj0K4xZs^ZZGqK(EcL?tbGe|zvnfNS zKrb_*CP{93DayJm>LEt*M#_f}c|o{`yLn>}RFEwsL4(U~tCx+BRbel4!M^4Ym__hZ*U$$PQCyLBIvo(6;qj|vBi*I{ z{Jc&24M7)uyr0gqsB!-NG@zvG!q=%R=?jE=nT z;^lO{wDr-L3u&uy`R9wT!**A?9*#K?fQkWY#dnzkKlM?U_IYKlr%(qBe(|E=q{nn8 z$9aWY0c9Gmt(|NJmn3p9^}>dj)=T3$_5wT45lm)o44_+v^4R3DSrf%A=!fB*XM MI>y*WE$7((0fQq{$p8QV literal 0 HcmV?d00001 diff --git a/static/players/red-alive.png b/static/players/red-alive.png new file mode 100644 index 0000000000000000000000000000000000000000..6db934cc4f1b99c664516d9e848bb92cb2e74cf9 GIT binary patch literal 2977 zcmbW3X*d*$8pmhMYA`dlEMu9mn=xaE> zSt^vJ=ptFlQbvkYc2T*V=YF|g&wZcg{r{i;hu`yl_mB=f5BL|?h`@5lHo~P=5M`%f=5S3 zPymqb7g#(vApnH(0YOYC3Cn{#168$#$SLv&iUASAK;CXNItG3s40c=tbgUAI5(Wb8 zAqqSokS7!$30H~Xl|}<$K`;$du=E2oI-eiSLLeYem;?_`B%ELjmU@In!w`IdFm+$3 zS^`4+E*g#D;n$(r5_An*p(-ap5=4-wEDsMOC>$js+KNIop-}dLArWwGVM&ZCNaznf z!5n`6L_R)U2;^cxnYo+SNr-$s5>+gK%H>CKkVr)kD7EFj2P@GfJSG}Wwu0acz?fPj z@}>aN6$T@N!3ovPhIURG6soKW!5N}t4wg;l6AtC&r9z>`5XkkOp^Ww}zoZOfhKrJ> zb`-CCBm(gpFRv{WTG&5&?XSMz?83mzTx)Np98p~YC$9&Vbzl_=OdNc+#z-gPY3)KQ1ws)@AXq3@aFbPY%BN zjAm>+u3!cNMdteh4g4NQ;ePfqlySZ&jphn4hjpt?s$3> zb{?x%NAj_5@oToemUkGEgR`%@*SPpJeTN>^VlrKP9^aO=0z?H@J)rBT*l=9Mxir9hvrM)LP2rWv zT_X`ieK&={b%s>WO6Prcd*R!+nN?MvKYy8_45j#J4hxcVS9i8j)iOvZ2Y5B^BD+*Nj=6`DO9Le;!WcSe2i- zsWGp9V){<0VFG;4<$UxIh|FCsTce}apH-N0jEzb|;#^V^7RtD8*ns`2n+I9^T1=2t z!MBjt@=#x~>8%h5Mz}z2qsCpD+QHSD#dV8oZfUJyV7*}>#!vEJ`k=6f(Uhwt+wUy2a&p16gjS&5pK{wjJmu6z`@iJ)2*>1Mr7HNM+zetKiQ z$n}A|zm6&I_ts`6m9$%Cd8X$Jz$Xk9y6Zb7yB9q&n4vV?sP4Q9of(@<#9gre6k=*0 zdbAH;W`ff0hj`D2$GL&Ob~4=Ts7f0BC6N5(4*K4WmIn{FHcT6?e-!B2GUJCe68%}iS)x5CL zKteKOaE;bN#~am8h2dr)q7M3!QbYjGT!5U>Cazxex*%;}4+dwv(*M~9Rh8`6+2_@s z6!#u!)}V@MgK5V|??P8a7do$I;RytjqD9AAmxh-!u*_A9<&BAs~;&Fw5v1g$_f5;JSqOsRwPH;VpKyP(^S8&goOWvnIXm)UV=Z9X7# zdvRx%YJvvivKTY2C{{1ZvAeQ}X!wkRz3R#McgWZa(as97UWKJ)I~Z-O@|9@KC?_S6 zTPCldtcxyQz0fFi(R3{86o=mE9Amk&qW7n~>yQ3aT&m-c!|)JMA|+@ap+aDko5~ro zCneNBNMjw8-B*W8M;byjB3eEMvnh~;4HvEBv`0jMud_$+xA9ZPf#iS9>L;wV`Es5y z8meX1@LI%ZDDQ|`H6KB@8w!`{MDet2cvQTW49VHyVH=`(bP>E4a9;hGM z?ee?akMUI@% z;ErVjrxaG1>?K1YKtw3xj^hfyo@8;_C4lgqkT%B!$3M zD&p8YD}5{M@!t6!|Wm{@@)7{Sy>SFf$_l8GbAWUj8ZzHD7kpq(A^<$Fp44WQtW zHl?CR-&x}Ov2qFS`aHd{hAc?l%o-8djlBVA*wUtbOQevjIdz_6KjV|sp5FG!MQ5m} zs>gYXDcY1OZ%f8 z5Bue^@BZv$bA`Os-wLq~2l{1S2SLq}&D1sysGEg@(T+KU&4XK4s1E^pe@J_(#yKeb P{nA=n*qOJQ`6T}bj%~r1 literal 0 HcmV?d00001 diff --git a/static/players/red-dead.png b/static/players/red-dead.png new file mode 100644 index 0000000000000000000000000000000000000000..486bf5cf3217eabbc65a01d000224f8ffa376535 GIT binary patch literal 3820 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 literal 0 HcmV?d00001 diff --git a/static/players/white-dead.png b/static/players/white-dead.png new file mode 100644 index 0000000000000000000000000000000000000000..e17c195cd38f141f25642889cdb9ab09854df213 GIT binary patch literal 3860 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 Rto-w{U}kKEZbW$!{s*;Eyk!6Y literal 0 HcmV?d00001 diff --git a/static/players/yellow-alive.png b/static/players/yellow-alive.png new file mode 100644 index 0000000000000000000000000000000000000000..c2beaa7a371926fe50b94a3daebbfe363a590712 GIT binary patch literal 3334 zcmcIn`7;!N+h6CdUF^E;x_0d@xn*7JW_PhU)}34-Lb8O&QSNoiIwC5HgoxbtnR4Zp ztCCPiRE~t|+jr)j_YZhy-e>0d96x=2dFC_oBwLspaextE006*2HYQsAV~_tXi0L01 zX?b1-02sS0Ol?U2?Em*LF#J!#|BC-};=#fB{v>q4@N8cq+SJ46@87?Bdv;9BOeUAS zdlSX^IGJyIAarCP+uJsxd@MhH*gZ>>q^NOnK$tc+t%qJ3J`4~6vM}uK+6G(k2?&5Z zNZdd$q@zh!70ZT20M(358ya-&wP9o&2Nye&mG89=A1L#4rn$K)`B#KeT;Wh2J_!j< z1UHKSj5#p(KE<25zHZr-h;F!vEWa+A>y5Z&FA!?Y=R@XkF@UiEfovcqFp!b#dU
?qKTSSErAqqxV);eH2n0b06ec4B1#@tc6xsRsKxhPOblJ1WlB%!= zPXe+FFW!u^4+?Lt)ke!JhK0#grb>HyVzMqHbaeO?6u8i6_PEODlN01ScU02TmEz*$ zg)kCYT70&e(2#X>Y8pL@aKuzaF@gdCO&as3hFO+!#McQyvdF-KM(fbQ=NyY+Yoc zzK!?$uXnv1r!9D2`Sdb^&lGz~^~Z>Rba~F|s84S~+QMLbyetfsFgSQPXC2_#^7DPf zZs$L^3E6EW7dAAQIUFSD{JD4pD_qM98Xrv`i2D8dii9hMH<@VA>o1wq5uW0wvh}XQ zTJoZ!K>IS7`|!ITN!e1UkZLEF&^^Mg`SXz3SWL1QdF_RNaDtQd=um@#I|5y~6UzR!F<9d8J)U0>A?#IchR7n`kUem+anrn{-zsM=>#)=)vKt))EP$JudVnGZxJ zXNNmr_n#QKM@Z~yl(n#cMg!Z?@&5Z#xf$p_{<$|)cQDL5)Z_bl;c`d#_@_KS1ZE;CxwkpZ; zVpI7|dcZN(%~V9#*)$~8L^F6Lc9XJPzPjWizL&Wpe7Dxe@tP;UzGrF$e&Mk|+qU(eki}ieGK=U}&xOQ9 zTbrqhC5<&u-T4+jrQ_#OK@{KVz`A8X@P$vJjmrwIglBREZPe;dhlEV;iTgRPEG>?1 znnBjyXYQ~F^!p4_lPasQQi<~*7>CAWKL^==NHoeEx+pmb+<4p&cPwmG*;#4)+0kVM|KHNks71^*8T<$F_!< z{A;YS%%YB7`B{M+_h%C>b#@3ZHF*=fm31uZQaMl==s{WukOQvdk8bHIs{h`$w3Lo= z?KYX32@B+VB%=zGT2FFm7H*5UaZ^?=ty#fMK+M2oau1u8t-Qv)MqaTn4GZuW87YYS z;#%7%j-n$8fN3rU=4rEm8YUED+ zMjMG$Mcvq*kI&(ViNW7~NW0#I`xLxn*JFRHP2wkU=M9)0HB|qdcTLz-Hy7|woyYre zaoocO*G6^W-3d1H3%8`%3tqjst?UuP$g&U#c~Goq(GAGqi69vUB-CaD^$yEEa;k*j zk2NoAFj=ZZe=Zplqyd=61wviFU=-mlb2m8A@sNs41c#=<18hg z=FFV(&d%Nmo{L4#r0p0$sDoc?us#^LvX_mLd>@8fc~WCjaAJTn9IShE#*-o1($N

C)Uc^&{o(cV z3UhwW_YnNCMn5`sJ5Z~}&c@`Hox|c&^0gCzfj=${;B==z44#{jYSqme@E0o18QXSFE|e4y13yTa4!QXTfPx5hUgyr3T{I)q#-{Y89gEtfhRahVsUQs6?l?d$DbgqDtnn%5jJc41 z&^VWPC_9_GeiqMcX0h|7Gz$aKuS8$O-PbB5eX1gQw7he*Km7Y9*%1beB+n$SrhTd8 z_>q*7O!TVb>X>oZtwnWJ=7xGzluly>zH(q?Nr5${vFHPz<7i{&IxvoikB$E54JtWa z@Jeke(t?XV(31>{r1~A*G5WmjgE_G8D6lh{H}#o;xDkif>tDHQYdA((c0sB=VB`UG zk$zvV=>6OreL_$AF;d-sKI-Xhue9Rnc+HL+y3I>#(j%mCpCf$etu{n!H|{cl1Y?nk z#$W#{oQ=$s=uk!3ty^cl5WI1_=%rX)lvZ1DA@1kP$e^{H(NksnFQ0?L47~G3ld~U! zcBayTPG*LoPBnx1-CpAl+-3n%ahl#0!ITO+KzWI;SPrOrM=ON+cZGJWEjZz$#1WDH zjEPLSSCN0Wwfp-oj6_eFg47FA7|P%#a(BI z#;IzXB_ug2ClK91VAOd<+~uxMiFi7fjpbQO?KVVA3v4lSN_{(&egQ`6VlZ))^UuTG z0hG2z;H*(^YPW+%$el2SfXHvR%zm9qr1zLzb*psJe(rxj*xp8&*yUDyPJ@#tA|mqH zx%zI_J#El9ho-3)i+w-Mu^|zD@F`unIN@t z6H{A((?cXqW9}%Y{uDl|h&gd)= z9MwjjCO*GC9`uf(uB_6Ar%c9h(AD=gSR) zAH5n0*sLp+mb&__Zl=vyY)?nQdff>x&g#Q}bZv~>^f~`wrj;Xg#a~VlC|>KQuWTt( z=Bd1gm~Z4r-}tftV8>yEH=c}myRDCIX^YS89Eyr)hFtyZ?f2(=l;t>J{O~uNcrxa~ zDB}CoL3|+@Nf^!5+t}Ws?#5}h7k1B^czjR9@b*skt%7C$d|95LM9*a0p`5&U``_P! MOfn}vGjNUl4=HDo6#xJL literal 0 HcmV?d00001 diff --git a/static/players/yellow-dead.png b/static/players/yellow-dead.png new file mode 100644 index 0000000000000000000000000000000000000000..237dac34b760c0db6d2c673cc51f0402ded4a7a4 GIT binary patch literal 3803 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 literal 0 HcmV?d00001 diff --git a/yarn.lock b/yarn.lock index bbacc8a5..69f8fa39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1417,7 +1417,7 @@ ajv@^6.1.0, ajv@^6.10.1, ajv@^6.10.2, ajv@^6.12.0: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^6.12.2, ajv@^6.12.3, ajv@^6.9.1: +ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.6, ajv@^6.9.1: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2445,7 +2445,7 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0, color-convert@^1.9.1: +color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -2464,27 +2464,11 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@^1.0.0, color-name@~1.1.4: +color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6" - integrity sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/color/-/color-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e" - integrity sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ== - dependencies: - color-convert "^1.9.1" - color-string "^1.5.4" - combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -4982,11 +4966,6 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -7847,13 +7826,6 @@ simple-peer@^9.8.0: randombytes "^2.1.0" readable-stream "^3.6.0" -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - single-line-log@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-1.1.2.tgz#c2f83f273a3e1a16edb0995661da0ed5ef033364" From 74e1a051ba0ccb3582a3fd83e63c93f4684f93d0 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 08:30:31 -0800 Subject: [PATCH 28/45] Attempt to fix microphone fuckery --- src/renderer/Voice.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/renderer/Voice.tsx b/src/renderer/Voice.tsx index 8c2a874e..53d179a8 100644 --- a/src/renderer/Voice.tsx +++ b/src/renderer/Voice.tsx @@ -160,12 +160,19 @@ export default function Voice() { // Initialize variables let audioListener: any; - let audio: boolean | MediaTrackConstraints = true; - + let audio: MediaTrackConstraints = { + autoGainControl: false, + channelCount: 2, + echoCancellation: false, + latency: 0, + noiseSuppression: true, + sampleRate: 48000, + sampleSize: 16, + }; // Get microphone settings if (settings.microphone.toLowerCase() !== 'default') - audio = { deviceId: settings.microphone }; + audio.deviceId = settings.microphone; navigator.getUserMedia({ video: false, audio }, async (stream) => { connectionStuff.current.stream = stream; From 27866b7d69b3cf39424f08e3c41ffe6ba75794dd Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 08:40:59 -0800 Subject: [PATCH 29/45] Max mic test at 100% --- src/renderer/MicrophoneSoundBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/MicrophoneSoundBar.tsx b/src/renderer/MicrophoneSoundBar.tsx index 1514dda3..894dea75 100644 --- a/src/renderer/MicrophoneSoundBar.tsx +++ b/src/renderer/MicrophoneSoundBar.tsx @@ -27,7 +27,7 @@ const TestMicrophoneButton = function() { const input = event.inputBuffer.getChannelData(0) const total = input.reduce((acc, val) => acc + Math.abs(val), 0) - const rms = Math.sqrt(total / input.length) + const rms = Math.min(50, Math.sqrt(total / input.length)); setRms(rms) } From 9cf439b7cc2f59bb138bd11132130344b752a3ad Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 09:25:19 -0800 Subject: [PATCH 30/45] Add .eslintrc --- .eslintrc.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .eslintrc.yml diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 00000000..cbdfc4dd --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,30 @@ +env: + browser: true + es2021: true + node: true +extends: + - 'eslint:recommended' + - 'plugin:react/recommended' + - 'plugin:@typescript-eslint/recommended' +parser: '@typescript-eslint/parser' +parserOptions: + ecmaFeatures: + jsx: true + ecmaVersion: 12 + sourceType: module +plugins: + - react + - '@typescript-eslint' +rules: + indent: + - error + - tab + linebreak-style: + - error + - unix + quotes: + - error + - single + semi: + - error + - always From 04d6202018928e5d1bad1df3ba83fe6c86c39b31 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 09:33:21 -0800 Subject: [PATCH 31/45] Add linter --- package.json | 5 + src/main/GameReader.ts | 100 ++--- src/main/hook-ti.ts | 54 +-- src/main/hook.ts | 38 +- src/main/index.ts | 48 +-- src/main/memoryjs.d.ts | 2 +- src/patcher.ts | 4 +- src/renderer/App.tsx | 24 +- src/renderer/Avatar.tsx | 12 +- src/renderer/Footer.tsx | 6 +- src/renderer/Menu.tsx | 6 +- src/renderer/MicrophoneSoundBar.tsx | 94 ++--- src/renderer/Settings.tsx | 24 +- src/renderer/TestSpeakersButton.tsx | 22 +- src/renderer/Voice.tsx | 36 +- src/renderer/contexts.tsx | 6 +- src/renderer/cosmetics.ts | 2 +- src/renderer/vad.ts | 46 +-- yarn.lock | 548 +++++++++++++++++++++++++++- 19 files changed, 801 insertions(+), 276 deletions(-) diff --git a/package.json b/package.json index d6bbd8b7..1d88ce91 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "scripts": { "postinstall": "electron-builder install-app-deps", + "lint": "eslint src", "dev": "electron-webpack dev", "compile": "electron-webpack", "dist": "yarn compile && electron-builder --win --x64", @@ -57,10 +58,14 @@ "@types/simple-peer": "^9.6.1", "@types/socket.io-client": "^1.4.34", "@types/webpack-env": "^1.15.3", + "@typescript-eslint/eslint-plugin": "^4.9.1", + "@typescript-eslint/parser": "^4.9.1", "electron": "9.3.3", "electron-builder": "^22.9.1", "electron-webpack": "^2.8.2", "electron-webpack-ts": "^4.0.1", + "eslint": "^7.15.0", + "eslint-plugin-react": "^7.21.5", "ts-interface-builder": "^0.2.2", "typescript": "^4.0.3", "webpack": "~4.42.1" diff --git a/src/main/GameReader.ts b/src/main/GameReader.ts index d5b1d103..05ee5897 100644 --- a/src/main/GameReader.ts +++ b/src/main/GameReader.ts @@ -1,8 +1,8 @@ -import { DataType, findModule, getProcesses, ModuleObject, openProcess, ProcessObject, readBuffer, readMemory as readMemoryRaw } from "memoryjs"; +import { DataType, findModule, getProcesses, ModuleObject, openProcess, ProcessObject, readBuffer, readMemory as readMemoryRaw } from 'memoryjs'; import * as Struct from 'structron'; import patcher from '../patcher'; -import { GameState, AmongUsState, Player } from "../common/AmongUsState"; -import { IOffsets } from "./IOffsets"; +import { GameState, AmongUsState, Player } from '../common/AmongUsState'; +import { IOffsets } from './IOffsets'; export default class GameReader { reply: Function; @@ -19,10 +19,10 @@ export default class GameReader { amongUs: ProcessObject | null = null; gameAssembly: ModuleObject | null = null; - gameCode: string = 'MENU'; + gameCode = 'MENU'; checkProcessOpen(): void { - let processOpen = getProcesses().find(p => p.szExeFile === 'Among Us.exe'); + const processOpen = getProcesses().find(p => p.szExeFile === 'Among Us.exe'); if (!this.amongUs && processOpen) { // If process just opened try { this.amongUs = openProcess('Among Us.exe'); @@ -42,44 +42,44 @@ export default class GameReader { this.checkProcessOpen(); if (this.amongUs !== null && this.gameAssembly !== null) { let state = GameState.UNKNOWN; - let meetingHud = this.readMemory('pointer', this.gameAssembly.modBaseAddr, this.offsets.meetingHud); - let meetingHud_cachePtr = meetingHud === 0 ? 0 : this.readMemory('uint32', meetingHud, this.offsets.meetingHudCachePtr); - let meetingHudState = meetingHud_cachePtr === 0 ? 4 : this.readMemory('int', meetingHud, this.offsets.meetingHudState, 4); - let gameState = this.readMemory('int', this.gameAssembly.modBaseAddr, this.offsets.gameState); + const meetingHud = this.readMemory('pointer', this.gameAssembly.modBaseAddr, this.offsets.meetingHud); + const meetingHud_cachePtr = meetingHud === 0 ? 0 : this.readMemory('uint32', meetingHud, this.offsets.meetingHudCachePtr); + const meetingHudState = meetingHud_cachePtr === 0 ? 4 : this.readMemory('int', meetingHud, this.offsets.meetingHudState, 4); + const gameState = this.readMemory('int', this.gameAssembly.modBaseAddr, this.offsets.gameState); switch (gameState) { - case 0: - state = GameState.MENU; - this.exileCausesEnd = false; - break; - case 1: - case 3: + case 0: + state = GameState.MENU; + this.exileCausesEnd = false; + break; + case 1: + case 3: + state = GameState.LOBBY; + this.exileCausesEnd = false; + break; + default: + if (this.exileCausesEnd) state = GameState.LOBBY; - this.exileCausesEnd = false; - break; - default: - if (this.exileCausesEnd) - state = GameState.LOBBY; - else if (meetingHudState < 4) - state = GameState.DISCUSSION; - else - state = GameState.TASKS; - break; + else if (meetingHudState < 4) + state = GameState.DISCUSSION; + else + state = GameState.TASKS; + break; } - let allPlayersPtr = this.readMemory('ptr', this.gameAssembly.modBaseAddr, this.offsets.allPlayersPtr) & 0xffffffff; - let allPlayers = this.readMemory('ptr', allPlayersPtr, this.offsets.allPlayers); - let playerCount = this.readMemory('int' as 'int', allPlayersPtr, this.offsets.playerCount); + const allPlayersPtr = this.readMemory('ptr', this.gameAssembly.modBaseAddr, this.offsets.allPlayersPtr) & 0xffffffff; + const allPlayers = this.readMemory('ptr', allPlayersPtr, this.offsets.allPlayers); + const playerCount = this.readMemory('int' as const, allPlayersPtr, this.offsets.playerCount); let playerAddrPtr = allPlayers + this.offsets.playerAddrPtr; - let players = []; + const players = []; - let exiledPlayerId = this.readMemory('byte', this.gameAssembly.modBaseAddr, this.offsets.exiledPlayerId); + const exiledPlayerId = this.readMemory('byte', this.gameAssembly.modBaseAddr, this.offsets.exiledPlayerId); let impostors = 0, crewmates = 0; for (let i = 0; i < Math.min(playerCount, 10); i++) { - let { address, last } = this.offsetAddress(playerAddrPtr, this.offsets.player.offsets); - let playerData = readBuffer(this.amongUs.handle, address + last, this.offsets.player.bufferLength); - let player = this.parsePlayer(address + last, playerData); + const { address, last } = this.offsetAddress(playerAddrPtr, this.offsets.player.offsets); + const playerData = readBuffer(this.amongUs.handle, address + last, this.offsets.player.bufferLength); + const player = this.parsePlayer(address + last, playerData); playerAddrPtr += 4; players.push(player); @@ -106,14 +106,14 @@ export default class GameReader { } this.lastPlayerPtr = allPlayers; - let inGame = state === GameState.TASKS || state === GameState.DISCUSSION || state === GameState.LOBBY; + const inGame = state === GameState.TASKS || state === GameState.DISCUSSION || state === GameState.LOBBY; let newGameCode = 'MENU'; if (state === GameState.LOBBY) { newGameCode = this.readString( this.readMemory('int32', this.gameAssembly.modBaseAddr, this.offsets.gameCode) ); if (newGameCode) { - let split = newGameCode.split('\r\n'); + const split = newGameCode.split('\r\n'); if (split.length === 2) { newGameCode = split[1]; } else { @@ -129,13 +129,13 @@ export default class GameReader { } if (newGameCode) this.gameCode = newGameCode; - let newState = { + const newState = { lobbyCode: this.gameCode, players, gameState: state, oldGameState: this.oldGameState }; - let patch = patcher.diff(this.lastState, newState); + const patch = patcher.diff(this.lastState, newState); if (patch) { try { this.reply('gameState', newState); @@ -154,7 +154,7 @@ export default class GameReader { this.PlayerStruct = new Struct(); - for (let member of offsets.player.struct) { + for (const member of offsets.player.struct) { if (member.type === 'SKIP') { this.PlayerStruct = this.PlayerStruct.addMember(Struct.TYPES.SKIP(member.skip!), member.name); } else { @@ -166,7 +166,7 @@ export default class GameReader { readMemory(dataType: DataType, address: number, offsets: number[], defaultParam?: T): T { if (address === 0) return defaultParam as T; - let { address: addr, last } = this.offsetAddress(address, offsets); + const { address: addr, last } = this.offsetAddress(address, offsets); if (addr === 0) return defaultParam as T; return readMemoryRaw( this.amongUs!.handle, @@ -181,33 +181,33 @@ export default class GameReader { if (address == 0) break; } - let last = offsets.length > 0 ? offsets[offsets.length - 1] : 0; + const last = offsets.length > 0 ? offsets[offsets.length - 1] : 0; return { address, last }; } readString(address: number): string { if (address === 0) return ''; - let length = readMemoryRaw(this.amongUs!.handle, address + 0x8, 'int'); + const length = readMemoryRaw(this.amongUs!.handle, address + 0x8, 'int'); // console.log(length); // console.log("reading string", length, length << 1); - let buffer = readBuffer(this.amongUs!.handle, address + 0xC, length << 1); + const buffer = readBuffer(this.amongUs!.handle, address + 0xC, length << 1); return buffer.toString('utf8').replace(/\0/g, ''); } parsePlayer(ptr: number, buffer: Buffer): Player { - let { data } = this.PlayerStruct.report(buffer, 0, {}); + const { data } = this.PlayerStruct.report(buffer, 0, {}); - let isLocal = this.readMemory('int', data.objectPtr, this.offsets.player.isLocal) !== 0; + const isLocal = this.readMemory('int', data.objectPtr, this.offsets.player.isLocal) !== 0; - let positionOffsets = isLocal ? [ + const positionOffsets = isLocal ? [ this.offsets.player.localX, this.offsets.player.localY ] : [ - this.offsets.player.remoteX, - this.offsets.player.remoteY - ]; + this.offsets.player.remoteX, + this.offsets.player.remoteY + ]; - let x = this.readMemory('float', data.objectPtr, positionOffsets[0]); - let y = this.readMemory('float', data.objectPtr, positionOffsets[1]); + const x = this.readMemory('float', data.objectPtr, positionOffsets[0]); + const y = this.readMemory('float', data.objectPtr, positionOffsets[1]); return { ptr, id: data.id, diff --git a/src/main/hook-ti.ts b/src/main/hook-ti.ts index 2e3d3288..fbd10bc7 100644 --- a/src/main/hook-ti.ts +++ b/src/main/hook-ti.ts @@ -1,38 +1,38 @@ /** * This module was automatically generated by `ts-interface-builder` */ -import * as t from "ts-interface-checker"; +import * as t from 'ts-interface-checker'; // tslint:disable:object-literal-key-quotes export const IOffsets = t.iface([], { - "meetingHud": t.array("number"), - "meetingHudCachePtr": t.array("number"), - "meetingHudState": t.array("number"), - "gameState": t.array("number"), - "allPlayersPtr": t.array("number"), - "allPlayers": t.array("number"), - "playerCount": t.array("number"), - "playerAddrPtr": "number", - "exiledPlayerId": t.array("number"), - "gameCode": t.array("number"), - "player": t.iface([], { - "isLocal": t.array("number"), - "localX": t.array("number"), - "localY": t.array("number"), - "remoteX": t.array("number"), - "remoteY": t.array("number"), - "offsets": t.array("number"), - "inVent": t.array("number"), - "bufferLength": "number", - "struct": t.array(t.iface([], { - "type": "string", - "skip": t.opt("number"), - "name": "string", - })), - }), + 'meetingHud': t.array('number'), + 'meetingHudCachePtr': t.array('number'), + 'meetingHudState': t.array('number'), + 'gameState': t.array('number'), + 'allPlayersPtr': t.array('number'), + 'allPlayers': t.array('number'), + 'playerCount': t.array('number'), + 'playerAddrPtr': 'number', + 'exiledPlayerId': t.array('number'), + 'gameCode': t.array('number'), + 'player': t.iface([], { + 'isLocal': t.array('number'), + 'localX': t.array('number'), + 'localY': t.array('number'), + 'remoteX': t.array('number'), + 'remoteY': t.array('number'), + 'offsets': t.array('number'), + 'inVent': t.array('number'), + 'bufferLength': 'number', + 'struct': t.array(t.iface([], { + 'type': 'string', + 'skip': t.opt('number'), + 'name': 'string', + })), + }), }); const exportedTypeSuite: t.ITypeSuite = { - IOffsets, + IOffsets, }; export default exportedTypeSuite; diff --git a/src/main/hook.ts b/src/main/hook.ts index d8d17345..56aa9d0f 100644 --- a/src/main/hook.ts +++ b/src/main/hook.ts @@ -7,7 +7,7 @@ import spawn from 'cross-spawn'; import GameReader from './GameReader'; import iohook from 'iohook'; import Store from 'electron-store'; -import { ISettings } from "../common/ISettings"; +import { ISettings } from '../common/ISettings'; import axios, { AxiosError } from 'axios'; import { createCheckers } from 'ts-interface-checker'; @@ -20,11 +20,11 @@ const store = new Store(); async function loadOffsets(event: Electron.IpcMainEvent): Promise { - const valuesFile = resolve((process.env.LOCALAPPDATA || '') + "Low", 'Innersloth/Among Us/Unity/6b8b0d91-4a20-4a00-a3e4-4da4a883a5f0/Analytics/values'); - let version: string = ''; + const valuesFile = resolve((process.env.LOCALAPPDATA || '') + 'Low', 'Innersloth/Among Us/Unity/6b8b0d91-4a20-4a00-a3e4-4da4a883a5f0/Analytics/values'); + let version = ''; if (existsSync(valuesFile)) { try { - let json = JSON.parse(readFileSync(valuesFile, 'utf8')); + const json = JSON.parse(readFileSync(valuesFile, 'utf8')); version = json.app_ver; } catch (e) { console.error(e); @@ -32,12 +32,12 @@ async function loadOffsets(event: Electron.IpcMainEvent): Promise { // Register key events iohook.on('keydown', (ev: any) => { - let shortcutKey = store.get('pushToTalkShortcut'); + const shortcutKey = store.get('pushToTalkShortcut'); if (keyCodeMatches(shortcutKey as K, ev)) { event.reply('pushToTalk', true); } }); iohook.on('keyup', (ev: any) => { - let shortcutKey = store.get('pushToTalkShortcut'); + const shortcutKey = store.get('pushToTalkShortcut'); if (keyCodeMatches(shortcutKey as K, ev)) { event.reply('pushToTalk', false); } @@ -123,7 +123,7 @@ ipcMain.on('start', async (event) => { const frame = () => { gameReader.loop(); setTimeout(frame, 1000 / 20); - } + }; frame(); } else if (gameReader) { gameReader.amongUs = null; @@ -182,7 +182,7 @@ ipcMain.on('openGame', () => { dialog.showErrorBox('Error', 'Please launch the game through Steam.'); } } -}) +}); ipcMain.on('relaunch', () => { app.relaunch(); diff --git a/src/main/index.ts b/src/main/index.ts index a9b4800a..fdc015d0 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,13 +1,13 @@ -'use strict' +'use strict'; import { autoUpdater } from 'electron-updater'; import { app, BrowserWindow } from 'electron'; -import * as windowStateKeeper from 'electron-window-state' -import * as path from 'path' -import { format as formatUrl } from 'url' +import * as windowStateKeeper from 'electron-window-state'; +import * as path from 'path'; +import { format as formatUrl } from 'url'; import './hook'; -const isDevelopment = process.env.NODE_ENV !== 'production' +const isDevelopment = process.env.NODE_ENV !== 'production'; // global reference to mainWindow (necessary to prevent window from being garbage collected) let mainWindow: BrowserWindow | null; @@ -23,13 +23,13 @@ if (!gotTheLock) { app.on('second-instance', (event, commandLine, workingDirectory) => { // Someone tried to run a second instance, we should focus our window. if (mainWindow) { - if (mainWindow.isMinimized()) mainWindow.restore() - mainWindow.focus() + if (mainWindow.isMinimized()) mainWindow.restore(); + mainWindow.focus(); } - }) + }); function createMainWindow() { - const mainWindowState = windowStateKeeper({}) + const mainWindowState = windowStateKeeper({}); const window = new BrowserWindow({ width: 250, @@ -49,14 +49,14 @@ if (!gotTheLock) { } }); - mainWindowState.manage(window) + mainWindowState.manage(window); if (isDevelopment) { - window.webContents.openDevTools() + window.webContents.openDevTools(); } if (isDevelopment) { - window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}?version=${autoUpdater.currentVersion.version}`) + window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}?version=${autoUpdater.currentVersion.version}`); } else { window.loadURL(formatUrl({ @@ -66,37 +66,37 @@ if (!gotTheLock) { version: autoUpdater.currentVersion.version }, slashes: true - })) + })); } window.on('closed', () => { - mainWindow = null - }) + mainWindow = null; + }); window.webContents.on('devtools-opened', () => { - window.focus() + window.focus(); setImmediate(() => { - window.focus() - }) - }) + window.focus(); + }); + }); - return window + return window; } // quit application when all windows are closed app.on('window-all-closed', () => { // on macOS it is common for applications to stay open until the user explicitly quits if (process.platform !== 'darwin') { - app.quit() + app.quit(); } - }) + }); app.on('activate', () => { // on macOS it is common to re-create a window even after all windows have been closed if (mainWindow === null) { - mainWindow = createMainWindow() + mainWindow = createMainWindow(); } - }) + }); // create main BrowserWindow when electron is ready app.on('ready', () => { diff --git a/src/main/memoryjs.d.ts b/src/main/memoryjs.d.ts index 53e26be6..eddae8ae 100644 --- a/src/main/memoryjs.d.ts +++ b/src/main/memoryjs.d.ts @@ -36,7 +36,7 @@ declare module 'memoryjs' { export type Vector3 = { x: number, y: number, z: number }; export type Vector4 = { x: number, y: number, z: number, w: number }; - export type DataType = "byte" | "int" | "int32" | "uint32" | "int64" | "uint64" | "dword" | "short" | "long" | "float" | "double" | "bool" | "boolean" | "ptr" | "pointer" | "str" | "string" | "vec3" | "vector3" | "vec4" | "vector4"; + export type DataType = 'byte' | 'int' | 'int32' | 'uint32' | 'int64' | 'uint64' | 'dword' | 'short' | 'long' | 'float' | 'double' | 'bool' | 'boolean' | 'ptr' | 'pointer' | 'str' | 'string' | 'vec3' | 'vector3' | 'vec4' | 'vector4'; export function readMemory(handle: number, address: number, dataType: DataType, callback?: Callback): T; diff --git a/src/patcher.ts b/src/patcher.ts index 941953ac..49741797 100644 --- a/src/patcher.ts +++ b/src/patcher.ts @@ -1,5 +1,5 @@ -import { create } from "jsondiffpatch"; -import { Player } from "./common/AmongUsState"; +import { create } from 'jsondiffpatch'; +import { Player } from './common/AmongUsState'; export default create({ objectHash: (obj: Player) => obj.ptr, diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 05073a08..c303a804 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -3,18 +3,18 @@ import ReactDOM from 'react-dom'; import Voice from './Voice'; import Menu from './Menu'; import { ipcRenderer, remote } from 'electron'; -import { AmongUsState } from "../common/AmongUsState"; +import { AmongUsState } from '../common/AmongUsState'; import Settings, { settingsReducer } from './Settings'; import { GameStateContext, SettingsContext } from './contexts'; let appVersion = ''; if (typeof window !== 'undefined' && window.location) { - let query = new URLSearchParams(window.location.search.substring(1)); + const query = new URLSearchParams(window.location.search.substring(1)); appVersion = (' v' + query.get('version')) || ''; } -enum AppState { MENU, VOICE }; +enum AppState { MENU, VOICE } function App() { const [state, setState] = useState(AppState.MENU); @@ -56,23 +56,23 @@ function App() { ipcRenderer.once('started', () => { if (shouldInit) setGameState(ipcRenderer.sendSync('initState')); - }) + }); return () => { ipcRenderer.off('gameOpen', onOpen); ipcRenderer.off('error', onError); ipcRenderer.off('gameState', onState); - } + }; }, []); let page; switch (state) { - case AppState.MENU: - page =

; - break; - case AppState.VOICE: - page = ; - break; + case AppState.MENU: + page = ; + break; + case AppState.VOICE: + page = ; + break; } return ( @@ -96,7 +96,7 @@ function App() { {page} - ) + ); } ReactDOM.render(, document.getElementById('app')); \ No newline at end of file diff --git a/src/renderer/Avatar.tsx b/src/renderer/Avatar.tsx index 37209d43..7022233b 100644 --- a/src/renderer/Avatar.tsx +++ b/src/renderer/Avatar.tsx @@ -1,7 +1,7 @@ -import React, { useEffect, useRef } from "react"; -import { Player } from "../common/AmongUsState"; -import { backLayerHats, hatOffsets, hats, skins, players } from "./cosmetics"; -import Tooltip from "react-tooltip-lite"; +import React, { useEffect, useRef } from 'react'; +import { Player } from '../common/AmongUsState'; +import { backLayerHats, hatOffsets, hats, skins, players } from './cosmetics'; +import Tooltip from 'react-tooltip-lite'; export interface CanvasProps { src: string; @@ -69,7 +69,7 @@ function Canvas({ src, hat, skin, isAlive }: CanvasProps) { ctx.drawImage(image.current, 0, 0); function drawHat() { - let hatY = 17 - hatOffsets[hat]; + const hatY = 17 - hatOffsets[hat]; ctx.drawImage(hatImg.current!, 0, hatY > 0 ? 0 : -hatY, hatImg.current!.width, hatImg.current!.height, canvas.current!.width / 2 - hatImg.current!.width / 2 + 2, Math.max(hatY, 0), hatImg.current!.width, hatImg.current!.height); } @@ -92,5 +92,5 @@ function Canvas({ src, hat, skin, isAlive }: CanvasProps) { - ) + ); } \ No newline at end of file diff --git a/src/renderer/Footer.tsx b/src/renderer/Footer.tsx index 9676a347..7558af0f 100644 --- a/src/renderer/Footer.tsx +++ b/src/renderer/Footer.tsx @@ -1,5 +1,5 @@ -import { shell } from "electron"; -import React from "react"; +import { shell } from 'electron'; +import React from 'react'; export default function Footer() { return ( @@ -56,5 +56,5 @@ export default function Footer() {
- ) + ); } \ No newline at end of file diff --git a/src/renderer/Menu.tsx b/src/renderer/Menu.tsx index 1556e0b6..7609d878 100644 --- a/src/renderer/Menu.tsx +++ b/src/renderer/Menu.tsx @@ -1,8 +1,8 @@ -import React from "react"; -import { ImpulseSpinner as Spinner } from "react-spinners-kit"; +import React from 'react'; +import { ImpulseSpinner as Spinner } from 'react-spinners-kit'; import { ipcRenderer } from 'electron'; import './css/menu.css'; -import Footer from "./Footer"; +import Footer from './Footer'; export default function Menu({ errored }: { errored: boolean }) { return ( diff --git a/src/renderer/MicrophoneSoundBar.tsx b/src/renderer/MicrophoneSoundBar.tsx index bf22ecbd..3821203d 100644 --- a/src/renderer/MicrophoneSoundBar.tsx +++ b/src/renderer/MicrophoneSoundBar.tsx @@ -1,54 +1,54 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react'; interface ITestMicProps { microphone: string } const TestMicrophoneButton: React.FunctionComponent = function({ microphone }) { - const [error, setError] = useState(false) - const [rms, setRms] = useState(0) - - useEffect(() => { - setError(false) - - const ctx = new AudioContext() - const processor = ctx.createScriptProcessor(2048, 1, 1) - processor.connect(ctx.destination) - - const minUpdateRate = 50; - let lastRefreshTime = 0; - - const handleProcess = (event: AudioProcessingEvent) => { - // limit update frequency - if ( event.timeStamp - lastRefreshTime < minUpdateRate ) { - return; - } - - // update last refresh time - lastRefreshTime = event.timeStamp; - - const input = event.inputBuffer.getChannelData(0) - const total = input.reduce((acc, val) => acc + Math.abs(val), 0) - const rms = Math.min(50, Math.sqrt(total / input.length)); - setRms(rms) - } - - navigator.mediaDevices.getUserMedia({ audio: { deviceId: microphone ?? 'default' } }) - .then((stream) => { - const src = ctx.createMediaStreamSource(stream) - src.connect(processor) - processor.addEventListener('audioprocess', handleProcess) - }) - .catch(() => setError(true)) - - return () => { - processor.removeEventListener('audioprocess', handleProcess) - } - }, [microphone]) - - if (error) return

Could not connect to microphone

- - return
-} + const [error, setError] = useState(false); + const [rms, setRms] = useState(0); + + useEffect(() => { + setError(false); + + const ctx = new AudioContext(); + const processor = ctx.createScriptProcessor(2048, 1, 1); + processor.connect(ctx.destination); + + const minUpdateRate = 50; + let lastRefreshTime = 0; + + const handleProcess = (event: AudioProcessingEvent) => { + // limit update frequency + if ( event.timeStamp - lastRefreshTime < minUpdateRate ) { + return; + } + + // update last refresh time + lastRefreshTime = event.timeStamp; + + const input = event.inputBuffer.getChannelData(0); + const total = input.reduce((acc, val) => acc + Math.abs(val), 0); + const rms = Math.min(50, Math.sqrt(total / input.length)); + setRms(rms); + }; + + navigator.mediaDevices.getUserMedia({ audio: { deviceId: microphone ?? 'default' } }) + .then((stream) => { + const src = ctx.createMediaStreamSource(stream); + src.connect(processor); + processor.addEventListener('audioprocess', handleProcess); + }) + .catch(() => setError(true)); + + return () => { + processor.removeEventListener('audioprocess', handleProcess); + }; + }, [microphone]); + + if (error) return

Could not connect to microphone

; + + return
; +}; -export default TestMicrophoneButton +export default TestMicrophoneButton; diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 308950fc..90fd8aa1 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -1,6 +1,6 @@ import Store from 'electron-store'; -import React, { useContext, useEffect, useReducer, useState } from "react"; -import { SettingsContext } from "./contexts"; +import React, { useContext, useEffect, useReducer, useState } from 'react'; +import { SettingsContext } from './contexts'; import Ajv from 'ajv'; import './css/settings.css'; import MicrophoneSoundBar from './MicrophoneSoundBar'; @@ -24,13 +24,13 @@ const store = new Store({ if (typeof serverIP === 'string') { const serverURL = `http://${serverIP}`; if (validateURL(serverURL)) { - store.set('serverURL', serverURL) + store.set('serverURL', serverURL); } else { console.warn('Error while parsing the old serverIP property. Default URL will be used instead.'); } // @ts-ignore: Old serverIP property no longer exists in ISettings - store.delete('serverIP') + store.delete('serverIP'); } }, '1.1.5': store => { @@ -109,13 +109,13 @@ export const settingsReducer = (state: ISettings, action: { type: 'set' | 'setOne', action: [string, any] | ISettings }): ISettings => { if (action.type === 'set') return action.action as ISettings; - let v = (action.action as [string, any]); + const v = (action.action as [string, any]); store.set(v[0], v[1]); return { ...state, [v[0]]: v[1] }; -} +}; interface MediaDevice { id: string; @@ -147,7 +147,7 @@ function URLInput({ initialURL, onValidURL }: URLInputProps) { } } - return + return ; } export default function Settings({ open, onClose }: SettingsProps) { @@ -173,11 +173,11 @@ export default function Settings({ open, onClose }: SettingsProps) { .map(d => { let label = d.label; if (d.deviceId === 'default') { - label = "Default"; + label = 'Default'; } else { - let match = /(.+?)\)/.exec(d.label); + const match = /(.+?)\)/.exec(d.label); if (match && match[1]) - label = match[1] + ")"; + label = match[1] + ')'; } return { id: d.deviceId, @@ -295,7 +295,7 @@ export default function Settings({ open, onClose }: SettingsProps) { setSettings({ type: 'setOne', action: ['serverURL', url] - }) + }); }} />
setSettings({ @@ -313,5 +313,5 @@ export default function Settings({ open, onClose }: SettingsProps) {
- + ; } diff --git a/src/renderer/TestSpeakersButton.tsx b/src/renderer/TestSpeakersButton.tsx index 96d7f812..ae0ee769 100644 --- a/src/renderer/TestSpeakersButton.tsx +++ b/src/renderer/TestSpeakersButton.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React from 'react'; // @ts-ignore import chime from '../../static/chime.mp3'; @@ -7,17 +7,17 @@ interface ITestSpeakersProps { } const TestSpeakersButton: React.FunctionComponent = ({ speaker }) => { - const testSpeakers = () => { - const audio = new Audio(); - audio.src = chime; + const testSpeakers = () => { + const audio = new Audio(); + audio.src = chime; - if (speaker.toLowerCase() !== 'default') - (audio as any).setSinkId(speaker) + if (speaker.toLowerCase() !== 'default') + (audio as any).setSinkId(speaker); - audio.play(); - } + audio.play(); + }; - return -} + return ; +}; -export default TestSpeakersButton +export default TestSpeakersButton; diff --git a/src/renderer/Voice.tsx b/src/renderer/Voice.tsx index 4638e151..fdf5ea64 100644 --- a/src/renderer/Voice.tsx +++ b/src/renderer/Voice.tsx @@ -1,12 +1,12 @@ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; import io, { Socket } from 'socket.io-client'; import Avatar from './Avatar'; -import { GameStateContext, SettingsContext } from "./contexts"; -import { AmongUsState, GameState, Player } from "../common/AmongUsState"; +import { GameStateContext, SettingsContext } from './contexts'; +import { AmongUsState, GameState, Player } from '../common/AmongUsState'; import Peer from 'simple-peer'; import { ipcRenderer, remote } from 'electron'; import VAD from './vad'; -import { ISettings } from "../common/ISettings"; +import { ISettings } from '../common/ISettings'; interface PeerConnections { [peer: string]: Peer.Instance; @@ -121,7 +121,7 @@ export default function Voice() { } else if (gameState.gameState !== GameState.TASKS) { if (!gameState.players) return; setOtherDead(old => { - for (let player of gameState.players) { + for (const player of gameState.players) { old[player.id] = player.isDead || player.disconnected; } return { ...old }; @@ -149,7 +149,7 @@ export default function Voice() { // Initialize variables let audioListener: any; - let audio: MediaTrackConstraints = { + const audio: MediaTrackConstraints = { autoGainControl: false, channelCount: 2, echoCancellation: false, @@ -181,7 +181,7 @@ export default function Voice() { }); const ac = new AudioContext(); - ac.createMediaStreamSource(stream) + ac.createMediaStreamSource(stream); audioListener = VAD(ac, ac.createMediaStreamSource(stream), undefined, { onVoiceStart: () => setTalking(true), onVoiceStop: () => setTalking(false), @@ -193,7 +193,7 @@ export default function Voice() { const audioListeners: AudioListeners = {}; const connect = (lobbyCode: string, playerId: number) => { - console.log("Connect called", lobbyCode, playerId); + console.log('Connect called', lobbyCode, playerId); socket.emit('leave'); Object.keys(peerConnections).forEach(k => { disconnectPeer(k); @@ -236,16 +236,16 @@ export default function Voice() { peerConnections[peer] = connection; connection.on('stream', (stream: MediaStream) => { - let audio = document.createElement('audio'); + const audio = document.createElement('audio'); document.body.appendChild(audio); audio.srcObject = stream; if (settings.speaker.toLowerCase() !== 'default') (audio as any).setSinkId(settings.speaker); const context = new AudioContext(); - var source = context.createMediaStreamSource(stream); - let gain = context.createGain(); - let pan = context.createPanner(); + const source = context.createMediaStreamSource(stream); + const gain = context.createGain(); + const pan = context.createPanner(); pan.refDistance = 0.1; pan.panningModel = 'equalpower'; pan.distanceModel = 'linear'; @@ -294,7 +294,7 @@ export default function Voice() { }); socket.on('setId', (socketId: string, id: number) => { setSocketPlayerIds(old => ({ ...old, [socketId]: id })); - }) + }); socket.on('setIds', (ids: SocketIdMap) => { setSocketPlayerIds(ids); }); @@ -307,7 +307,7 @@ export default function Voice() { return () => { connectionStuff.current.socket?.close(); audioListener.destroy(); - } + }; }, []); @@ -324,11 +324,11 @@ export default function Voice() { if (!gameState || !gameState.players || gameState.lobbyCode === 'MENU' || !myPlayer) otherPlayers = []; else otherPlayers = gameState.players.filter(p => !p.isLocal); - let playerSocketIds = {} as any; - for (let k of Object.keys(socketPlayerIds)) { + const playerSocketIds = {} as any; + for (const k of Object.keys(socketPlayerIds)) { playerSocketIds[socketPlayerIds[k]] = k; } - for (let player of otherPlayers) { + for (const player of otherPlayers) { const audio = audioElements.current[playerSocketIds[player.id]]; if (audio) { calculateVoiceAudio(gameState, settingsRef.current, myPlayer!, player, audio.gain, audio.pan); @@ -388,7 +388,7 @@ export default function Voice() {
{ otherPlayers.map(player => { - let connected = Object.values(socketPlayerIds).includes(player.id); + const connected = Object.values(socketPlayerIds).includes(player.id); return (
- ) + ); } diff --git a/src/renderer/contexts.tsx b/src/renderer/contexts.tsx index 412ba949..56ae380e 100644 --- a/src/renderer/contexts.tsx +++ b/src/renderer/contexts.tsx @@ -1,10 +1,10 @@ import React, { createContext } from 'react'; -import { AmongUsState } from "../common/AmongUsState"; -import { ISettings } from "../common/ISettings"; +import { AmongUsState } from '../common/AmongUsState'; +import { ISettings } from '../common/ISettings'; export const GameStateContext = createContext({} as AmongUsState); export const SettingsContext = createContext<[ISettings, React.Dispatch<{ - type: "set" | "setOne"; + type: 'set' | 'setOne'; action: ISettings | [string, any]; }>]>(null as any); diff --git a/src/renderer/cosmetics.ts b/src/renderer/cosmetics.ts index f80c9325..3ee4ed85 100644 --- a/src/renderer/cosmetics.ts +++ b/src/renderer/cosmetics.ts @@ -167,7 +167,7 @@ export const skins = [ ]; export const hatOffsets = [ 45, 25, 50, 37/*T*/, 33, 60/*T*/, 70, 20, 27, 35, 41, 52, 35, 29, 40, 49, 34, 40, 25, 52, 55, 46, 41, 49, 46, 36, 44, 59, 44, 39, 30, 32, 37, 26, 61, 40, 43, 26, 50/*T*/, 51, 37, 44/*T*/, 30, 22, 40, 42, 8, 29, 32, 36, 28, 22, 39, 42, 24, 30, 47, 27, 52, 44, 26, 44, 48, 47, 42, 48, 50, 32, 44, 38, 56, 19, 27, 30, 42/*T*/, 43, 60, 34, 10, 45, 50, 33, 13, 2, 40/*T*/, 32, 32, 55, 22, 999, 26, 29, 43 -] +]; export const backLayerHats = new Set([38, 3, 5, 14, 28]); diff --git a/src/renderer/vad.ts b/src/renderer/vad.ts index bc8c8cf7..233cad42 100644 --- a/src/renderer/vad.ts +++ b/src/renderer/vad.ts @@ -19,7 +19,7 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat opts = opts || {}; - var defaults = { + const defaults = { fftSize: 1024, bufferLen: 1024, smoothingTimeConstant: 0.2, @@ -34,30 +34,30 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat onUpdate: (_: number) => { } }; - var options: any = {}; - for (var key in defaults) { + const options: any = {}; + for (const key in defaults) { options[key] = opts.hasOwnProperty(key) ? (opts as any)[key] : (defaults as any)[key]; } - var baseLevel = 0; - var voiceScale = 1; - var activityCounter = 0; - var activityCounterMin = 0; - var activityCounterMax = 30; - var activityCounterThresh = 5; + let baseLevel = 0; + let voiceScale = 1; + let activityCounter = 0; + const activityCounterMin = 0; + const activityCounterMax = 30; + const activityCounterThresh = 5; - var envFreqRange: number[] = []; - var isNoiseCapturing = true; - var prevVadState: boolean | undefined = undefined; - var vadState = false; - var captureTimeout: any = null; + let envFreqRange: number[] = []; + let isNoiseCapturing = true; + let prevVadState: boolean | undefined = undefined; + let vadState = false; + let captureTimeout: any = null; // var source = audioContext.createMediaStreamSource(stream); - var analyser = audioContext.createAnalyser(); + const analyser = audioContext.createAnalyser(); analyser.smoothingTimeConstant = options.smoothingTimeConstant; analyser.fftSize = options.fftSize; - var scriptProcessorNode = audioContext.createScriptProcessor(options.bufferLen, 2, 2); + const scriptProcessorNode = audioContext.createScriptProcessor(options.bufferLen, 2, 2); connect(); scriptProcessorNode.onaudioprocess = monitor; @@ -73,7 +73,7 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat envFreqRange = envFreqRange.filter(function (val) { return val; }).sort(); - var averageEnvFreq = envFreqRange.length ? envFreqRange.reduce(function (p, c) { return Math.min(p, c) }, 1) : (options.minNoiseLevel || 0.1); + const averageEnvFreq = envFreqRange.length ? envFreqRange.reduce(function (p, c) { return Math.min(p, c); }, 1) : (options.minNoiseLevel || 0.1); baseLevel = averageEnvFreq * options.avgNoiseMultiplier; if (options.minNoiseLevel && baseLevel < options.minNoiseLevel) baseLevel = options.minNoiseLevel; @@ -113,18 +113,18 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat if (destination) { for (let channel = 0; channel < event.outputBuffer.numberOfChannels; channel++) { - var inputData = event.inputBuffer.getChannelData(channel); - var outputData = event.outputBuffer.getChannelData(channel); - for (var sample = 0; sample < event.inputBuffer.length; sample++) { + const inputData = event.inputBuffer.getChannelData(channel); + const outputData = event.outputBuffer.getChannelData(channel); + for (let sample = 0; sample < event.inputBuffer.length; sample++) { // make output equal to the same as the input outputData[sample] = inputData[sample]; } } } - var frequencies = new Uint8Array(analyser.frequencyBinCount); + const frequencies = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(frequencies); - var average = analyserFrequency(analyser, frequencies, options.minCaptureFreq, options.maxCaptureFreq); + const average = analyserFrequency(analyser, frequencies, options.minCaptureFreq, options.maxCaptureFreq); if (isNoiseCapturing) { envFreqRange.push(average); return; @@ -154,4 +154,4 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat } return { connect, destroy }; -}; +} diff --git a/yarn.lock b/yarn.lock index 464229ec..dbf3b829 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1005,6 +1005,43 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== +"@eslint/eslintrc@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76" + integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + lodash "^4.17.19" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -1084,6 +1121,11 @@ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.5.tgz#136d5e6a57a931e1cce6f9d8126aa98a9c92a6bb" integrity sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww== +"@types/json-schema@^7.0.3": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" + integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -1206,6 +1248,76 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@^4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.9.1.tgz#66758cbe129b965fe9c63b04b405d0cf5280868b" + integrity sha512-QRLDSvIPeI1pz5tVuurD+cStNR4sle4avtHhxA+2uyixWGFjKzJ+EaFVRW6dA/jOgjV5DTAjOxboQkRDE8cRlQ== + dependencies: + "@typescript-eslint/experimental-utils" "4.9.1" + "@typescript-eslint/scope-manager" "4.9.1" + debug "^4.1.1" + functional-red-black-tree "^1.0.1" + regexpp "^3.0.0" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/experimental-utils@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.9.1.tgz#86633e8395191d65786a808dc3df030a55267ae2" + integrity sha512-c3k/xJqk0exLFs+cWSJxIjqLYwdHCuLWhnpnikmPQD2+NGAx9KjLYlBDcSI81EArh9FDYSL6dslAUSwILeWOxg== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/scope-manager" "4.9.1" + "@typescript-eslint/types" "4.9.1" + "@typescript-eslint/typescript-estree" "4.9.1" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@^4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.9.1.tgz#2d74c4db5dd5117379a9659081a4d1ec02629055" + integrity sha512-Gv2VpqiomvQ2v4UL+dXlQcZ8zCX4eTkoIW+1aGVWT6yTO+6jbxsw7yQl2z2pPl/4B9qa5JXeIbhJpONKjXIy3g== + dependencies: + "@typescript-eslint/scope-manager" "4.9.1" + "@typescript-eslint/types" "4.9.1" + "@typescript-eslint/typescript-estree" "4.9.1" + debug "^4.1.1" + +"@typescript-eslint/scope-manager@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz#cc2fde310b3f3deafe8436a924e784eaab265103" + integrity sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ== + dependencies: + "@typescript-eslint/types" "4.9.1" + "@typescript-eslint/visitor-keys" "4.9.1" + +"@typescript-eslint/types@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.9.1.tgz#a1a7dd80e4e5ac2c593bc458d75dd1edaf77faa2" + integrity sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA== + +"@typescript-eslint/typescript-estree@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.1.tgz#6e5b86ff5a5f66809e1f347469fadeec69ac50bf" + integrity sha512-bzP8vqwX6Vgmvs81bPtCkLtM/Skh36NE6unu6tsDeU/ZFoYthlTXbBmpIrvosgiDKlWTfb2ZpPELHH89aQjeQw== + dependencies: + "@typescript-eslint/types" "4.9.1" + "@typescript-eslint/visitor-keys" "4.9.1" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/visitor-keys@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz#d76374a58c4ead9e92b454d186fea63487b25ae1" + integrity sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ== + dependencies: + "@typescript-eslint/types" "4.9.1" + eslint-visitor-keys "^2.0.0" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -1369,7 +1481,7 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-jsx@^5.0.0: +acorn-jsx@^5.0.0, acorn-jsx@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== @@ -1384,6 +1496,11 @@ acorn@^6.2.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== +acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" @@ -1417,7 +1534,7 @@ ajv@^6.1.0, ajv@^6.10.1, ajv@^6.10.2, ajv@^6.12.0: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.6, ajv@^6.9.1: +ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.6, ajv@^6.9.1: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1446,6 +1563,11 @@ ansi-colors@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" @@ -1598,6 +1720,11 @@ array-union@^1.0.1: dependencies: array-uniq "^1.0.1" +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -1616,6 +1743,16 @@ array.prototype.flat@^1.2.3: define-properties "^1.1.3" es-abstract "^1.17.0-next.1" +array.prototype.flatmap@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz#94cfd47cc1556ec0747d97f7c7738c58122004c9" + integrity sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + function-bind "^1.1.1" + arraybuffer.slice@~0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" @@ -2212,6 +2349,14 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" +call-bind@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce" + integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.0" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2720,7 +2865,7 @@ cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.3: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -2931,7 +3076,7 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@~0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= @@ -3048,6 +3193,13 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + dissolve@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/dissolve/-/dissolve-0.3.3.tgz#b97ef1ff2989c789cecfb03107e17411fa8be6e5" @@ -3096,6 +3248,13 @@ doctrine@1.5.0: esutils "^2.0.2" isarray "^1.0.0" +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -3473,6 +3632,13 @@ enhanced-resolve@^4.1.0: memory-fs "^0.5.0" tapable "^1.0.0" +enquirer@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + entities@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" @@ -3640,6 +3806,23 @@ eslint-plugin-import@^2.8.0: resolve "^1.17.0" tsconfig-paths "^3.9.0" +eslint-plugin-react@^7.21.5: + version "7.21.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz#50b21a412b9574bfe05b21db176e8b7b3b15bff3" + integrity sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g== + dependencies: + array-includes "^3.1.1" + array.prototype.flatmap "^1.2.3" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.4.1 || ^3.0.0" + object.entries "^1.1.2" + object.fromentries "^2.0.2" + object.values "^1.1.1" + prop-types "^15.7.2" + resolve "^1.18.1" + string.prototype.matchall "^4.0.2" + eslint-restricted-globals@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" @@ -3653,6 +3836,14 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.0.0, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + eslint-utils@^1.3.1: version "1.4.3" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" @@ -3660,11 +3851,23 @@ eslint-utils@^1.3.1: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: +eslint-utils@^2.0.0, eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== +eslint-visitor-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" + integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== + eslint@^5.16.0: version "5.16.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" @@ -3707,6 +3910,49 @@ eslint@^5.16.0: table "^5.2.3" text-table "^0.2.0" +eslint@^7.15.0: + version "7.15.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.15.0.tgz#eb155fb8ed0865fcf5d903f76be2e5b6cd7e0bc7" + integrity sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^0.2.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.2.0" + esutils "^2.0.2" + file-entry-cache "^6.0.0" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.19" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + espree@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" @@ -3716,12 +3962,21 @@ espree@^5.0.1: acorn-jsx "^5.0.0" eslint-visitor-keys "^1.0.0" +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1: +esquery@^1.0.1, esquery@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== @@ -3735,12 +3990,19 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + estraverse@^4.1.0, estraverse@^4.1.1: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== @@ -3922,16 +4184,35 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== +fast-glob@^3.1.1: + version "3.2.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" + integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fastq@^1.6.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.9.0.tgz#e16a72f338eaca48e91b5c23593bcc2ef66b7947" + integrity sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w== + dependencies: + reusify "^1.0.4" + faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" @@ -3972,6 +4253,13 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" +file-entry-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a" + integrity sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA== + dependencies: + flat-cache "^3.0.4" + file-loader@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.0.0.tgz#97bbfaab7a2460c07bcbd72d3a6922407f67649f" @@ -4089,11 +4377,24 @@ flat-cache@^2.0.1: rimraf "2.6.3" write "1.0.3" +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + flatted@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flatted@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.0.tgz#a5d06b4a8b01e3a63771daa5cb7a1903e2e57067" + integrity sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA== + flush-write-stream@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" @@ -4288,6 +4589,15 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-intrinsic@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.1.tgz#94a9768fcbdd0595a1c9273aacf4c89d075631be" + integrity sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -4332,6 +4642,13 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-parent@^5.0.0, glob-parent@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -4415,6 +4732,13 @@ globals@^11.1.0, globals@^11.7.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + globalthis@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.1.tgz#40116f5d9c071f9e8fb0037654df1ab3a83b7ef9" @@ -4422,6 +4746,18 @@ globalthis@^1.0.1: dependencies: define-properties "^1.1.3" +globby@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -4794,6 +5130,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + import-fresh@^3.0.0: version "3.2.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" @@ -4802,6 +5143,14 @@ import-fresh@^3.0.0: parent-module "^1.0.0" resolve-from "^4.0.0" +import-fresh@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.2.tgz#fc129c160c5d68235507f4331a6baad186bdbc3e" + integrity sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -4902,6 +5251,15 @@ internal-ip@^4.3.0: default-gateway "^4.2.0" ipaddr.js "^1.9.0" +internal-slot@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3" + integrity sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g== + dependencies: + es-abstract "^1.17.0-next.1" + has "^1.0.3" + side-channel "^1.0.2" + interpret@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" @@ -5010,6 +5368,13 @@ is-core-module@^2.0.0: dependencies: has "^1.0.3" +is-core-module@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" + integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== + dependencies: + has "^1.0.3" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -5093,7 +5458,7 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0: +is-glob@^4.0.0, is-glob@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -5416,6 +5781,14 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.1.0.tgz#642f1d7b88aa6d7eb9d8f2210e166478444fa891" + integrity sha512-d4/UOjg+mxAWxCiF0c5UTSwyqbchkbqCvK87aBovhnh8GtysTjWmgC63tY0cJx/HzGgm9qnA147jVBdpOiQ2RA== + dependencies: + array-includes "^3.1.1" + object.assign "^4.1.1" + keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -5491,6 +5864,14 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -5775,6 +6156,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -5804,7 +6190,7 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.0: +micromatch@^4.0.0, micromatch@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== @@ -6304,6 +6690,26 @@ object.assign@^4.1.1: has-symbols "^1.0.1" object-keys "^1.1.1" +object.entries@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.3.tgz#c601c7f168b62374541a07ddbd3e2d5e4f7711a6" + integrity sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + has "^1.0.3" + +object.fromentries@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.3.tgz#13cefcffa702dc67750314a3305e8cb3fad1d072" + integrity sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + has "^1.0.3" + object.getownpropertydescriptors@^2.0.3: version "2.1.0" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" @@ -6386,6 +6792,18 @@ optionator@^0.8.2: type-check "~0.3.2" word-wrap "~1.2.3" +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" @@ -6665,6 +7083,11 @@ path-type@^2.0.0: dependencies: pify "^2.0.0" +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" @@ -6686,7 +7109,7 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.5: +picomatch@^2.0.5, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== @@ -6854,6 +7277,11 @@ prebuild-install@^5.3.5: tunnel-agent "^0.6.0" which-pm-runs "^1.0.0" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -6918,7 +7346,7 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= -prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.2: +prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -7305,7 +7733,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0: +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== @@ -7318,6 +7746,11 @@ regexpp@^2.0.1: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== +regexpp@^3.0.0, regexpp@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== + regexpu-core@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" @@ -7493,6 +7926,14 @@ resolve@^1.13.1, resolve@^1.17.0: is-core-module "^2.0.0" path-parse "^1.0.6" +resolve@^1.18.1: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== + dependencies: + is-core-module "^2.1.0" + path-parse "^1.0.6" + responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -7518,6 +7959,11 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -7532,6 +7978,13 @@ rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.3, rimraf@^2.7.1: dependencies: glob "^7.1.3" +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -7557,6 +8010,11 @@ run-async@^2.2.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-parallel@^1.1.9: + version "1.1.10" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef" + integrity sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw== + run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" @@ -7682,6 +8140,13 @@ semver@^7.1.3: resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6" integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA== +semver@^7.2.1: + version "7.3.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" + semver@^7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" @@ -7803,6 +8268,14 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +side-channel@^1.0.2, side-channel@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.3.tgz#cdc46b057550bbab63706210838df5d4c19519c3" + integrity sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g== + dependencies: + es-abstract "^1.18.0-next.0" + object-inspect "^1.8.0" + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -7841,6 +8314,11 @@ single-line-log@^1.1.2: dependencies: string-width "^1.0.1" +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + slice-ansi@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" @@ -8171,6 +8649,19 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string.prototype.matchall@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz#24243399bc31b0a49d19e2b74171a15653ec996a" + integrity sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + has-symbols "^1.0.1" + internal-slot "^1.0.2" + regexp.prototype.flags "^1.3.0" + side-channel "^1.0.3" + string.prototype.trimend@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz#ee497fd29768646d84be2c9b819e292439614373" @@ -8297,6 +8788,11 @@ strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + structron@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/structron/-/structron-0.2.4.tgz#dd37e702b638b3c9e14c38fc8730e336ee85c047" @@ -8650,6 +9146,18 @@ tslib@^1.10.0, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -8672,6 +9180,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -8931,6 +9446,11 @@ v8-compile-cache@2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== +v8-compile-cache@^2.0.3: + version "2.2.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" + integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -9145,7 +9665,7 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" -word-wrap@~1.2.3: +word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== From 797435892e1adf98851c6f0b154a7c7c3e84263b Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 10:19:05 -0800 Subject: [PATCH 32/45] COMPLETELY LINT EVERYTHING --- .eslintrc.yml | 1 + package.json | 3 +- src/main/GameReader.ts | 44 +++++++---- src/main/IOffsets.d.ts | 2 +- src/main/hook.ts | 21 +++-- src/main/index.ts | 116 ++++++++++++++-------------- src/main/memoryjs.d.ts | 12 ++- src/main/structron.d.ts | 56 ++++++++++++++ src/renderer/Avatar.tsx | 34 ++++++-- src/renderer/Footer.tsx | 6 +- src/renderer/Menu.tsx | 10 ++- src/renderer/MicrophoneSoundBar.tsx | 8 +- src/renderer/Settings.tsx | 14 ++-- src/renderer/TestSpeakersButton.tsx | 15 ++-- src/renderer/Voice.tsx | 39 ++++++---- src/renderer/audio.d.ts | 3 - src/renderer/contexts.tsx | 9 ++- src/renderer/cosmetics.ts | 8 +- src/renderer/vad.ts | 46 +++++------ yarn.lock | 4 +- 20 files changed, 282 insertions(+), 169 deletions(-) create mode 100644 src/main/structron.d.ts diff --git a/.eslintrc.yml b/.eslintrc.yml index cbdfc4dd..bc4bf977 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -28,3 +28,4 @@ rules: semi: - error - always + '@typescript-eslint/ban-ts-comment': off diff --git a/package.json b/package.json index 1d88ce91..cd207d70 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "dependencies": { "ajv": "^6.12.6", "analyser-frequency-average": "^1.0.0", - "audio-activity": "^1.0.0", "axios": "^0.21.0", "cross-spawn": "^7.0.3", "electron-store": "^6.0.1", @@ -35,7 +34,7 @@ "electron-window-state": "^5.0.3", "iohook": "git://github.com/ykhwong/iohook", "jsondiffpatch": "^0.4.1", - "memoryjs": "https://github.com/Rob--/memoryjs", + "memoryjs": "git://github.com/Rob--/memoryjs", "react": "^17.0.1", "react-dom": "^17.0.1", "react-spinners-kit": "^1.9.1", diff --git a/src/main/GameReader.ts b/src/main/GameReader.ts index 05ee5897..d85f6f72 100644 --- a/src/main/GameReader.ts +++ b/src/main/GameReader.ts @@ -1,13 +1,27 @@ import { DataType, findModule, getProcesses, ModuleObject, openProcess, ProcessObject, readBuffer, readMemory as readMemoryRaw } from 'memoryjs'; -import * as Struct from 'structron'; +import { Struct, ValueType } from 'structron'; import patcher from '../patcher'; import { GameState, AmongUsState, Player } from '../common/AmongUsState'; import { IOffsets } from './IOffsets'; +interface PlayerReport { + objectPtr: number; + id: number; + name: number; + color: number; + hat: number; + pet: number; + skin: number; + disconnected: number; + impostor: number; + dead: number; + taskPtr: number; +} + export default class GameReader { - reply: Function; + reply: (event: string, ...args: unknown[]) => void; offsets: IOffsets; - PlayerStruct: any; + PlayerStruct: Struct; menuUpdateTimer = 20; lastPlayerPtr = 0; @@ -148,36 +162,38 @@ export default class GameReader { } } - constructor(reply: Function, offsets: IOffsets) { + constructor(reply: (event: string, ...args: unknown[]) => void, offsets: IOffsets) { this.reply = reply; this.offsets = offsets; this.PlayerStruct = new Struct(); for (const member of offsets.player.struct) { - if (member.type === 'SKIP') { - this.PlayerStruct = this.PlayerStruct.addMember(Struct.TYPES.SKIP(member.skip!), member.name); + if (member.type === 'SKIP' && member.skip) { + this.PlayerStruct = this.PlayerStruct.addMember(Struct.TYPES.SKIP(member.skip), member.name); } else { - this.PlayerStruct = this.PlayerStruct.addMember(Struct.TYPES[member.type], member.name); + this.PlayerStruct = this.PlayerStruct.addMember(Struct.TYPES[member.type] as ValueType, member.name); } } } readMemory(dataType: DataType, address: number, offsets: number[], defaultParam?: T): T { + if (!this.amongUs) return defaultParam as T; if (address === 0) return defaultParam as T; const { address: addr, last } = this.offsetAddress(address, offsets); if (addr === 0) return defaultParam as T; return readMemoryRaw( - this.amongUs!.handle, + this.amongUs.handle, addr + last, dataType ); } offsetAddress(address: number, offsets: number[]): { address: number, last: number } { + if (!this.amongUs) throw 'Among Us not open? Weird error'; address = address & 0xffffffff; for (let i = 0; i < offsets.length - 1; i++) { - address = readMemoryRaw(this.amongUs!.handle, address + offsets[i], 'uint32'); + address = readMemoryRaw(this.amongUs.handle, address + offsets[i], 'uint32'); if (address == 0) break; } @@ -185,16 +201,14 @@ export default class GameReader { return { address, last }; } readString(address: number): string { - if (address === 0) return ''; - const length = readMemoryRaw(this.amongUs!.handle, address + 0x8, 'int'); - // console.log(length); - // console.log("reading string", length, length << 1); - const buffer = readBuffer(this.amongUs!.handle, address + 0xC, length << 1); + if (address === 0 || !this.amongUs) return ''; + const length = readMemoryRaw(this.amongUs.handle, address + 0x8, 'int'); + const buffer = readBuffer(this.amongUs.handle, address + 0xC, length << 1); return buffer.toString('utf8').replace(/\0/g, ''); } parsePlayer(ptr: number, buffer: Buffer): Player { - const { data } = this.PlayerStruct.report(buffer, 0, {}); + const { data } = this.PlayerStruct.report(buffer, 0, {}); const isLocal = this.readMemory('int', data.objectPtr, this.offsets.player.isLocal) !== 0; diff --git a/src/main/IOffsets.d.ts b/src/main/IOffsets.d.ts index d8096d53..9d730e22 100644 --- a/src/main/IOffsets.d.ts +++ b/src/main/IOffsets.d.ts @@ -20,7 +20,7 @@ export interface IOffsets { offsets: number[]; inVent: number[]; struct: { - type: string; + type: 'INT' | 'INT_BE' | 'UINT' | 'UINT_BE' | 'SHORT' | 'SHORT_BE' | 'USHORT' | 'USHORT_BE' | 'FLOAT' | 'CHAR' | 'BYTE' | 'SKIP'; skip?: number; name: string; }[]; diff --git a/src/main/hook.ts b/src/main/hook.ts index 56aa9d0f..7c40ba13 100644 --- a/src/main/hook.ts +++ b/src/main/hook.ts @@ -16,6 +16,17 @@ import { existsSync, readFileSync } from 'fs'; import { IOffsets } from './IOffsets'; const { IOffsets } = createCheckers(TI); +interface IOHookEvent { + type: string + keychar?: number + keycode?: number + rawcode?: number + button?: number + clicks?: number + x?: number + y?: number +} + const store = new Store(); async function loadOffsets(event: Electron.IpcMainEvent): Promise { @@ -66,7 +77,7 @@ async function loadOffsets(event: Electron.IpcMainEvent): Promise { readingGame = true; // Register key events - iohook.on('keydown', (ev: any) => { + iohook.on('keydown', (ev: IOHookEvent) => { const shortcutKey = store.get('pushToTalkShortcut'); if (keyCodeMatches(shortcutKey as K, ev)) { event.reply('pushToTalk', true); } }); - iohook.on('keyup', (ev: any) => { + iohook.on('keyup', (ev: IOHookEvent) => { const shortcutKey = store.get('pushToTalkShortcut'); if (keyCodeMatches(shortcutKey as K, ev)) { event.reply('pushToTalk', false); @@ -115,7 +126,7 @@ ipcMain.on('start', async (event) => { iohook.start(); // Read game memory - gameReader = new GameReader(event.reply, offsets); + gameReader = new GameReader(event.reply as (event: string, ...args: unknown[]) => void, offsets); ipcMain.on('initState', (event: Electron.IpcMainEvent) => { event.returnValue = gameReader.lastState; @@ -148,7 +159,7 @@ const keycodeMap = { }; type K = keyof typeof keycodeMap; -function keyCodeMatches(key: K, ev: any): boolean { +function keyCodeMatches(key: K, ev: IOHookEvent): boolean { if (keycodeMap[key]) return keycodeMap[key] === ev.keycode; else if (key.length === 1) diff --git a/src/main/index.ts b/src/main/index.ts index fdc015d0..ffdcb1d5 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -2,8 +2,8 @@ import { autoUpdater } from 'electron-updater'; import { app, BrowserWindow } from 'electron'; -import * as windowStateKeeper from 'electron-window-state'; -import * as path from 'path'; +import windowStateKeeper from 'electron-window-state'; +import { join as joinPath } from 'path'; import { format as formatUrl } from 'url'; import './hook'; @@ -14,13 +14,67 @@ let mainWindow: BrowserWindow | null; app.commandLine.appendSwitch('disable-pinch'); +function createMainWindow() { + const mainWindowState = windowStateKeeper({}); + + const window = new BrowserWindow({ + width: 250, + height: 350, + x: mainWindowState.x, + y: mainWindowState.y, + + resizable: false, + frame: false, + fullscreenable: false, + maximizable: false, + transparent: true, + webPreferences: { + nodeIntegration: true, + enableRemoteModule: true, + webSecurity: false + } + }); + + mainWindowState.manage(window); + + if (isDevelopment) { + window.webContents.openDevTools(); + } + + if (isDevelopment) { + window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}?version=${autoUpdater.currentVersion.version}`); + } + else { + window.loadURL(formatUrl({ + pathname: joinPath(__dirname, 'index.html'), + protocol: 'file', + query: { + version: autoUpdater.currentVersion.version + }, + slashes: true + })); + } + + window.on('closed', () => { + mainWindow = null; + }); + + window.webContents.on('devtools-opened', () => { + window.focus(); + setImmediate(() => { + window.focus(); + }); + }); + + return window; +} + const gotTheLock = app.requestSingleInstanceLock(); if (!gotTheLock) { app.quit(); } else { - // app.disableHardwareAcceleration(); autoUpdater.checkForUpdatesAndNotify(); - app.on('second-instance', (event, commandLine, workingDirectory) => { + app.on('second-instance', () => { // Someone tried to run a second instance, we should focus our window. if (mainWindow) { if (mainWindow.isMinimized()) mainWindow.restore(); @@ -28,60 +82,6 @@ if (!gotTheLock) { } }); - function createMainWindow() { - const mainWindowState = windowStateKeeper({}); - - const window = new BrowserWindow({ - width: 250, - height: 350, - x: mainWindowState.x, - y: mainWindowState.y, - - resizable: false, - frame: false, - fullscreenable: false, - maximizable: false, - transparent: true, - webPreferences: { - nodeIntegration: true, - enableRemoteModule: true, - webSecurity: false - } - }); - - mainWindowState.manage(window); - - if (isDevelopment) { - window.webContents.openDevTools(); - } - - if (isDevelopment) { - window.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}?version=${autoUpdater.currentVersion.version}`); - } - else { - window.loadURL(formatUrl({ - pathname: path.join(__dirname, 'index.html'), - protocol: 'file', - query: { - version: autoUpdater.currentVersion.version - }, - slashes: true - })); - } - - window.on('closed', () => { - mainWindow = null; - }); - - window.webContents.on('devtools-opened', () => { - window.focus(); - setImmediate(() => { - window.focus(); - }); - }); - - return window; - } // quit application when all windows are closed app.on('window-all-closed', () => { diff --git a/src/main/memoryjs.d.ts b/src/main/memoryjs.d.ts index eddae8ae..42679025 100644 --- a/src/main/memoryjs.d.ts +++ b/src/main/memoryjs.d.ts @@ -1,6 +1,6 @@ declare module 'memoryjs' { - type Callback = (error: any, value: T) => void; + type Callback = (error: unknown, value: T) => void; // Processes @@ -18,6 +18,7 @@ declare module 'memoryjs' { export function openProcess(identifier: string, callback?: Callback): ProcessObject; export function getProcesses(callback?: Callback): ProcessObject[]; + export function getProcesses(processId: number, callback?: Callback): ModuleObject[]; // Modules @@ -30,7 +31,6 @@ declare module 'memoryjs' { } export function findModule(identifier: string, processId: number, callback?: Callback): ModuleObject; - export function getProcesses(processId: number, callback?: Callback): ModuleObject[]; // Memory @@ -42,7 +42,7 @@ declare module 'memoryjs' { export function readBuffer(handle: number, address: number, size: number, callback?: Callback): Buffer; - export function writeMemory(handle: number, address: number, value: any, dataType: DataType): void; + export function writeMemory(handle: number, address: number, value: T, dataType: DataType): void; export function writeBuffer(handle: number, address: number, buffer: Buffer): void; @@ -58,7 +58,7 @@ declare module 'memoryjs' { export const T_FLOAT = 0x6; - export type FunctionArg = { type: number, value: any }; + export type FunctionArg = { type: number, value: unknown }; export interface FunctionResult { returnValue: T; @@ -67,6 +67,4 @@ declare module 'memoryjs' { export function callFunction(handle: number, args: FunctionArg[], returnType: number, address: number): FunctionResult; -} - -declare module 'structron'; \ No newline at end of file +} \ No newline at end of file diff --git a/src/main/structron.d.ts b/src/main/structron.d.ts new file mode 100644 index 00000000..9ecd6f59 --- /dev/null +++ b/src/main/structron.d.ts @@ -0,0 +1,56 @@ +declare module 'structron' { + interface ValueType { + read(buffer: BufferSource, offset: number): T; + SIZE: number; + } + + type Rule = (...params: unknown[]) => (dataObj: unknown, buffer: BufferSource) => boolean; + + export class Struct implements ValueType { + + constructor(name?: string); + + addMember(type: ValueType, name: string): this; + addArray(type: ValueType, name: string, offsetMemberName: string, countMemberName: string, relative?: boolean): this; + addReference(type: ValueType, name: string, memberName: string, relative?: boolean): this; + addRule(rule: Rule): this; + read(buffer: BufferSource, offset: number, report?: Report): T; + report(buffer: BufferSource, offset: number, options: Partial): Report; + validate(buffer: BufferSource, offset?: number): boolean; + getOffsetByName(name: string): number; + + get SIZE(): number; + + static RULES: { + EQUAL: Rule; + } + + static TYPES: { + INT: ValueType; + INT_BE: ValueType; + UINT: ValueType; + UINT_BE: ValueType; + SHORT: ValueType; + SHORT_BE: ValueType; + USHORT: ValueType; + USHORT_BE: ValueType; + FLOAT: ValueType; + CHAR: ValueType; + BYTE: ValueType; + STRING(length: number, encoding: string | 'ascii'): ValueType; + NULL_TERMINATED_STRING(encoding: string | 'ascii'): ValueType; + SKIP(length: number): ValueType; + } + } + export type ReportOptions = { + monitorUsage: boolean; + } + + export default class Report { + + constructor(buffer: BufferSource, options: ReportOptions); + toString(): string; + getUsage(): number; + data: T; + } +} \ No newline at end of file diff --git a/src/renderer/Avatar.tsx b/src/renderer/Avatar.tsx index 7022233b..2d0ab280 100644 --- a/src/renderer/Avatar.tsx +++ b/src/renderer/Avatar.tsx @@ -19,7 +19,7 @@ export interface AvatarProps { deafened?: boolean; } -export default function Avatar({ talking, deafened, borderColor, isAlive, player, size }: AvatarProps) { +const Avatar: React.FC = function ({ talking, deafened, borderColor, isAlive, player, size }: AvatarProps) { const status = isAlive ? 'alive' : 'dead'; let image = players[status][player.colorId]; if (!image) image = players[status][0]; @@ -40,7 +40,7 @@ export default function Avatar({ talking, deafened, borderColor, isAlive, player ); -} +}; function Canvas({ src, hat, skin, isAlive }: CanvasProps) { const canvas = useRef(null); @@ -51,16 +51,26 @@ function Canvas({ src, hat, skin, isAlive }: CanvasProps) { useEffect(() => { (async () => { if (!canvas.current || !image.current || !hatImg.current || !skinImg.current) return; - const ctx = canvas.current.getContext('2d')!; + const ctx = canvas.current.getContext('2d'); + if (!ctx) return; if (!image.current.complete) { - await new Promise(r => image!.current!.onload = r); + await new Promise(r => { + if (image?.current) + image.current.onload = r; + }); } if (!hatImg.current.complete) { - await new Promise(r => hatImg!.current!.onload = r); + await new Promise(r => { + if (hatImg?.current) + hatImg.current.onload = r; + }); } if (!skinImg.current.complete) { - await new Promise(r => skinImg!.current!.onload = r); + await new Promise(r => { + if (skinImg?.current) + skinImg.current.onload = r; + }); } canvas.current.width = image.current.width; @@ -69,8 +79,14 @@ function Canvas({ src, hat, skin, isAlive }: CanvasProps) { ctx.drawImage(image.current, 0, 0); function drawHat() { + if (!ctx || !hatImg.current || !canvas.current) return; const hatY = 17 - hatOffsets[hat]; - ctx.drawImage(hatImg.current!, 0, hatY > 0 ? 0 : -hatY, hatImg.current!.width, hatImg.current!.height, canvas.current!.width / 2 - hatImg.current!.width / 2 + 2, Math.max(hatY, 0), hatImg.current!.width, hatImg.current!.height); + ctx.drawImage(hatImg.current, + 0, hatY > 0 ? 0 : -hatY, + hatImg.current.width, hatImg.current.height, + canvas.current.width / 2 - hatImg.current.width / 2 + 2, Math.max(hatY, 0), + hatImg.current.width, hatImg.current.height + ); } if (isAlive) { @@ -93,4 +109,6 @@ function Canvas({ src, hat, skin, isAlive }: CanvasProps) { ); -} \ No newline at end of file +} + +export default Avatar; diff --git a/src/renderer/Footer.tsx b/src/renderer/Footer.tsx index 7558af0f..174a6cfd 100644 --- a/src/renderer/Footer.tsx +++ b/src/renderer/Footer.tsx @@ -1,7 +1,7 @@ import { shell } from 'electron'; import React from 'react'; -export default function Footer() { +const Footer: React.FC = function() { return (
Made by Ottomated @@ -57,4 +57,6 @@ export default function Footer() {
); -} \ No newline at end of file +}; + +export default Footer; diff --git a/src/renderer/Menu.tsx b/src/renderer/Menu.tsx index 7609d878..78260e50 100644 --- a/src/renderer/Menu.tsx +++ b/src/renderer/Menu.tsx @@ -4,7 +4,11 @@ import { ipcRenderer } from 'electron'; import './css/menu.css'; import Footer from './Footer'; -export default function Menu({ errored }: { errored: boolean }) { +export interface MenuProps { + errored: boolean +} + +const Menu : React.FC = function({ errored }: MenuProps) { return (
@@ -31,4 +35,6 @@ export default function Menu({ errored }: { errored: boolean }) {
); -} \ No newline at end of file +}; + +export default Menu; \ No newline at end of file diff --git a/src/renderer/MicrophoneSoundBar.tsx b/src/renderer/MicrophoneSoundBar.tsx index 3821203d..3cdd6a4d 100644 --- a/src/renderer/MicrophoneSoundBar.tsx +++ b/src/renderer/MicrophoneSoundBar.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useState } from 'react'; -interface ITestMicProps { - microphone: string +interface TestMicProps { + microphone: string } -const TestMicrophoneButton: React.FunctionComponent = function({ microphone }) { +const TestMicrophoneButton: React.FC = function ({ microphone } : TestMicProps) { const [error, setError] = useState(false); const [rms, setRms] = useState(0); @@ -20,7 +20,7 @@ const TestMicrophoneButton: React.FunctionComponent = function({ const handleProcess = (event: AudioProcessingEvent) => { // limit update frequency - if ( event.timeStamp - lastRefreshTime < minUpdateRate ) { + if (event.timeStamp - lastRefreshTime < minUpdateRate) { return; } diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 90fd8aa1..a0c23e7c 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -94,7 +94,7 @@ const store = new Store({ } }); -store.onDidChange('serverURL', (newUrl, oldUrl) => { +store.onDidChange('serverURL', (newUrl) => { if (newUrl === 'http://54.193.94.35:9736') { store.set('serverURL', 'https://crewl.ink'); } @@ -102,14 +102,14 @@ store.onDidChange('serverURL', (newUrl, oldUrl) => { export interface SettingsProps { open: boolean; - onClose: any; + onClose: () => void; } export const settingsReducer = (state: ISettings, action: { - type: 'set' | 'setOne', action: [string, any] | ISettings + type: 'set' | 'setOne', action: [string, unknown] | ISettings }): ISettings => { if (action.type === 'set') return action.action as ISettings; - const v = (action.action as [string, any]); + const v = (action.action as [string, unknown]); store.set(v[0], v[1]); return { ...state, @@ -150,7 +150,7 @@ function URLInput({ initialURL, onValidURL }: URLInputProps) { return ; } -export default function Settings({ open, onClose }: SettingsProps) { +const Settings: React.FC = function ({ open, onClose }: SettingsProps) { const [settings, setSettings] = useContext(SettingsContext); const [unsavedCount, setUnsavedCount] = useState(0); const unsaved = unsavedCount > 2; @@ -314,4 +314,6 @@ export default function Settings({ open, onClose }: SettingsProps) { ; -} +}; + +export default Settings; diff --git a/src/renderer/TestSpeakersButton.tsx b/src/renderer/TestSpeakersButton.tsx index ae0ee769..70eecf7a 100644 --- a/src/renderer/TestSpeakersButton.tsx +++ b/src/renderer/TestSpeakersButton.tsx @@ -1,23 +1,26 @@ import React from 'react'; // @ts-ignore import chime from '../../static/chime.mp3'; +import { ExtendedAudioElement } from './Voice'; -interface ITestSpeakersProps { - speaker: string +interface TestSpeakersProps { + speaker: string } -const TestSpeakersButton: React.FunctionComponent = ({ speaker }) => { +const TestSpeakersButton: React.FC = ({ speaker }: TestSpeakersProps) => { const testSpeakers = () => { - const audio = new Audio(); + const audio = new Audio() as ExtendedAudioElement; audio.src = chime; if (speaker.toLowerCase() !== 'default') - (audio as any).setSinkId(speaker); + audio.setSinkId(speaker); audio.play(); }; - return ; + return ( + + ); }; export default TestSpeakersButton; diff --git a/src/renderer/Voice.tsx b/src/renderer/Voice.tsx index fdf5ea64..c8607177 100644 --- a/src/renderer/Voice.tsx +++ b/src/renderer/Voice.tsx @@ -8,9 +8,14 @@ import { ipcRenderer, remote } from 'electron'; import VAD from './vad'; import { ISettings } from '../common/ISettings'; +export interface ExtendedAudioElement extends HTMLAudioElement { + setSinkId: (sinkId: string) => Promise; +} + interface PeerConnections { [peer: string]: Peer.Instance; } + interface AudioElements { [peer: string]: { element: HTMLAudioElement; @@ -18,9 +23,6 @@ interface AudioElements { pan: PannerNode; }; } -interface AudioListeners { - [peer: string]: any; -} interface SocketIdMap { [socketId: string]: number; @@ -86,7 +88,7 @@ function calculateVoiceAudio(state: AmongUsState, settings: ISettings, me: Playe } -export default function Voice() { +const Voice: React.FC = function () { const [settings] = useContext(SettingsContext); const settingsRef = useRef(settings); const gameState = useContext(GameStateContext); @@ -148,7 +150,10 @@ export default function Voice() { }); // Initialize variables - let audioListener: any; + let audioListener: { + connect: () => void; + destroy: () => void; + }; const audio: MediaTrackConstraints = { autoGainControl: false, channelCount: 2, @@ -173,7 +178,7 @@ export default function Voice() { stream.getAudioTracks()[0].enabled = !connectionStuff.current.deafened; setDeafened(connectionStuff.current.deafened); }); - ipcRenderer.on('pushToTalk', (_: any, pressing: boolean) => { + ipcRenderer.on('pushToTalk', (_: unknown, pressing: boolean) => { if (!connectionStuff.current.pushToTalk) return; if (!connectionStuff.current.deafened) { stream.getAudioTracks()[0].enabled = pressing; @@ -190,7 +195,6 @@ export default function Voice() { const peerConnections: PeerConnections = {}; audioElements.current = {}; - const audioListeners: AudioListeners = {}; const connect = (lobbyCode: string, playerId: number) => { console.log('Connect called', lobbyCode, playerId); @@ -215,9 +219,6 @@ export default function Voice() { audioElements.current[peer].gain.disconnect(); delete audioElements.current[peer]; } - if (audioListeners[peer]) { - audioListeners[peer].destroy(); - } } socket.emit('join', lobbyCode, playerId); @@ -236,11 +237,11 @@ export default function Voice() { peerConnections[peer] = connection; connection.on('stream', (stream: MediaStream) => { - const audio = document.createElement('audio'); + const audio = document.createElement('audio') as ExtendedAudioElement; document.body.appendChild(audio); audio.srcObject = stream; if (settings.speaker.toLowerCase() !== 'default') - (audio as any).setSinkId(settings.speaker); + audio.setSinkId(settings.speaker); const context = new AudioContext(); const source = context.createMediaStreamSource(stream); @@ -283,7 +284,7 @@ export default function Voice() { createPeerConnection(peer, true); setSocketPlayerIds(old => ({ ...old, [peer]: playerId })); }); - socket.on('signal', ({ data, from }: any) => { + socket.on('signal', ({ data, from }: { data: Peer.SignalData, from: string }) => { let connection: Peer.Instance; if (peerConnections[from]) { connection = peerConnections[from]; @@ -321,17 +322,19 @@ export default function Voice() { const otherPlayers = useMemo(() => { let otherPlayers: Player[]; - if (!gameState || !gameState.players || gameState.lobbyCode === 'MENU' || !myPlayer) otherPlayers = []; + if (!gameState || !gameState.players || gameState.lobbyCode === 'MENU' || !myPlayer) return []; else otherPlayers = gameState.players.filter(p => !p.isLocal); - const playerSocketIds = {} as any; + const playerSocketIds: { + [index: number]: string + } = {}; for (const k of Object.keys(socketPlayerIds)) { playerSocketIds[socketPlayerIds[k]] = k; } for (const player of otherPlayers) { const audio = audioElements.current[playerSocketIds[player.id]]; if (audio) { - calculateVoiceAudio(gameState, settingsRef.current, myPlayer!, player, audio.gain, audio.pan); + calculateVoiceAudio(gameState, settingsRef.current, myPlayer, player, audio.gain, audio.pan); if (connectionStuff.current.deafened) { audio.gain.gain.value = 0; } @@ -401,4 +404,6 @@ export default function Voice() { ); -} +}; + +export default Voice; diff --git a/src/renderer/audio.d.ts b/src/renderer/audio.d.ts index 5e5e67c5..d5498513 100644 --- a/src/renderer/audio.d.ts +++ b/src/renderer/audio.d.ts @@ -1,4 +1 @@ -declare module 'audio-activity' { - export default function audioActivity(stream: MediaStream, callback: (level: number) => void): any; -} declare module 'analyser-frequency-average'; \ No newline at end of file diff --git a/src/renderer/contexts.tsx b/src/renderer/contexts.tsx index 56ae380e..b7b16649 100644 --- a/src/renderer/contexts.tsx +++ b/src/renderer/contexts.tsx @@ -2,9 +2,10 @@ import React, { createContext } from 'react'; import { AmongUsState } from '../common/AmongUsState'; import { ISettings } from '../common/ISettings'; +type SettingsContextValue = [ISettings, React.Dispatch<{ + type: 'set' | 'setOne'; + action: ISettings | [string, unknown]; +}>] export const GameStateContext = createContext({} as AmongUsState); -export const SettingsContext = createContext<[ISettings, React.Dispatch<{ - type: 'set' | 'setOne'; - action: ISettings | [string, any]; -}>]>(null as any); +export const SettingsContext = createContext(null as unknown as SettingsContextValue); diff --git a/src/renderer/cosmetics.ts b/src/renderer/cosmetics.ts index 3ee4ed85..6a55a259 100644 --- a/src/renderer/cosmetics.ts +++ b/src/renderer/cosmetics.ts @@ -138,12 +138,12 @@ import brownDead from '../../static/players/brown-dead.png';// @ts-ignore import cyanDead from '../../static/players/cyan-dead.png';// @ts-ignore import limeDead from '../../static/players/lime-dead.png'; -export interface playersInterface { - alive: any[] - dead: any[] +export interface PlayerImageColors { + alive: string[]; + dead: string[]; } -export const players: playersInterface = { +export const players: PlayerImageColors = { alive: [redAlive, blueAlive, greenAlive, pinkAlive, orangeAlive, yellowAlive, blackAlive, whiteAlive, purpleAlive, brownAlive, cyanAlive, limeAlive], dead: [redDead, blueDead, greenDead, pinkDead, orangeDead, yellowDead, blackDead, whiteDead, purpleDead, brownDead, cyanDead, limeDead], }; diff --git a/src/renderer/vad.ts b/src/renderer/vad.ts index 233cad42..30b41dec 100644 --- a/src/renderer/vad.ts +++ b/src/renderer/vad.ts @@ -1,25 +1,28 @@ import analyserFrequency from 'analyser-frequency-average'; interface VADOptions { - fftSize?: number; - bufferLen?: number; - smoothingTimeConstant?: number; - minCaptureFreq?: number; - maxCaptureFreq?: number; - noiseCaptureDuration?: number; - minNoiseLevel?: number; - maxNoiseLevel?: number; - avgNoiseMultiplier?: number; - onVoiceStart?: () => void; - onVoiceStop?: () => void; - onUpdate?: (val: number) => void; + fftSize: number; + bufferLen: number; + smoothingTimeConstant: number; + minCaptureFreq: number; + maxCaptureFreq: number; + noiseCaptureDuration: number; + minNoiseLevel: number; + maxNoiseLevel: number; + avgNoiseMultiplier: number; + onVoiceStart: () => void; + onVoiceStop: () => void; + onUpdate: (val: number) => void; } -export default function (audioContext: AudioContext, source: AudioNode, destination: AudioNode | undefined, opts: VADOptions) { +export default function (audioContext: AudioContext, source: AudioNode, destination: AudioNode | undefined, opts: Partial): { + connect: () => void, + destroy: () => void +} { opts = opts || {}; - const defaults = { + const defaults : VADOptions = { fftSize: 1024, bufferLen: 1024, smoothingTimeConstant: 0.2, @@ -29,15 +32,12 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat minNoiseLevel: 0.3, // from 0 to 1 maxNoiseLevel: 0.7, // from 0 to 1 avgNoiseMultiplier: 1.2, - onVoiceStart: () => { }, - onVoiceStop: () => { }, - onUpdate: (_: number) => { } + onVoiceStart: function () { /* DO NOTHING */ }, + onVoiceStop: function () { /* DO NOTHING */ }, + onUpdate: function () { /* DO NOTHING */ } }; - const options: any = {}; - for (const key in defaults) { - options[key] = opts.hasOwnProperty(key) ? (opts as any)[key] : (defaults as any)[key]; - } + const options: VADOptions = Object.assign({}, defaults, opts); let baseLevel = 0; let voiceScale = 1; @@ -50,7 +50,7 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat let isNoiseCapturing = true; let prevVadState: boolean | undefined = undefined; let vadState = false; - let captureTimeout: any = null; + let captureTimeout: number | null = null; // var source = audioContext.createMediaStreamSource(stream); const analyser = audioContext.createAnalyser(); @@ -63,7 +63,7 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat if (isNoiseCapturing) { //console.log('VAD: start noise capturing'); - captureTimeout = setTimeout(init, options.noiseCaptureDuration); + captureTimeout = setTimeout(init, options.noiseCaptureDuration) as unknown as number; } function init() { diff --git a/yarn.lock b/yarn.lock index dbf3b829..3193fa5a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6111,9 +6111,9 @@ memory-fs@^0.5.0: errno "^0.1.3" readable-stream "^2.0.1" -"memoryjs@https://github.com/Rob--/memoryjs": +"memoryjs@git://github.com/Rob--/memoryjs": version "3.3.1" - resolved "https://github.com/Rob--/memoryjs#79618efdefc2aac203ae7137eefa2cf30cf888ce" + resolved "git://github.com/Rob--/memoryjs#79618efdefc2aac203ae7137eefa2cf30cf888ce" dependencies: bindings "^1.5.0" concentrate "^0.2.3" From e0d9006a08e08a21eed14be5fba928558be00563 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 11:26:26 -0800 Subject: [PATCH 33/45] Fix structron defs --- src/main/GameReader.ts | 8 +++++++- src/main/structron.d.ts | 25 ++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/GameReader.ts b/src/main/GameReader.ts index d85f6f72..c9e30145 100644 --- a/src/main/GameReader.ts +++ b/src/main/GameReader.ts @@ -1,9 +1,15 @@ import { DataType, findModule, getProcesses, ModuleObject, openProcess, ProcessObject, readBuffer, readMemory as readMemoryRaw } from 'memoryjs'; -import { Struct, ValueType } from 'structron'; +import Struct from 'structron'; import patcher from '../patcher'; import { GameState, AmongUsState, Player } from '../common/AmongUsState'; import { IOffsets } from './IOffsets'; + +interface ValueType { + read(buffer: BufferSource, offset: number): T; + SIZE: number; +} + interface PlayerReport { objectPtr: number; id: number; diff --git a/src/main/structron.d.ts b/src/main/structron.d.ts index 9ecd6f59..3e730932 100644 --- a/src/main/structron.d.ts +++ b/src/main/structron.d.ts @@ -1,12 +1,21 @@ declare module 'structron' { + type ReportOptions = { + monitorUsage: boolean; + } + + class Report { + constructor(buffer: BufferSource, options: ReportOptions); + toString(): string; + getUsage(): number; + data: T; + } interface ValueType { read(buffer: BufferSource, offset: number): T; SIZE: number; } type Rule = (...params: unknown[]) => (dataObj: unknown, buffer: BufferSource) => boolean; - - export class Struct implements ValueType { + class Struct implements ValueType { constructor(name?: string); @@ -42,15 +51,5 @@ declare module 'structron' { SKIP(length: number): ValueType; } } - export type ReportOptions = { - monitorUsage: boolean; - } - - export default class Report { - - constructor(buffer: BufferSource, options: ReportOptions); - toString(): string; - getUsage(): number; - data: T; - } + export = Struct; } \ No newline at end of file From 1e62e99239ba602ff8e4fcefd01bb4d8b95635a7 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 14:41:28 -0800 Subject: [PATCH 34/45] Add settings indicator and fix css --- src/common/ISettings.d.ts | 2 +- src/renderer/App.tsx | 2 +- src/renderer/Settings.tsx | 21 ++++++++++++++++----- src/renderer/Voice.tsx | 4 +++- src/renderer/css/index.css | 7 +++---- src/renderer/css/menu.css | 3 ++- src/renderer/css/settings.css | 20 ++++++++++++++++++-- src/renderer/vad.ts | 9 ++++++--- 8 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/common/ISettings.d.ts b/src/common/ISettings.d.ts index 3b4e7f34..e54031a3 100644 --- a/src/common/ISettings.d.ts +++ b/src/common/ISettings.d.ts @@ -12,5 +12,5 @@ export interface ISettings { data: string; }, hideCode: boolean; - stereoInLobby: boolean; + enableSpatialAudio: boolean; } diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index c303a804..c242cdd0 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -34,7 +34,7 @@ function App() { data: '' }, hideCode: false, - stereoInLobby: true + enableSpatialAudio: true }); useEffect(() => { diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index a0c23e7c..17d3f1c7 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -38,6 +38,12 @@ const store = new Store({ if (serverURL === 'http://54.193.94.35:9736') { store.set('serverURL', 'https://crewl.ink'); } + }, + '1.1.6': store => { + const enableSpatialAudio = store.get('stereoInLobby'); + store.set('enableSpatialAudio', enableSpatialAudio); + // @ts-ignore + store.delete('stereoInLobby'); } }, schema: { @@ -87,7 +93,7 @@ const store = new Store({ type: 'boolean', default: false }, - stereoInLobby: { + enableSpatialAudio: { type: 'boolean', default: true } @@ -163,7 +169,7 @@ const Settings: React.FC = function ({ open, onClose }: SettingsP useEffect(() => { setUnsavedCount(s => s + 1); - }, [settings.microphone, settings.speaker, settings.serverURL]); + }, [settings.microphone, settings.speaker, settings.serverURL, settings.enableSpatialAudio]); const [devices, setDevices] = useState([]); const [_, updateDevices] = useReducer((state) => state + 1, 0); @@ -307,10 +313,15 @@ const Settings: React.FC = function ({ open, onClose }: SettingsP
setSettings({ type: 'setOne', - action: ['stereoInLobby', !settings.stereoInLobby] + action: ['enableSpatialAudio', !settings.enableSpatialAudio] })}> - - + + +
+
+ + Exit to apply changes +
; diff --git a/src/renderer/Voice.tsx b/src/renderer/Voice.tsx index c8607177..f537602b 100644 --- a/src/renderer/Voice.tsx +++ b/src/renderer/Voice.tsx @@ -50,7 +50,7 @@ function calculateVoiceAudio(state: AmongUsState, settings: ISettings, me: Playe (other.x - me.x), (other.y - me.y) ]; - if (state.gameState === GameState.DISCUSSION || (state.gameState === GameState.LOBBY && !settings.stereoInLobby)) { + if (state.gameState === GameState.DISCUSSION || (state.gameState === GameState.LOBBY && !settings.enableSpatialAudio)) { panPos = [0, 0]; } if (isNaN(panPos[0])) panPos[0] = 999; @@ -191,6 +191,7 @@ const Voice: React.FC = function () { onVoiceStart: () => setTalking(true), onVoiceStop: () => setTalking(false), noiseCaptureDuration: 1, + stereo: false }); const peerConnections: PeerConnections = {}; @@ -259,6 +260,7 @@ const Voice: React.FC = function () { VAD(context, gain, context.destination, { onVoiceStart: () => setTalking(true), onVoiceStop: () => setTalking(false), + stereo: settingsRef.current.enableSpatialAudio }); const setTalking = (talking: boolean) => { diff --git a/src/renderer/css/index.css b/src/renderer/css/index.css index f09f29cb..3bfa11ae 100644 --- a/src/renderer/css/index.css +++ b/src/renderer/css/index.css @@ -1,6 +1,5 @@ @import url('https://fonts.googleapis.com/css2?family=Varela&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@500&display=swap'); - body { background-color: #23272A; color: white; @@ -13,6 +12,7 @@ body { width: 100vw; height: 100vh; } + .root { padding-top: 24px; } @@ -77,6 +77,7 @@ body { .close { right: 2px; } + .settings { left: 2px; } @@ -143,11 +144,9 @@ hr { 0% { background-position: 0% 50%; } - 50% { background-position: 100% 50%; } - 100% { background-position: 0% 50%; } @@ -155,7 +154,7 @@ hr { ::-webkit-scrollbar { width: 8px; - margin-left:2px; + margin-left: 2px; } ::-webkit-scrollbar-track { diff --git a/src/renderer/css/menu.css b/src/renderer/css/menu.css index b0d63294..4f46620d 100644 --- a/src/renderer/css/menu.css +++ b/src/renderer/css/menu.css @@ -30,7 +30,7 @@ } .errormessage { - margin: 5px; + margin: 5px; } .title { @@ -51,6 +51,7 @@ justify-content: center; align-items: center; } + .footer .row { width: 100%; display: flex; diff --git a/src/renderer/css/settings.css b/src/renderer/css/settings.css index 6eb04eca..e98d607c 100644 --- a/src/renderer/css/settings.css +++ b/src/renderer/css/settings.css @@ -6,7 +6,7 @@ backdrop-filter: blur(4px); position: absolute; top: 0; - left:0; + left: 0; z-index: 10; display: flex; flex-direction: column; @@ -67,11 +67,13 @@ select { .settings-scroll { overflow-y: auto; - height: calc(100vh - 20px); + height: calc(100vh - 50px); display: flex; flex-direction: column; justify-content: start; align-items: center; + margin-bottom: 30px; + width: 100%; } .microphone-bar { @@ -80,6 +82,8 @@ select { background: #1d1d1d; border: 1px solid rgba(255, 255, 255, 0.5); border-radius: 5px; + margin: 5px auto; + overflow: hidden; } .microphone-bar-inner { @@ -91,4 +95,16 @@ select { .test-speakers { width: fit-content; margin: 5px auto; +} + +.settings-alert { + background: #f1c40f; + color: black; + position: absolute; + bottom: 20px; + left: 0; + height: 30px; + justify-content: center; + align-items: center; + width: 100vw; } \ No newline at end of file diff --git a/src/renderer/vad.ts b/src/renderer/vad.ts index 30b41dec..cce220e2 100644 --- a/src/renderer/vad.ts +++ b/src/renderer/vad.ts @@ -13,6 +13,7 @@ interface VADOptions { onVoiceStart: () => void; onVoiceStop: () => void; onUpdate: (val: number) => void; + stereo: boolean; } export default function (audioContext: AudioContext, source: AudioNode, destination: AudioNode | undefined, opts: Partial): { @@ -22,7 +23,7 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat opts = opts || {}; - const defaults : VADOptions = { + const defaults: VADOptions = { fftSize: 1024, bufferLen: 1024, smoothingTimeConstant: 0.2, @@ -34,7 +35,8 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat avgNoiseMultiplier: 1.2, onVoiceStart: function () { /* DO NOTHING */ }, onVoiceStop: function () { /* DO NOTHING */ }, - onUpdate: function () { /* DO NOTHING */ } + onUpdate: function () { /* DO NOTHING */ }, + stereo: true }; const options: VADOptions = Object.assign({}, defaults, opts); @@ -57,7 +59,8 @@ export default function (audioContext: AudioContext, source: AudioNode, destinat analyser.smoothingTimeConstant = options.smoothingTimeConstant; analyser.fftSize = options.fftSize; - const scriptProcessorNode = audioContext.createScriptProcessor(options.bufferLen, 2, 2); + const channels = options.stereo ? 2 : 1; + const scriptProcessorNode = audioContext.createScriptProcessor(options.bufferLen, channels, channels); connect(); scriptProcessorNode.onaudioprocess = monitor; From 54ee065758c93f7842e53d5c5ca9bbf9d76c6359 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 15:50:28 -0800 Subject: [PATCH 35/45] Add twitter --- src/renderer/Footer.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/renderer/Footer.tsx b/src/renderer/Footer.tsx index 174a6cfd..b7bdc7c6 100644 --- a/src/renderer/Footer.tsx +++ b/src/renderer/Footer.tsx @@ -1,7 +1,7 @@ import { shell } from 'electron'; import React from 'react'; -const Footer: React.FC = function() { +const Footer: React.FC = function () { return (
Made by Ottomated @@ -16,6 +16,11 @@ const Footer: React.FC = function() { }}> + { + shell.openExternal('https://twitter.com/Ottomated_'); + }}> + + { shell.openExternal('https://paypal.me/ottomated'); }}> From 054fbc6f7457c2d3db58a593816a54c0a9de1d34 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 15:50:58 -0800 Subject: [PATCH 36/45] remove comment --- src/renderer/Settings.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/renderer/Settings.tsx b/src/renderer/Settings.tsx index 17d3f1c7..e0649fd9 100644 --- a/src/renderer/Settings.tsx +++ b/src/renderer/Settings.tsx @@ -228,15 +228,6 @@ const Settings: React.FC = function ({ open, onClose }: SettingsP - {/*
{ - ipcRenderer.send('alwaysOnTop', !settings.alwaysOnTop); - setSettings({ - type: 'setOne', - action: ['alwaysOnTop', !settings.alwaysOnTop] - }); - }}> - Always on Top -
*/}
From 9e1c990119d4561e1e7cf04143a351029ad6acfc Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 10 Dec 2020 15:51:08 -0800 Subject: [PATCH 37/45] update error message --- src/renderer/Menu.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/renderer/Menu.tsx b/src/renderer/Menu.tsx index 78260e50..f96791e1 100644 --- a/src/renderer/Menu.tsx +++ b/src/renderer/Menu.tsx @@ -8,7 +8,7 @@ export interface MenuProps { errored: boolean } -const Menu : React.FC = function({ errored }: MenuProps) { +const Menu: React.FC = function ({ errored }: MenuProps) { return (
@@ -16,7 +16,11 @@ const Menu : React.FC = function({ errored }: MenuProps) { <> Error - Make sure that the Voice Server is correct in the settings and you are using the latest version of Among Us. If there was a recent update, CrewLink might not work for a few days. +
    +
  1. Use a different Voice Server in settings
  2. +
  3. Update Among Us
  4. +
  5. Wait for 24 hours after Among Us updates
  6. +